LCOV - code coverage report
Current view: top level - tests - api_compact.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 430 433 99.3 %
Date: 2019-06-30 05:20:33 Functions: 21 21 100.0 %
Branches: 697 2554 27.3 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_compact.cc
       2                 :            :  * @brief Tests of Database::compact()
       3                 :            :  */
       4                 :            : /* Copyright (C) 2009,2010,2011,2012,2013,2015,2016,2017,2018,2019 Olly Betts
       5                 :            :  * Copyright (C) 2010 Richard Boulton
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include "api_compact.h"
      26                 :            : 
      27                 :            : #include <xapian.h>
      28                 :            : 
      29                 :            : #include "apitest.h"
      30                 :            : #include "dbcheck.h"
      31                 :            : #include "filetests.h"
      32                 :            : #include "msvcignoreinvalidparam.h"
      33                 :            : #include "str.h"
      34                 :            : #include "testsuite.h"
      35                 :            : #include "testutils.h"
      36                 :            : 
      37                 :            : #include <cerrno>
      38                 :            : #include <cstdlib>
      39                 :            : #include <fstream>
      40                 :            : 
      41                 :            : #include <sys/types.h>
      42                 :            : #include "safesysstat.h"
      43                 :            : #include "safefcntl.h"
      44                 :            : #include "safeunistd.h"
      45                 :            : 
      46                 :            : #include "unixcmds.h"
      47                 :            : 
      48                 :            : using namespace std;
      49                 :            : 
      50                 :            : static void
      51                 :         12 : make_sparse_db(Xapian::WritableDatabase &db, const string & s)
      52                 :            : {
      53                 :            :     // Need non-const pointer for strtoul(), but data isn't modified.
      54                 :         12 :     char * p = const_cast<char *>(s.c_str());
      55                 :            : 
      56         [ +  - ]:         36 :     while (*p) {
      57                 :         36 :         bool del = (*p == '!');
      58         [ +  + ]:         36 :         if (del) ++p;
      59                 :         36 :         Xapian::docid first = strtoul(p, &p, 10);
      60                 :         36 :         Xapian::docid last = first;
      61         [ +  + ]:         36 :         if (*p == '-') {
      62                 :         12 :             last = strtoul(p + 1, &p, 10);
      63                 :            :         }
      64 [ +  + ][ -  + ]:         36 :         if (*p && *p != ' ') {
      65 [ #  # ][ #  # ]:          0 :             tout << p - s.c_str() << endl;
      66 [ #  # ][ #  # ]:          0 :             FAIL_TEST("Bad sparse db spec (expected space): " << s);
         [ #  # ][ #  # ]
                 [ #  # ]
      67                 :            :         }
      68         [ -  + ]:         36 :         if (first > last) {
      69 [ #  # ][ #  # ]:          0 :             FAIL_TEST("Bad sparse db spec (first > last): " << s);
         [ #  # ][ #  # ]
                 [ #  # ]
      70                 :            :         }
      71                 :            : 
      72         [ +  + ]:         99 :         do {
      73         [ +  + ]:         99 :             if (del) {
      74         [ +  - ]:          6 :                 db.delete_document(first);
      75                 :            :             } else {
      76         [ +  - ]:         93 :                 Xapian::Document doc;
      77         [ +  - ]:        186 :                 string id = str(first);
      78         [ +  - ]:         93 :                 doc.set_data(id);
      79 [ +  - ][ +  - ]:         93 :                 doc.add_term("Q" + str(first));
                 [ +  - ]
      80 [ +  - ][ +  - ]:         93 :                 doc.add_term(string(first % 7 + 1, char((first % 26) + 'a')));
      81         [ +  - ]:        186 :                 db.replace_document(first, doc);
      82                 :            :             }
      83                 :         99 :         } while (first++ < last);
      84                 :            : 
      85         [ +  + ]:         36 :         if (*p == '\0') break;
      86                 :         24 :         ++p;
      87                 :            :     }
      88                 :            : 
      89         [ +  - ]:         12 :     db.commit();
      90                 :         12 : }
      91                 :            : 
      92                 :            : static void
      93                 :          5 : check_sparse_uid_terms(const string & path)
      94                 :            : {
      95         [ +  - ]:          5 :     Xapian::Database db(path);
      96                 :         10 :     Xapian::TermIterator t;
      97 [ +  - ][ +  - ]:         90 :     for (t = db.allterms_begin("Q"); t != db.allterms_end("Q"); ++t) {
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
      98         [ +  - ]:         86 :         Xapian::docid did = atoi((*t).c_str() + 1);
      99 [ +  - ][ +  - ]:         86 :         Xapian::PostingIterator p = db.postlist_begin(*t);
     100 [ +  - ][ +  + ]:         86 :         TEST_EQUAL(*p, did);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     101                 :         91 :     }
     102                 :          4 : }
     103                 :            : 
     104                 :            : // With multi the docids in the shards change the behaviour.
     105                 :          2 : DEFINE_TESTCASE(compactnorenumber1, compact && generated && !multi) {
     106 [ +  - ][ +  - ]:          2 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     107                 :            : 
     108                 :            :     string a = get_database_path("compactnorenumber1a", make_sparse_db,
     109 [ +  - ][ +  - ]:          2 :                                  "5-7 24 76 987 1023-1027 9999 !9999");
                 [ +  - ]
     110         [ +  - ]:          4 :     string a_uuid;
     111                 :            :     {
     112         [ +  - ]:          2 :         Xapian::Database db(a);
     113 [ +  - ][ +  - ]:          2 :         a_uuid = db.get_uuid();
     114                 :            :     }
     115                 :            :     string b = get_database_path("compactnorenumber1b", make_sparse_db,
     116 [ +  - ][ +  - ]:          4 :                                  "1027-1030");
                 [ +  - ]
     117                 :            :     string c = get_database_path("compactnorenumber1c", make_sparse_db,
     118 [ +  - ][ +  - ]:          4 :                                  "1028-1040");
                 [ +  - ]
     119                 :            :     string d = get_database_path("compactnorenumber1d", make_sparse_db,
     120 [ +  - ][ +  - ]:          4 :                                  "3000 999999 !999999");
                 [ +  - ]
     121                 :            : 
     122 [ +  - ][ +  - ]:          4 :     string out = get_compaction_output_path("compactnorenumber1out");
     123                 :            : 
     124         [ +  - ]:          2 :     rm_rf(out);
     125                 :            :     {
     126         [ +  - ]:          2 :         Xapian::Database db(a);
     127         [ +  - ]:          2 :         db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER);
     128                 :            :     }
     129                 :            : 
     130         [ +  + ]:          2 :     check_sparse_uid_terms(out);
     131                 :            : 
     132                 :            :     {
     133 [ +  - ][ -  + ]:          1 :         TEST(!dir_exists(out + "/donor"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     134         [ +  - ]:          1 :         Xapian::Database db(out);
     135                 :            :         // xapian-compact should change the UUID of the database, but didn't
     136                 :            :         // prior to 1.0.18/1.1.4.
     137         [ +  - ]:          2 :         string out_uuid = db.get_uuid();
     138 [ +  - ][ -  + ]:          1 :         TEST_NOT_EQUAL(a_uuid, out_uuid);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     139 [ -  + ][ #  # ]:          1 :         TEST_EQUAL(out_uuid.size(), 36);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     140 [ +  - ][ -  + ]:          1 :         TEST_NOT_EQUAL(out_uuid, "00000000-0000-0000-0000-000000000000");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     141                 :            : 
     142                 :            :         // White box test - ensure that the donor database is removed.
     143 [ +  - ][ -  + ]:          2 :         TEST(!dir_exists(out + "/donor"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     144                 :            :     }
     145                 :            : 
     146         [ +  - ]:          1 :     rm_rf(out);
     147                 :            :     {
     148         [ +  - ]:          1 :         Xapian::Database db;
     149 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     150 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(c));
     151         [ +  - ]:          1 :         db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER);
     152                 :            :     }
     153         [ +  - ]:          1 :     check_sparse_uid_terms(out);
     154                 :            :     {
     155                 :            :         // Check that xapian-compact is producing a consistent database.  Also,
     156                 :            :         // regression test - xapian 1.1.4 set lastdocid to 0 in the output
     157                 :            :         // database.
     158         [ +  - ]:          1 :         Xapian::Database outdb(out);
     159         [ +  - ]:          1 :         dbcheck(outdb, 24, 9999);
     160                 :            :     }
     161                 :            : 
     162         [ +  - ]:          1 :     rm_rf(out);
     163                 :            :     {
     164         [ +  - ]:          1 :         Xapian::Database db;
     165 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(d));
     166 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     167 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(c));
     168         [ +  - ]:          1 :         db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER);
     169                 :            :     }
     170         [ +  - ]:          1 :     check_sparse_uid_terms(out);
     171                 :            : 
     172         [ +  - ]:          1 :     rm_rf(out);
     173                 :            :     {
     174         [ +  - ]:          1 :         Xapian::Database db;
     175 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(c));
     176 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     177 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(d));
     178         [ +  - ]:          1 :         db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER);
     179                 :            :     }
     180         [ +  - ]:          1 :     check_sparse_uid_terms(out);
     181                 :            : 
     182                 :            :     // Should fail.
     183         [ +  - ]:          1 :     rm_rf(out);
     184                 :            :     {
     185         [ +  - ]:          1 :         Xapian::Database db;
     186 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     187 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(b));
     188 [ +  - ][ -  + ]:          1 :         TEST_EXCEPTION(Xapian::InvalidOperationError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     189                 :            :             db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER)
     190                 :          1 :         );
     191                 :            :     }
     192                 :            : 
     193                 :            :     // Should fail.
     194         [ +  - ]:          1 :     rm_rf(out);
     195                 :            :     {
     196         [ +  - ]:          1 :         Xapian::Database db;
     197 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(b));
     198 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     199 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::InvalidOperationError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     200                 :            :             db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER)
     201                 :          1 :         );
     202                 :            :     }
     203                 :            : 
     204                 :            :     // Should fail.
     205         [ +  - ]:          1 :     rm_rf(out);
     206                 :            :     {
     207         [ +  - ]:          1 :         Xapian::Database db;
     208 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     209 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(b));
     210 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(d));
     211 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::InvalidOperationError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     212                 :            :             db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER)
     213                 :          1 :         );
     214                 :            :     }
     215                 :            : 
     216                 :            :     // Should fail.
     217         [ +  - ]:          1 :     rm_rf(out);
     218                 :            :     {
     219         [ +  - ]:          1 :         Xapian::Database db;
     220 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(d));
     221 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(b));
     222 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     223 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::InvalidOperationError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     224                 :            :             db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER)
     225                 :          1 :         );
     226                 :            :     }
     227                 :            : 
     228                 :            :     // Should fail.
     229         [ +  - ]:          1 :     rm_rf(out);
     230                 :            :     {
     231         [ +  - ]:          1 :         Xapian::Database db;
     232 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(b));
     233 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(a));
     234 [ +  - ][ +  - ]:          1 :         db.add_database(Xapian::Database(d));
     235 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::InvalidOperationError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     236                 :            :             db.compact(out, Xapian::DBCOMPACT_NO_RENUMBER)
     237                 :          1 :         );
     238                 :            :     }
     239                 :            : 
     240                 :          2 :     return true;
     241                 :            : }
     242                 :            : 
     243                 :            : // Test use of compact to merge two databases.
     244                 :          4 : DEFINE_TESTCASE(compactmerge1, compact) {
     245 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     246                 :            : 
     247 [ +  - ][ +  - ]:          4 :     string indbpath = get_database_path("apitest_simpledata");
     248 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compactmerge1out");
     249         [ +  - ]:          4 :     rm_rf(outdbpath);
     250                 :            : 
     251         [ +  - ]:          8 :     const string& dbtype = get_dbtype();
     252                 :          4 :     bool singlefile = startswith(dbtype, "singlefile_");
     253                 :            :     {
     254         [ +  - ]:          4 :         Xapian::Database db;
     255 [ +  - ][ +  - ]:          4 :         db.add_database(Xapian::Database(indbpath));
     256 [ +  - ][ +  - ]:          4 :         db.add_database(Xapian::Database(indbpath));
     257         [ +  + ]:          4 :         if (singlefile) {
     258         [ +  - ]:          1 :             db.compact(outdbpath, Xapian::DBCOMPACT_SINGLE_FILE);
     259                 :            :         } else {
     260         [ +  - ]:          3 :             db.compact(outdbpath);
     261                 :          4 :         }
     262                 :            :     }
     263                 :            : 
     264 [ +  - ][ +  - ]:          8 :     Xapian::Database indb(get_database("apitest_simpledata"));
     265         [ +  - ]:          8 :     Xapian::Database outdb(outdbpath);
     266                 :            : 
     267 [ +  - ][ +  - ]:          4 :     TEST_EQUAL(indb.get_doccount() * 2, outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     268 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     269                 :            : 
     270         [ +  + ]:          3 :     if (singlefile) {
     271                 :            :         // Check we actually got a single file out.
     272 [ -  + ][ #  # ]:          1 :         TEST(file_exists(outdbpath));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     273 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(Xapian::Database::check(outdbpath, 0, &tout), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     274         [ +  + ]:          2 :     } else if (startswith(dbtype, "multi_")) {
     275                 :            :         // Can't check a sharded DB.
     276                 :            :     } else {
     277                 :            :         // Check we got a directory out, not a file.
     278 [ -  + ][ #  # ]:          1 :         TEST(dir_exists(outdbpath));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     279                 :            :         static const char* const suffixes[] = {
     280                 :            :             "", "/postlist", "/termlist.", nullptr
     281                 :            :         };
     282         [ +  + ]:          5 :         for (auto s : suffixes) {
     283         [ +  - ]:          4 :             string suffix;
     284         [ +  + ]:          4 :             if (s) {
     285         [ +  - ]:          3 :                 suffix = s;
     286                 :            :             } else {
     287 [ +  - ][ +  - ]:          1 :                 suffix = "/docdata." + dbtype;
     288                 :            :             }
     289 [ +  - ][ +  - ]:          4 :             tout.str(string());
     290 [ +  - ][ +  - ]:          4 :             tout << "Trying suffix '" << suffix << "'" << endl;
         [ +  - ][ +  - ]
     291         [ +  - ]:          8 :             string arg = outdbpath;
     292         [ +  - ]:          4 :             arg += suffix;
     293 [ +  - ][ -  + ]:          4 :             TEST_EQUAL(Xapian::Database::check(arg, 0, &tout), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     294                 :          4 :         }
     295                 :            :     }
     296                 :            : 
     297                 :          4 :     return true;
     298                 :            : }
     299                 :            : 
     300                 :            : static void
     301                 :          3 : make_multichunk_db(Xapian::WritableDatabase &db, const string &)
     302                 :            : {
     303                 :          3 :     int count = 10000;
     304                 :            : 
     305         [ +  - ]:          3 :     Xapian::Document doc;
     306 [ +  - ][ +  - ]:          3 :     doc.add_term("a");
     307         [ +  + ]:      30003 :     while (count) {
     308         [ +  - ]:      30000 :         db.add_document(doc);
     309                 :      30000 :         --count;
     310                 :            :     }
     311                 :            : 
     312         [ +  - ]:          3 :     db.commit();
     313                 :          3 : }
     314                 :            : 
     315                 :            : // Test use of compact on a database which has multiple chunks for a term.
     316                 :            : // This is a regression test for ticket #427
     317                 :          3 : DEFINE_TESTCASE(compactmultichunks1, compact && generated) {
     318 [ +  - ][ +  - ]:          3 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     319                 :            : 
     320                 :            :     string indbpath = get_database_path("compactmultichunks1in",
     321 [ +  - ][ +  - ]:          3 :                                         make_multichunk_db, "");
                 [ +  - ]
     322 [ +  - ][ +  - ]:          6 :     string outdbpath = get_compaction_output_path("compactmultichunks1out");
     323         [ +  - ]:          3 :     rm_rf(outdbpath);
     324                 :            : 
     325                 :            :     {
     326         [ +  - ]:          3 :         Xapian::Database db(indbpath);
     327         [ +  - ]:          3 :         db.compact(outdbpath);
     328                 :            :     }
     329                 :            : 
     330         [ +  - ]:          6 :     Xapian::Database indb(indbpath);
     331         [ +  - ]:          6 :     Xapian::Database outdb(outdbpath);
     332                 :            : 
     333 [ +  - ][ +  - ]:          3 :     TEST_EQUAL(indb.get_doccount(), outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     334 [ +  - ][ +  - ]:          3 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     335                 :            : 
     336                 :          3 :     return true;
     337                 :            : }
     338                 :            : 
     339                 :            : // Test compacting from a stub database directory.
     340                 :          4 : DEFINE_TESTCASE(compactstub1, compact) {
     341 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     342                 :            : 
     343                 :          4 :     const char * stubpath = ".stub/compactstub1";
     344                 :          4 :     const char * stubpathfile = ".stub/compactstub1/XAPIANDB";
     345                 :          4 :     mkdir(".stub", 0755);
     346                 :          4 :     mkdir(stubpath, 0755);
     347         [ +  - ]:          4 :     ofstream stub(stubpathfile);
     348 [ +  - ][ -  + ]:          4 :     TEST(stub.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     349 [ +  - ][ +  - ]:          4 :     stub << "auto ../../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     350 [ +  - ][ +  - ]:          4 :     stub << "auto ../../" << get_database_path("apitest_simpledata2") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     351         [ +  - ]:          4 :     stub.close();
     352                 :            : 
     353 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compactstub1out");
     354         [ +  - ]:          4 :     rm_rf(outdbpath);
     355                 :            : 
     356                 :            :     {
     357 [ +  - ][ +  - ]:          4 :         Xapian::Database db(stubpath);
     358         [ +  - ]:          4 :         db.compact(outdbpath);
     359                 :            :     }
     360                 :            : 
     361 [ +  - ][ +  - ]:          8 :     Xapian::Database indb(stubpath);
     362         [ +  - ]:          8 :     Xapian::Database outdb(outdbpath);
     363                 :            : 
     364 [ +  - ][ +  - ]:          4 :     TEST_EQUAL(indb.get_doccount(), outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     365 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     366                 :            : 
     367                 :          4 :     return true;
     368                 :            : }
     369                 :            : 
     370                 :            : // Test compacting from a stub database file.
     371                 :          4 : DEFINE_TESTCASE(compactstub2, compact) {
     372 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     373                 :            : 
     374                 :          4 :     const char * stubpath = ".stub/compactstub2";
     375                 :          4 :     mkdir(".stub", 0755);
     376         [ +  - ]:          4 :     ofstream stub(stubpath);
     377 [ +  - ][ -  + ]:          4 :     TEST(stub.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     378 [ +  - ][ +  - ]:          4 :     stub << "auto ../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     379 [ +  - ][ +  - ]:          4 :     stub << "auto ../" << get_database_path("apitest_simpledata2") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     380         [ +  - ]:          4 :     stub.close();
     381                 :            : 
     382 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compactstub2out");
     383         [ +  - ]:          4 :     rm_rf(outdbpath);
     384                 :            : 
     385                 :            :     {
     386 [ +  - ][ +  - ]:          4 :         Xapian::Database db(stubpath);
     387         [ +  - ]:          4 :         db.compact(outdbpath);
     388                 :            :     }
     389                 :            : 
     390 [ +  - ][ +  - ]:          8 :     Xapian::Database indb(stubpath);
     391         [ +  - ]:          8 :     Xapian::Database outdb(outdbpath);
     392                 :            : 
     393 [ +  - ][ +  - ]:          4 :     TEST_EQUAL(indb.get_doccount(), outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     394 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     395                 :            : 
     396                 :          4 :     return true;
     397                 :            : }
     398                 :            : 
     399                 :            : // Test compacting a stub database file to itself.
     400                 :          4 : DEFINE_TESTCASE(compactstub3, compact) {
     401 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     402                 :            : 
     403                 :          4 :     const char * stubpath = ".stub/compactstub3";
     404                 :          4 :     mkdir(".stub", 0755);
     405         [ +  - ]:          4 :     ofstream stub(stubpath);
     406 [ +  - ][ -  + ]:          4 :     TEST(stub.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     407 [ +  - ][ +  - ]:          4 :     stub << "auto ../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     408 [ +  - ][ +  - ]:          4 :     stub << "auto ../" << get_database_path("apitest_simpledata2") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     409         [ +  - ]:          4 :     stub.close();
     410                 :            : 
     411                 :            :     Xapian::doccount in_docs;
     412                 :            :     {
     413 [ +  - ][ +  - ]:          4 :         Xapian::Database indb(stubpath);
     414         [ +  - ]:          4 :         in_docs = indb.get_doccount();
     415 [ +  - ][ +  - ]:          4 :         indb.compact(stubpath);
     416                 :            :     }
     417                 :            : 
     418 [ +  - ][ +  - ]:          8 :     Xapian::Database outdb(stubpath);
     419                 :            : 
     420 [ +  - ][ -  + ]:          4 :     TEST_EQUAL(in_docs, outdb.get_doccount());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     421 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     422                 :            : 
     423                 :          4 :     return true;
     424                 :            : }
     425                 :            : 
     426                 :            : // Test compacting a stub database directory to itself.
     427                 :          4 : DEFINE_TESTCASE(compactstub4, compact) {
     428 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     429                 :            : 
     430                 :          4 :     const char * stubpath = ".stub/compactstub4";
     431                 :          4 :     const char * stubpathfile = ".stub/compactstub4/XAPIANDB";
     432                 :          4 :     mkdir(".stub", 0755);
     433                 :          4 :     mkdir(stubpath, 0755);
     434         [ +  - ]:          4 :     ofstream stub(stubpathfile);
     435 [ +  - ][ -  + ]:          4 :     TEST(stub.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     436 [ +  - ][ +  - ]:          4 :     stub << "auto ../../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     437 [ +  - ][ +  - ]:          4 :     stub << "auto ../../" << get_database_path("apitest_simpledata2") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     438         [ +  - ]:          4 :     stub.close();
     439                 :            : 
     440                 :            :     Xapian::doccount in_docs;
     441                 :            :     {
     442 [ +  - ][ +  - ]:          4 :         Xapian::Database indb(stubpath);
     443         [ +  - ]:          4 :         in_docs = indb.get_doccount();
     444 [ +  - ][ +  - ]:          4 :         indb.compact(stubpath);
     445                 :            :     }
     446                 :            : 
     447 [ +  - ][ +  - ]:          8 :     Xapian::Database outdb(stubpath);
     448                 :            : 
     449 [ +  - ][ -  + ]:          4 :     TEST_EQUAL(in_docs, outdb.get_doccount());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     450 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  + ]
     451                 :            : 
     452                 :          4 :     return true;
     453                 :            : }
     454                 :            : 
     455                 :            : static void
     456                 :          6 : make_all_tables(Xapian::WritableDatabase &db, const string &)
     457                 :            : {
     458         [ +  - ]:          6 :     Xapian::Document doc;
     459 [ +  - ][ +  - ]:          6 :     doc.add_term("foo");
     460         [ +  - ]:          6 :     db.add_document(doc);
     461 [ +  - ][ +  - ]:          6 :     db.add_spelling("foo");
     462 [ +  - ][ +  - ]:          6 :     db.add_synonym("bar", "pub");
                 [ +  - ]
     463 [ +  - ][ +  - ]:          6 :     db.add_synonym("foobar", "foo");
                 [ +  - ]
     464                 :            : 
     465         [ +  - ]:          6 :     db.commit();
     466                 :          6 : }
     467                 :            : 
     468                 :            : static void
     469                 :          3 : make_missing_tables(Xapian::WritableDatabase &db, const string &)
     470                 :            : {
     471         [ +  - ]:          3 :     Xapian::Document doc;
     472 [ +  - ][ +  - ]:          3 :     doc.add_term("foo");
     473         [ +  - ]:          3 :     db.add_document(doc);
     474                 :            : 
     475         [ +  - ]:          3 :     db.commit();
     476                 :          3 : }
     477                 :            : 
     478                 :          3 : DEFINE_TESTCASE(compactmissingtables1, compact && generated) {
     479 [ +  - ][ +  - ]:          3 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     480                 :            : 
     481                 :            :     string a = get_database_path("compactmissingtables1a",
     482 [ +  - ][ +  - ]:          3 :                                  make_all_tables);
                 [ +  - ]
     483                 :            :     string b = get_database_path("compactmissingtables1b",
     484 [ +  - ][ +  - ]:          6 :                                  make_missing_tables);
                 [ +  - ]
     485                 :            : 
     486 [ +  - ][ +  - ]:          6 :     string out = get_compaction_output_path("compactmissingtables1out");
     487         [ +  - ]:          3 :     rm_rf(out);
     488                 :            : 
     489                 :            :     {
     490         [ +  - ]:          3 :         Xapian::Database db;
     491 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(a));
     492 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(b));
     493         [ +  - ]:          3 :         db.compact(out);
     494                 :            :     }
     495                 :            : 
     496                 :            :     {
     497         [ +  - ]:          3 :         Xapian::Database db(out);
     498 [ +  - ][ -  + ]:          3 :         TEST_NOT_EQUAL(db.spellings_begin(), db.spellings_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     499 [ +  - ][ +  - ]:          3 :         TEST_NOT_EQUAL(db.synonym_keys_begin(), db.synonym_keys_end());
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     500                 :            :         // FIXME: arrange for input b to not have a termlist table.
     501                 :            : //      TEST_EXCEPTION(Xapian::FeatureUnavailableError, db.termlist_begin(1));
     502                 :            :     }
     503                 :            : 
     504                 :          3 :     return true;
     505                 :            : }
     506                 :            : 
     507                 :            : static void
     508                 :          3 : make_all_tables2(Xapian::WritableDatabase &db, const string &)
     509                 :            : {
     510         [ +  - ]:          3 :     Xapian::Document doc;
     511 [ +  - ][ +  - ]:          3 :     doc.add_term("bar");
     512         [ +  - ]:          3 :     db.add_document(doc);
     513 [ +  - ][ +  - ]:          3 :     db.add_spelling("bar");
     514 [ +  - ][ +  - ]:          3 :     db.add_synonym("bar", "baa");
                 [ +  - ]
     515 [ +  - ][ +  - ]:          3 :     db.add_synonym("barfoo", "barbar");
                 [ +  - ]
     516 [ +  - ][ +  - ]:          3 :     db.add_synonym("foofoo", "barfoo");
                 [ +  - ]
     517                 :            : 
     518         [ +  - ]:          3 :     db.commit();
     519                 :          3 : }
     520                 :            : 
     521                 :            : /// Adds coverage for merging synonym table.
     522                 :          3 : DEFINE_TESTCASE(compactmergesynonym1, compact && generated) {
     523 [ +  - ][ +  - ]:          3 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     524                 :            : 
     525                 :            :     string a = get_database_path("compactmergesynonym1a",
     526 [ +  - ][ +  - ]:          3 :                                  make_all_tables);
                 [ +  - ]
     527                 :            :     string b = get_database_path("compactmergesynonym1b",
     528 [ +  - ][ +  - ]:          6 :                                  make_all_tables2);
                 [ +  - ]
     529                 :            : 
     530 [ +  - ][ +  - ]:          6 :     string out = get_compaction_output_path("compactmergesynonym1out");
     531         [ +  - ]:          3 :     rm_rf(out);
     532                 :            : 
     533                 :            :     {
     534         [ +  - ]:          3 :         Xapian::Database db;
     535 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(a));
     536 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(b));
     537         [ +  - ]:          3 :         db.compact(out);
     538                 :            :     }
     539                 :            : 
     540                 :            :     {
     541         [ +  - ]:          3 :         Xapian::Database db(out);
     542                 :            : 
     543         [ +  - ]:          6 :         Xapian::TermIterator i = db.spellings_begin();
     544 [ -  + ][ #  # ]:          3 :         TEST_NOT_EQUAL(i, db.spellings_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     545 [ +  - ][ +  - ]:          3 :         TEST_EQUAL(*i, "bar");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     546         [ +  - ]:          3 :         ++i;
     547 [ -  + ][ #  # ]:          3 :         TEST_NOT_EQUAL(i, db.spellings_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     548 [ +  - ][ +  - ]:          3 :         TEST_EQUAL(*i, "foo");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     549         [ +  - ]:          3 :         ++i;
     550 [ -  + ][ #  # ]:          3 :         TEST_EQUAL(i, db.spellings_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     551                 :            : 
     552 [ +  - ][ +  - ]:          3 :         i = db.synonym_keys_begin();
                 [ +  - ]
     553 [ +  - ][ +  + ]:          3 :         TEST_NOT_EQUAL(i, db.synonym_keys_end());
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     554 [ +  - ][ +  - ]:          2 :         TEST_EQUAL(*i, "bar");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     555         [ +  - ]:          2 :         ++i;
     556 [ +  - ][ -  + ]:          2 :         TEST_NOT_EQUAL(i, db.synonym_keys_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     557 [ +  - ][ +  - ]:          2 :         TEST_EQUAL(*i, "barfoo");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     558         [ +  - ]:          2 :         ++i;
     559 [ +  - ][ -  + ]:          2 :         TEST_NOT_EQUAL(i, db.synonym_keys_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     560 [ +  - ][ +  - ]:          2 :         TEST_EQUAL(*i, "foobar");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     561         [ +  - ]:          2 :         ++i;
     562 [ +  - ][ -  + ]:          2 :         TEST_NOT_EQUAL(i, db.synonym_keys_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     563 [ +  - ][ +  - ]:          2 :         TEST_EQUAL(*i, "foofoo");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     564         [ +  - ]:          2 :         ++i;
     565 [ +  - ][ -  + ]:          5 :         TEST_EQUAL(i, db.synonym_keys_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     566                 :            :     }
     567                 :            : 
     568                 :          3 :     return true;
     569                 :            : }
     570                 :            : 
     571                 :          4 : DEFINE_TESTCASE(compactempty1, compact) {
     572 [ +  - ][ +  - ]:          4 :     string empty_dbpath = get_database_path(string());
     573 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compactempty1out");
     574         [ +  - ]:          4 :     rm_rf(outdbpath);
     575                 :            : 
     576                 :            :     {
     577                 :            :         // Compacting an empty database tried to divide by zero in 1.3.0.
     578         [ +  - ]:          4 :         Xapian::Database db;
     579 [ +  - ][ +  - ]:          4 :         db.add_database(Xapian::Database(empty_dbpath));
     580         [ +  - ]:          4 :         db.compact(outdbpath);
     581                 :            : 
     582         [ +  - ]:          8 :         Xapian::Database outdb(outdbpath);
     583 [ +  - ][ -  + ]:          4 :         TEST_EQUAL(outdb.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     584         [ +  - ]:          8 :         dbcheck(outdb, 0, 0);
     585                 :            :     }
     586                 :            : 
     587                 :            :     {
     588                 :            :         // Check compacting two empty databases together.
     589         [ +  - ]:          4 :         Xapian::Database db;
     590 [ +  - ][ +  - ]:          4 :         db.add_database(Xapian::Database(empty_dbpath));
     591 [ +  - ][ +  - ]:          4 :         db.add_database(Xapian::Database(empty_dbpath));
     592         [ +  - ]:          4 :         db.compact(outdbpath);
     593                 :            : 
     594         [ +  - ]:          8 :         Xapian::Database outdb(outdbpath);
     595 [ +  - ][ -  + ]:          4 :         TEST_EQUAL(outdb.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     596         [ +  - ]:          8 :         dbcheck(outdb, 0, 0);
     597                 :            :     }
     598                 :            : 
     599                 :          4 :     return true;
     600                 :            : }
     601                 :            : 
     602                 :          3 : DEFINE_TESTCASE(compactmultipass1, compact && generated) {
     603 [ +  - ][ +  - ]:          3 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     604                 :            : 
     605 [ +  - ][ +  - ]:          3 :     string outdbpath = get_compaction_output_path("compactmultipass1");
     606         [ +  - ]:          3 :     rm_rf(outdbpath);
     607                 :            : 
     608                 :            :     string a = get_database_path("compactnorenumber1a", make_sparse_db,
     609 [ +  - ][ +  - ]:          6 :                                  "5-7 24 76 987 1023-1027 9999 !9999");
                 [ +  - ]
     610                 :            :     string b = get_database_path("compactnorenumber1b", make_sparse_db,
     611 [ +  - ][ +  - ]:          6 :                                  "1027-1030");
                 [ +  - ]
     612                 :            :     string c = get_database_path("compactnorenumber1c", make_sparse_db,
     613 [ +  - ][ +  - ]:          6 :                                  "1028-1040");
                 [ +  - ]
     614                 :            :     string d = get_database_path("compactnorenumber1d", make_sparse_db,
     615 [ +  - ][ +  - ]:          6 :                                  "3000 999999 !999999");
                 [ +  - ]
     616                 :            : 
     617                 :            :     {
     618         [ +  - ]:          3 :         Xapian::Database db;
     619 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(a));
     620 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(b));
     621 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(c));
     622 [ +  - ][ +  - ]:          3 :         db.add_database(Xapian::Database(d));
     623         [ +  + ]:          3 :         db.compact(outdbpath, Xapian::DBCOMPACT_MULTIPASS);
     624                 :            :     }
     625                 :            : 
     626         [ +  - ]:          4 :     Xapian::Database outdb(outdbpath);
     627         [ +  - ]:          2 :     dbcheck(outdb, 29, 1041);
     628                 :            : 
     629                 :          3 :     return true;
     630                 :            : }
     631                 :            : 
     632                 :            : // Test compacting to an fd.
     633                 :          4 : DEFINE_TESTCASE(compacttofd1, compact) {
     634 [ +  - ][ +  - ]:          4 :     Xapian::Database indb(get_database("apitest_simpledata"));
     635 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compacttofd1out");
     636         [ +  - ]:          4 :     rm_rf(outdbpath);
     637                 :            : 
     638         [ +  - ]:          4 :     int fd = open(outdbpath.c_str(), O_CREAT|O_RDWR|O_BINARY, 0666);
     639 [ -  + ][ #  # ]:          4 :     TEST(fd != -1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     640         [ +  - ]:          4 :     indb.compact(fd);
     641                 :            : 
     642                 :            :     // Confirm that the fd was closed by Xapian.  Set errno first to workaround
     643                 :            :     // a bug in Wine's msvcrt.dll which fails to set errno in this case:
     644                 :            :     // https://bugs.winehq.org/show_bug.cgi?id=43902
     645                 :          4 :     errno = EBADF;
     646                 :            :     {
     647                 :          4 :         MSVCIgnoreInvalidParameter invalid_fd_in_close_is_expected;
     648 [ +  - ][ -  + ]:          4 :         TEST(close(fd) == -1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     649 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(errno, EBADF);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     650                 :            :     }
     651                 :            : 
     652         [ +  - ]:          8 :     Xapian::Database outdb(outdbpath);
     653                 :            : 
     654 [ +  - ][ +  - ]:          4 :     TEST_EQUAL(indb.get_doccount(), outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     655 [ +  - ][ +  - ]:          4 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  - ]
     656                 :            : 
     657                 :          4 :     return true;
     658                 :            : }
     659                 :            : 
     660                 :            : // Test compacting to an fd at at offset.
     661                 :          4 : DEFINE_TESTCASE(compacttofd2, compact) {
     662 [ +  - ][ +  - ]:          4 :     XFAIL_FOR_BACKEND("honey", "Honey->honey compaction is currently buggy");
     663                 :            : 
     664 [ +  - ][ +  - ]:          4 :     Xapian::Database indb(get_database("apitest_simpledata"));
     665 [ +  - ][ +  - ]:          8 :     string outdbpath = get_compaction_output_path("compacttofd2out");
     666         [ +  - ]:          4 :     rm_rf(outdbpath);
     667                 :            : 
     668         [ +  - ]:          4 :     int fd = open(outdbpath.c_str(), O_CREAT|O_RDWR|O_BINARY, 0666);
     669 [ -  + ][ #  # ]:          4 :     TEST(fd != -1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     670 [ -  + ][ #  # ]:          4 :     TEST(lseek(fd, 8192, SEEK_SET) == 8192);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     671         [ +  - ]:          4 :     indb.compact(fd);
     672                 :            : 
     673                 :            :     // Confirm that the fd was closed by Xapian.  Set errno first to workaround
     674                 :            :     // a bug in Wine's msvcrt.dll which fails to set errno in this case:
     675                 :            :     // https://bugs.winehq.org/show_bug.cgi?id=43902
     676                 :          4 :     errno = EBADF;
     677                 :            :     {
     678                 :          4 :         MSVCIgnoreInvalidParameter invalid_fd_in_close_is_expected;
     679 [ +  - ][ -  + ]:          4 :         TEST(close(fd) == -1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     680 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(errno, EBADF);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     681                 :            :     }
     682                 :            : 
     683         [ +  - ]:          4 :     fd = open(outdbpath.c_str(), O_RDONLY|O_BINARY, 0666);
     684 [ -  + ][ #  # ]:          4 :     TEST(fd != -1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     685                 :            : 
     686                 :            :     // Test that the database wasn't just written to the start of the file.
     687                 :            :     char buf[8192];
     688                 :          4 :     size_t n = sizeof(buf);
     689         [ +  + ]:          7 :     while (n) {
     690         [ +  - ]:          4 :         ssize_t c = read(fd, buf, n);
     691 [ -  + ][ #  # ]:          4 :         TEST(c > 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     692         [ +  + ]:      25605 :         for (const char * p = buf; p != buf + c; ++p) {
     693 [ +  + ][ +  - ]:      25602 :             TEST(*p == 0);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     694                 :            :         }
     695                 :          3 :         n -= c;
     696                 :            :     }
     697                 :            : 
     698 [ -  + ][ #  # ]:          3 :     TEST(lseek(fd, 8192, SEEK_SET) == 8192);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     699         [ +  - ]:          6 :     Xapian::Database outdb(fd);
     700                 :            : 
     701 [ +  - ][ +  - ]:          3 :     TEST_EQUAL(indb.get_doccount(), outdb.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     702 [ +  - ][ +  - ]:          3 :     dbcheck(outdb, outdb.get_doccount(), outdb.get_doccount());
                 [ +  - ]
     703                 :            : 
     704                 :          4 :     return true;
     705                 :            : }
     706                 :            : 
     707                 :            : // Regression test for bug fixed in 1.3.5.  If you compact a WritableDatabase
     708                 :            : // with uncommitted changes, you get an inconsistent output.
     709                 :          2 : DEFINE_TESTCASE(compactsingle1, compact && writable) {
     710 [ +  - ][ +  - ]:          2 :     Xapian::WritableDatabase db = get_writable_database();
     711         [ +  - ]:          4 :     Xapian::Document doc;
     712 [ +  - ][ +  - ]:          2 :     doc.add_term("foo");
     713 [ +  - ][ +  - ]:          2 :     doc.add_term("bar");
     714 [ +  - ][ +  - ]:          2 :     doc.add_term("baz");
     715         [ +  - ]:          2 :     db.add_document(doc);
     716                 :            :     // Include a zero-length document as a regression test for a
     717                 :            :     // Database::check() bug fixed in 1.4.7 (and introduced in 1.4.6).  Test it
     718                 :            :     // here so we also have test coverage for compaction for such a document.
     719         [ +  - ]:          4 :     Xapian::Document doc2;
     720 [ +  - ][ +  - ]:          2 :     doc2.add_boolean_term("Kfoo");
     721         [ +  - ]:          2 :     db.add_document(doc2);
     722                 :            :     // Also test a completely empty document.
     723 [ +  - ][ +  - ]:          2 :     db.add_document(Xapian::Document());
     724                 :            : 
     725 [ +  - ][ +  - ]:          4 :     string output = get_compaction_output_path("compactsingle1-out");
     726                 :            :     // In 1.3.4, we would hang if the output file already existed, so check
     727                 :            :     // that works.
     728         [ +  - ]:          2 :     touch(output);
     729                 :            : 
     730 [ +  - ][ -  + ]:          2 :     TEST_EXCEPTION(Xapian::InvalidOperationError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     731                 :            :         db.compact(output, Xapian::DBCOMPACT_SINGLE_FILE));
     732                 :            : 
     733                 :            :     // Check the file wasn't removed by the failed attempt.
     734   [ -  +  #  #  :          2 :     TEST(file_exists(output));
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     735                 :            : 
     736         [ +  - ]:          2 :     db.commit();
     737         [ +  - ]:          2 :     db.compact(output, Xapian::DBCOMPACT_SINGLE_FILE);
     738         [ +  - ]:          2 :     db.close();
     739                 :            : 
     740 [ +  - ][ -  +  :          2 :     TEST_EQUAL(Xapian::Database::check(output, 0, &tout), 0);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     741                 :            : 
     742 [ +  - ][ +  - ]:          2 :     TEST_EQUAL(Xapian::Database(output).get_doccount(), 3);
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     743                 :            : 
     744                 :          2 :     return true;
     745                 :            : }
     746                 :            : 
     747                 :            : // Regression test for bug fixed in 1.4.6.  Same as above, except not with
     748                 :            : // a single file database!
     749                 :          2 : DEFINE_TESTCASE(compact1, compact && writable) {
     750 [ +  - ][ +  - ]:          2 :     Xapian::WritableDatabase db = get_writable_database();
     751         [ +  - ]:          4 :     Xapian::Document doc;
     752 [ +  - ][ +  - ]:          2 :     doc.add_term("foo");
     753 [ +  - ][ +  - ]:          2 :     doc.add_term("bar");
     754 [ +  - ][ +  - ]:          2 :     doc.add_term("baz");
     755         [ +  - ]:          2 :     db.add_document(doc);
     756                 :            :     // Include a zero-length document as a regression test for a
     757                 :            :     // Database::check() bug fixed in 1.4.7 (and introduced in 1.4.6).  Test it
     758                 :            :     // here so we also have test coverage for compaction for such a document.
     759         [ +  - ]:          4 :     Xapian::Document doc2;
     760 [ +  - ][ +  - ]:          2 :     doc2.add_boolean_term("Kfoo");
     761         [ +  - ]:          2 :     db.add_document(doc2);
     762                 :            :     // Also test a completely empty document.
     763 [ +  - ][ +  - ]:          2 :     db.add_document(Xapian::Document());
     764                 :            : 
     765 [ +  - ][ +  - ]:          4 :     string output = get_compaction_output_path("compact1-out");
     766         [ +  - ]:          2 :     rm_rf(output);
     767                 :            : 
     768 [ +  - ][ -  + ]:          2 :     TEST_EXCEPTION(Xapian::InvalidOperationError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     769                 :            :         db.compact(output));
     770                 :            : 
     771         [ +  - ]:          2 :     db.commit();
     772         [ +  - ]:          2 :     db.compact(output);
     773         [ +  - ]:          2 :     db.close();
     774                 :            : 
     775 [ +  - ][ -  +  :          2 :     TEST_EQUAL(Xapian::Database::check(output, 0, &tout), 0);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     776                 :            : 
     777 [ +  - ][ +  - ]:          2 :     TEST_EQUAL(Xapian::Database(output).get_doccount(), 3);
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     778                 :            : 
     779                 :          2 :     return true;
     780                 :            : }

Generated by: LCOV version 1.11