LCOV - code coverage report
Current view: top level - tests - api_db.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 1088 1107 98.3 %
Date: 2019-06-30 05:20:33 Functions: 59 63 93.7 %
Branches: 1914 12018 15.9 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_db.cc
       2                 :            :  * @brief tests which need a backend
       3                 :            :  */
       4                 :            : /* Copyright 1999,2000,2001 BrightStation PLC
       5                 :            :  * Copyright 2002 Ananova Ltd
       6                 :            :  * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2011,2012,2013,2015,2016,2017,2019 Olly Betts
       7                 :            :  * Copyright 2006,2007,2008,2009 Lemur Consulting Ltd
       8                 :            :  *
       9                 :            :  * This program is free software; you can redistribute it and/or
      10                 :            :  * modify it under the terms of the GNU General Public License as
      11                 :            :  * published by the Free Software Foundation; either version 2 of the
      12                 :            :  * License, or (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This program is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :            :  * GNU General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU General Public License
      20                 :            :  * along with this program; if not, write to the Free Software
      21                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      22                 :            :  * USA
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <config.h>
      26                 :            : 
      27                 :            : #include "api_db.h"
      28                 :            : 
      29                 :            : #include <algorithm>
      30                 :            : #include <fstream>
      31                 :            : #include <map>
      32                 :            : #include <string>
      33                 :            : #include <vector>
      34                 :            : #include "safenetdb.h" // For gai_strerror().
      35                 :            : #include "safesysstat.h" // For mkdir().
      36                 :            : #include "safeunistd.h" // For sleep().
      37                 :            : 
      38                 :            : #include <xapian.h>
      39                 :            : 
      40                 :            : #include "backendmanager.h"
      41                 :            : #include "backendmanager_local.h"
      42                 :            : #include "testsuite.h"
      43                 :            : #include "testutils.h"
      44                 :            : #include "unixcmds.h"
      45                 :            : 
      46                 :            : #include "apitest.h"
      47                 :            : 
      48                 :            : using namespace std;
      49                 :            : 
      50                 :            : static Xapian::Query
      51                 :          6 : query(const string &t)
      52                 :            : {
      53 [ +  - ][ +  - ]:          6 :     return Xapian::Query(Xapian::Stem("english")(t));
         [ +  - ][ +  - ]
      54                 :            : }
      55                 :            : 
      56                 :            : // #######################################################################
      57                 :            : // # Tests start here
      58                 :            : 
      59                 :            : // tests Xapian::Database::get_termfreq() and Xapian::Database::term_exists()
      60                 :          7 : DEFINE_TESTCASE(termstats, backend) {
      61 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
      62                 :            : 
      63 [ +  - ][ +  - ]:          7 :     TEST(!db.term_exists("corn"));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      64 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_termfreq("corn"), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      65 [ +  - ][ +  - ]:          7 :     TEST(db.term_exists("banana"));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      66 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_termfreq("banana"), 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      67 [ +  - ][ +  - ]:          7 :     TEST(db.term_exists("paragraph"));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      68 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_termfreq("paragraph"), 5);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      69                 :            : 
      70                 :          7 :     return true;
      71                 :            : }
      72                 :            : 
      73                 :            : // Check that stub databases work.
      74                 :          4 : DEFINE_TESTCASE(stubdb1, path) {
      75                 :          4 :     mkdir(".stub", 0755);
      76                 :          4 :     const char * dbpath = ".stub/stubdb1";
      77         [ +  - ]:          4 :     ofstream out(dbpath);
      78 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      79 [ +  - ][ +  - ]:          4 :     out << "auto ../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
      80         [ +  - ]:          4 :     out.close();
      81                 :            : 
      82                 :            :     {
      83 [ +  - ][ +  - ]:          4 :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB);
      84         [ +  - ]:          8 :         Xapian::Enquire enquire(db);
      85 [ +  - ][ +  - ]:          4 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
      86         [ +  - ]:          8 :         enquire.get_mset(0, 10);
      87                 :            :     }
      88                 :            :     {
      89 [ +  - ][ +  - ]:          4 :         Xapian::Database db(dbpath);
      90         [ +  - ]:          8 :         Xapian::Enquire enquire(db);
      91 [ +  - ][ +  - ]:          4 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
      92         [ +  - ]:          8 :         enquire.get_mset(0, 10);
      93                 :            :     }
      94                 :            : 
      95                 :            :     try {
      96 [ +  - ][ +  + ]:          4 :         TEST_EQUAL(Xapian::Database::check(dbpath), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      97 [ -  + ][ +  - ]:          2 :     } catch (const Xapian::UnimplementedError& e) {
      98 [ -  + ][ -  +  :          1 :         TEST_STRINGS_EQUAL(e.get_msg(),
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      99                 :            :                            "Honey database checking not implemented");
     100                 :            :     }
     101                 :            : 
     102                 :          4 :     return true;
     103                 :            : }
     104                 :            : 
     105                 :            : // Check that stub databases work remotely.
     106                 :          4 : DEFINE_TESTCASE(stubdb2, path) {
     107                 :          4 :     mkdir(".stub", 0755);
     108                 :          4 :     const char * dbpath = ".stub/stubdb2";
     109         [ +  - ]:          4 :     ofstream out(dbpath);
     110 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     111 [ +  - ][ +  - ]:          4 :     out << "remote :" << BackendManager::get_xapian_progsrv_command()
                 [ +  - ]
     112 [ +  - ][ +  - ]:          8 :         << ' ' << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     113         [ +  - ]:          4 :     out.close();
     114                 :            : 
     115                 :            :     try {
     116 [ +  - ][ +  - ]:          4 :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB);
     117         [ +  - ]:          8 :         Xapian::Enquire enquire(db);
     118 [ +  - ][ +  - ]:          4 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
     119         [ +  - ]:          8 :         enquire.get_mset(0, 10);
     120         [ #  # ]:          0 :     } catch (Xapian::FeatureUnavailableError&) {
     121                 :            : #ifdef XAPIAN_HAS_REMOTE_BACKEND
     122                 :          0 :         throw;
     123                 :            : #endif
     124                 :            :     }
     125                 :            : 
     126                 :            :     try {
     127 [ +  - ][ +  - ]:          4 :         Xapian::Database db(dbpath);
     128         [ +  - ]:          8 :         Xapian::Enquire enquire(db);
     129 [ +  - ][ +  - ]:          4 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
     130         [ +  - ]:          8 :         enquire.get_mset(0, 10);
     131         [ #  # ]:          0 :     } catch (Xapian::FeatureUnavailableError&) {
     132                 :            : #ifdef XAPIAN_HAS_REMOTE_BACKEND
     133                 :          4 :         throw;
     134                 :            : #endif
     135                 :            :     }
     136                 :            : 
     137         [ +  - ]:          4 :     out.open(dbpath);
     138 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     139 [ +  - ][ +  - ]:          4 :     out << "remote" << endl;
     140         [ +  - ]:          4 :     out.close();
     141                 :            : 
     142                 :            :     // Quietly ignored prior to 1.4.1.
     143 [ +  - ][ +  - ]:          8 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     144                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB)
     145                 :            :     );
     146                 :            : 
     147                 :            :     // Quietly ignored prior to 1.4.1.
     148 [ +  - ][ -  +  :          4 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     149                 :            :         Xapian::WritableDatabase db(dbpath, Xapian::DB_BACKEND_STUB)
     150                 :            :     );
     151                 :            : 
     152                 :            : #ifdef XAPIAN_HAS_REMOTE_BACKEND
     153                 :            : # define EXPECTED_EXCEPTION Xapian::DatabaseOpeningError
     154                 :            : #else
     155                 :            : # define EXPECTED_EXCEPTION Xapian::FeatureUnavailableError
     156                 :            : #endif
     157                 :            : 
     158         [ +  - ]:          8 :     out.open(dbpath);
     159 [ +  - ][ -  +  :          4 :     TEST(out.is_open());
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     160 [ +  - ][ +  - ]:          4 :     out << "remote foo" << endl;
     161         [ +  - ]:          4 :     out.close();
     162                 :            : 
     163                 :            :     // Quietly ignored prior to 1.4.1.
     164 [ +  - ][ +  - ]:          8 :     TEST_EXCEPTION(EXPECTED_EXCEPTION,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     165                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB)
     166                 :            :     );
     167                 :            : 
     168                 :            :     // Quietly ignored prior to 1.4.1.
     169 [ +  - ][ -  +  :          4 :     TEST_EXCEPTION(EXPECTED_EXCEPTION,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     170                 :            :         Xapian::WritableDatabase db(dbpath, Xapian::DB_BACKEND_STUB)
     171                 :            :     );
     172                 :            : 
     173                 :            : #ifdef XAPIAN_HAS_REMOTE_BACKEND
     174         [ +  - ]:          8 :     out.open(dbpath);
     175 [ +  - ][ -  +  :          4 :     TEST(out.is_open());
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     176 [ +  - ][ +  - ]:          4 :     out << "remote [::1]:65535" << endl;
     177         [ +  - ]:          4 :     out.close();
     178                 :            : 
     179                 :            :     try {
     180 [ +  - ][ -  + ]:          8 :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB);
     181         [ -  + ]:         12 :     } catch (const Xapian::NetworkError& e) {
     182                 :            :         // 1.4.0 threw (on Linux) the confusing message:
     183                 :            :         //  NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
     184                 :            :         // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
     185                 :            :         //  NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (nodename nor servname provided, or not known)
     186                 :            :         // or on OS X (EAI_NONAME):
     187                 :            :         //  NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (Address family for hostname not supported)
     188                 :            :         //
     189                 :            :         // But NetBSD seems to resolve ::1 to an IPv4 address and then tries
     190                 :            :         // to connect to it (which hopefully fails), so just test the message
     191                 :            :         // doesn't match the bad 1.4.0 result.
     192 [ -  + ][ -  +  :          4 :         TEST(e.get_msg().find("host [") == string::npos);
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     193                 :            :     }
     194                 :            : 
     195                 :            :     try {
     196 [ +  - ][ -  + ]:          8 :         Xapian::WritableDatabase db(dbpath, Xapian::DB_BACKEND_STUB);
     197         [ -  + ]:         12 :     } catch (const Xapian::NetworkError& e) {
     198                 :            :         // 1.4.0 threw (Linux):
     199                 :            :         //  NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
     200                 :            :         // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
     201                 :            :         //  NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (nodename nor servname provided, or not known)
     202                 :            :         // or on OS X (EAI_NONAME):
     203                 :            :         //  NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (Address family for hostname not supported)
     204                 :            :         // So we test the message instead of the error string for portability.
     205                 :            :         //
     206                 :            :         // But NetBSD seems to resolve ::1 to an IPv4 address and then tries
     207                 :            :         // to connect to it (which hopefully fails), so just test the message
     208                 :            :         // doesn't match the bad 1.4.0 result.
     209 [ -  + ][ -  +  :          4 :         TEST(e.get_msg().find("host [") == string::npos);
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     210                 :            :     }
     211                 :            : #endif
     212                 :            : 
     213         [ +  - ]:          4 :     out.open(dbpath);
     214 [ +  - ][ -  +  :          4 :     TEST(out.is_open());
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     215                 :            :     // Invalid - the port number is required.
     216 [ +  - ][ +  - ]:          4 :     out << "remote [::1]" << endl;
     217         [ +  - ]:          4 :     out.close();
     218                 :            : 
     219                 :            :     // 1.4.0 threw:
     220                 :            :     // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
     221 [ +  - ][ +  - ]:          8 :     TEST_EXCEPTION(EXPECTED_EXCEPTION,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     222                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB);
     223                 :            :     );
     224                 :            : 
     225                 :            :     // 1.4.0 threw:
     226                 :            :     // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
     227 [ +  - ][ -  +  :          4 :     TEST_EXCEPTION(EXPECTED_EXCEPTION,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     228                 :            :         Xapian::WritableDatabase db(dbpath, Xapian::DB_BACKEND_STUB);
     229                 :            :     );
     230                 :            : 
     231                 :          4 :     return true;
     232                 :            : }
     233                 :            : 
     234                 :            : // Regression test - bad entries were ignored after a good entry prior to 1.0.8.
     235                 :          4 : DEFINE_TESTCASE(stubdb3, path) {
     236                 :          4 :     mkdir(".stub", 0755);
     237                 :          4 :     const char * dbpath = ".stub/stubdb3";
     238         [ +  - ]:          4 :     ofstream out(dbpath);
     239 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     240 [ +  - ][ +  - ]:         12 :     out << "auto ../" << get_database_path("apitest_simpledata") << "\n"
         [ +  - ][ +  - ]
     241         [ +  - ]:          4 :            "bad line here\n";
     242         [ +  - ]:          4 :     out.close();
     243                 :            : 
     244 [ +  - ][ +  - ]:          8 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     245                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB));
     246                 :            : 
     247 [ +  - ][ -  +  :          4 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     248                 :            :         Xapian::Database db(dbpath));
     249                 :            : 
     250                 :          4 :     return true;
     251                 :            : }
     252                 :            : 
     253                 :            : // Test a stub database with just a bad entry.
     254                 :          1 : DEFINE_TESTCASE(stubdb4, !backend) {
     255                 :          1 :     mkdir(".stub", 0755);
     256                 :          1 :     const char * dbpath = ".stub/stubdb4";
     257         [ +  - ]:          1 :     ofstream out(dbpath);
     258 [ +  - ][ -  + ]:          1 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     259         [ +  - ]:          1 :     out << "bad line here\n";
     260         [ +  - ]:          1 :     out.close();
     261                 :            : 
     262 [ +  - ][ +  - ]:          2 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     263                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB));
     264                 :            : 
     265 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     266                 :            :         Xapian::Database db(dbpath));
     267                 :            : 
     268                 :          2 :     return true;
     269                 :            : }
     270                 :            : 
     271                 :            : // Test a stub database with a bad entry with no spaces (prior to 1.1.0 this
     272                 :            : // was deliberately allowed, though not documented.
     273                 :          4 : DEFINE_TESTCASE(stubdb5, path) {
     274                 :          4 :     mkdir(".stub", 0755);
     275                 :          4 :     const char * dbpath = ".stub/stubdb5";
     276         [ +  - ]:          4 :     ofstream out(dbpath);
     277 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     278                 :            :     out << "bad\n"
     279 [ +  - ][ +  - ]:          8 :            "auto ../" << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     280         [ +  - ]:          4 :     out.close();
     281                 :            : 
     282 [ +  - ][ +  - ]:          8 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     283                 :            :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB));
     284                 :            : 
     285 [ +  - ][ -  +  :          4 :     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     286                 :            :         Xapian::Database db(dbpath));
     287                 :            : 
     288                 :          4 :     return true;
     289                 :            : }
     290                 :            : 
     291                 :            : // Test a stub database with an inmemory database (new feature in 1.1.0).
     292                 :          1 : DEFINE_TESTCASE(stubdb6, inmemory) {
     293                 :          1 :     mkdir(".stub", 0755);
     294                 :          1 :     const char * dbpath = ".stub/stubdb6";
     295         [ +  - ]:          1 :     ofstream out(dbpath);
     296 [ +  - ][ -  + ]:          1 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     297         [ +  - ]:          1 :     out << "inmemory\n";
     298         [ +  - ]:          1 :     out.close();
     299                 :            : 
     300                 :            :     // Read-only tests:
     301                 :            :     {
     302 [ +  - ][ +  - ]:          1 :         Xapian::Database db(dbpath, Xapian::DB_BACKEND_STUB);
     303 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     304         [ +  - ]:          2 :         Xapian::Enquire enquire(db);
     305 [ +  - ][ +  - ]:          1 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
     306         [ +  - ]:          2 :         Xapian::MSet mset = enquire.get_mset(0, 10);
     307 [ +  - ][ -  + ]:          2 :         TEST(mset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     308                 :            :     }
     309                 :            :     {
     310 [ +  - ][ +  - ]:          1 :         Xapian::Database db(dbpath);
     311 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     312         [ +  - ]:          2 :         Xapian::Enquire enquire(db);
     313 [ +  - ][ +  - ]:          1 :         enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
     314         [ +  - ]:          2 :         Xapian::MSet mset = enquire.get_mset(0, 10);
     315 [ +  - ][ -  + ]:          2 :         TEST(mset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     316                 :            :     }
     317                 :            : 
     318                 :            :     // Writable tests:
     319                 :            :     {
     320                 :            :         Xapian::WritableDatabase db(dbpath,
     321 [ +  - ][ +  - ]:          1 :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_STUB);
     322 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     323 [ +  - ][ +  - ]:          1 :         db.add_document(Xapian::Document());
     324 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     325                 :            :     }
     326                 :            :     {
     327                 :            :         Xapian::WritableDatabase db(dbpath,
     328 [ +  - ][ +  - ]:          1 :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_STUB);
     329 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     330 [ +  - ][ +  - ]:          1 :         db.add_document(Xapian::Document());
     331 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(db.get_doccount(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     332                 :            :     }
     333                 :            : 
     334                 :          1 :     return true;
     335                 :            : }
     336                 :            : 
     337                 :            : /// Test error running Database::check() on a stub database.
     338                 :            : // Regression test - in 1.4.3 and earlier this threw
     339                 :            : // Xapian::DatabaseError.
     340                 :          1 : DEFINE_TESTCASE(stubdb8, inmemory) {
     341                 :          1 :     mkdir(".stub", 0755);
     342                 :          1 :     const char * dbpath = ".stub/stubdb8";
     343         [ +  - ]:          1 :     ofstream out(dbpath);
     344 [ +  - ][ -  + ]:          1 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     345         [ +  - ]:          1 :     out << "inmemory\n";
     346         [ +  - ]:          1 :     out.close();
     347                 :            : 
     348                 :            :     try {
     349 [ +  - ][ -  + ]:          1 :         Xapian::Database::check(dbpath);
     350 [ #  # ][ #  # ]:          0 :         FAIL_TEST("Managed to check inmemory stub");
         [ #  # ][ #  # ]
     351 [ -  + ][ +  - ]:          2 :     } catch (const Xapian::UnimplementedError& e) {
     352                 :            :         // Check the message is appropriate.
     353 [ -  + ][ -  +  :          1 :         TEST_STRINGS_EQUAL(e.get_msg(),
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     354                 :            :                            "InMemory database checking not implemented");
     355                 :            :     }
     356                 :          1 :     return true;
     357                 :            : }
     358                 :            : 
     359                 :            : /// Test error running Database::check() on a remote stub database.
     360                 :          4 : DEFINE_TESTCASE(stubdb9, path) {
     361                 :          4 :     mkdir(".stub", 0755);
     362                 :          4 :     const char * dbpath = ".stub/stubdb9";
     363         [ +  - ]:          4 :     ofstream out(dbpath);
     364 [ +  - ][ -  + ]:          4 :     TEST(out.is_open());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     365 [ +  - ][ +  - ]:          4 :     out << "remote :" << BackendManager::get_xapian_progsrv_command()
                 [ +  - ]
     366 [ +  - ][ +  - ]:          8 :         << ' ' << get_database_path("apitest_simpledata") << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     367         [ +  - ]:          4 :     out.close();
     368                 :            : 
     369                 :            :     try {
     370 [ +  - ][ -  + ]:          4 :         Xapian::Database::check(dbpath);
     371 [ #  # ][ #  # ]:          0 :         FAIL_TEST("Managed to check remote stub");
         [ #  # ][ #  # ]
     372 [ -  + ][ +  - ]:          8 :     } catch (const Xapian::UnimplementedError& e) {
     373                 :            :         // Check the message is appropriate.
     374 [ -  + ][ -  +  :          4 :         TEST_STRINGS_EQUAL(e.get_msg(),
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     375                 :            :                            "Remote database checking not implemented");
     376                 :            :     }
     377                 :          4 :     return true;
     378                 :            : }
     379                 :            : 
     380         [ -  + ]:         30 : class GrepMatchDecider : public Xapian::MatchDecider {
     381                 :            :     string needle;
     382                 :            :   public:
     383                 :         15 :     explicit GrepMatchDecider(const string& needle_)
     384         [ +  - ]:         15 :         : needle(needle_) {}
     385                 :            : 
     386                 :       5874 :     bool operator()(const Xapian::Document &doc) const {
     387                 :            :         // Note that this is not recommended usage of get_data()
     388                 :       5874 :         return doc.get_data().find(needle) != string::npos;
     389                 :            :     }
     390                 :            : };
     391                 :            : 
     392                 :            : // Test Xapian::MatchDecider functor.
     393                 :          5 : DEFINE_TESTCASE(matchdecider1, backend && !remote) {
     394 [ +  - ][ +  - ]:          5 :     Xapian::Database db(get_database("apitest_simpledata"));
     395         [ +  - ]:         10 :     Xapian::Enquire enquire(db);
     396 [ +  - ][ +  - ]:          5 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     397                 :            : 
     398 [ +  - ][ +  - ]:         10 :     GrepMatchDecider myfunctor("This is");
     399                 :            : 
     400         [ +  - ]:         10 :     Xapian::MSet mymset = enquire.get_mset(0, 100, 0, &myfunctor);
     401                 :            : 
     402 [ +  - ][ +  - ]:         10 :     vector<bool> docid_checked(db.get_lastdocid());
     403                 :            : 
     404                 :            :     // Check that we get the expected number of matches, and that they
     405                 :            :     // satisfy the condition.
     406         [ +  - ]:         10 :     Xapian::MSetIterator i = mymset.begin();
     407 [ +  - ][ -  + ]:          5 :     TEST(i != mymset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     408 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     409 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_matches_lower_bound(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     410 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_matches_upper_bound(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     411 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_matches_estimated(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     412 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     413 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     414 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     415 [ +  - ][ +  + ]:         20 :     for ( ; i != mymset.end(); ++i) {
     416         [ +  - ]:         15 :         const Xapian::Document doc(i.get_document());
     417 [ +  - ][ -  + ]:         15 :         TEST(myfunctor(doc));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     418         [ +  - ]:         15 :         docid_checked[*i] = true;
     419                 :         15 :     }
     420                 :            : 
     421                 :            :     // Check that there are some documents which aren't accepted by the match
     422                 :            :     // decider.
     423 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 100);
     424 [ +  - ][ -  + ]:          5 :     TEST(mymset.size() > 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     425                 :            : 
     426                 :            :     // Check that the bounds are appropriate even if we don't ask for any
     427                 :            :     // actual matches.
     428 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 0, 0, &myfunctor);
     429 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     430 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     431 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_matches_upper_bound(), 6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     432 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     433 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     434 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     435 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     436 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     437 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     438                 :            : 
     439                 :            :     // Check that the bounds are appropriate if we ask for only one hit.
     440                 :            :     // (Regression test - until SVN 10256, we didn't reduce the lower_bound
     441                 :            :     // appropriately, and returned 6 here.)
     442 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
     443 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     444 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     445 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     446 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     447 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     448 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     449 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     450 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     451 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     452 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     453 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     454 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     455 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     456                 :            : 
     457                 :            :     // Check that the other documents don't satisfy the condition.
     458         [ +  + ]:         30 :     for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
     459         [ +  + ]:         25 :         if (!docid_checked[did]) {
     460 [ +  - ][ +  - ]:         10 :             TEST(!myfunctor(db.get_document(did)));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     461                 :            :         }
     462                 :            :     }
     463                 :            : 
     464                 :            :     // Check that the bounds are appropriate if a collapse key is used.
     465                 :            :     // Use a value which is never set so we don't actually discard anything.
     466         [ +  - ]:          5 :     enquire.set_collapse_key(99);
     467 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
     468 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     469 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     470 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     471 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     472 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     473 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     474 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     475 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     476 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     477 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     478 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     479 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     480 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     481                 :            : 
     482                 :            :     // Check that the bounds are appropriate if a percentage cutoff is in
     483                 :            :     // use.  Set a 1% threshold so we don't actually discard anything.
     484         [ +  - ]:          5 :     enquire.set_collapse_key(Xapian::BAD_VALUENO);
     485         [ +  - ]:          5 :     enquire.set_cutoff(1);
     486 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
     487 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     488 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     489 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     490 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     491 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     492 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     493 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     494 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     495 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     496 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     497 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     498 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     499 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     500                 :            : 
     501                 :            :     // And now with both a collapse key and percentage cutoff.
     502         [ +  - ]:          5 :     enquire.set_collapse_key(99);
     503 [ +  - ][ +  - ]:          5 :     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
     504 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     505 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     506 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     507 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     508 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     509 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     510 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     511 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     512 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     513 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     514 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     515 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     516 [ +  - ][ -  + ]:          5 :     TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     517                 :            : 
     518                 :          5 :     return true;
     519                 :            : }
     520                 :            : 
     521                 :            : // Test Xapian::MatchDecider functor used as a match spy.
     522                 :          5 : DEFINE_TESTCASE(matchdecider2, backend && !remote) {
     523 [ +  - ][ +  - ]:          5 :     Xapian::Database db(get_database("apitest_simpledata"));
     524         [ +  - ]:         10 :     Xapian::Enquire enquire(db);
     525 [ +  - ][ +  - ]:          5 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     526                 :            : 
     527 [ +  - ][ +  - ]:         10 :     GrepMatchDecider myfunctor("This is");
     528                 :            : 
     529         [ +  - ]:         10 :     Xapian::MSet mymset = enquire.get_mset(0, 100, 0, NULL, &myfunctor);
     530                 :            : 
     531 [ +  - ][ +  - ]:         10 :     vector<bool> docid_checked(db.get_lastdocid());
     532                 :            : 
     533                 :            :     // Check that we get the expected number of matches, and that they
     534                 :            :     // satisfy the condition.
     535         [ +  - ]:         10 :     Xapian::MSetIterator i = mymset.begin();
     536 [ +  - ][ -  + ]:          5 :     TEST(i != mymset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     537 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mymset.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     538 [ +  - ][ +  + ]:         20 :     for ( ; i != mymset.end(); ++i) {
     539         [ +  - ]:         15 :         const Xapian::Document doc(i.get_document());
     540 [ +  - ][ -  + ]:         15 :         TEST(myfunctor(doc));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     541         [ +  - ]:         15 :         docid_checked[*i] = true;
     542                 :         15 :     }
     543                 :            : 
     544                 :            :     // Check that the other documents don't satisfy the condition.
     545         [ +  + ]:         30 :     for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
     546         [ +  + ]:         25 :         if (!docid_checked[did]) {
     547 [ +  - ][ +  - ]:         10 :             TEST(!myfunctor(db.get_document(did)));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     548                 :            :         }
     549                 :            :     }
     550                 :            : 
     551                 :          5 :     return true;
     552                 :            : }
     553                 :            : 
     554                 :            : // Regression test for lower bound using functor, sorting and collapsing.
     555                 :          5 : DEFINE_TESTCASE(matchdecider3, backend && !remote) {
     556 [ +  - ][ +  - ]:          5 :     Xapian::Database db(get_database("etext"));
     557         [ +  - ]:         10 :     Xapian::Enquire enquire(db);
     558 [ +  - ][ +  - ]:          5 :     enquire.set_query(Xapian::Query(""));
                 [ +  - ]
     559         [ +  - ]:          5 :     enquire.set_collapse_key(12);
     560         [ +  - ]:          5 :     enquire.set_sort_by_value(11, true);
     561                 :            : 
     562 [ +  - ][ +  - ]:         10 :     GrepMatchDecider myfunctor("We produce");
     563                 :            : 
     564         [ +  - ]:         10 :     Xapian::MSet mset1 = enquire.get_mset(0, 2, 0, NULL, &myfunctor);
     565         [ +  - ]:         10 :     Xapian::MSet mset2 = enquire.get_mset(0, 1000, 0, NULL, &myfunctor);
     566                 :            : 
     567                 :            :     // mset2 should contain all the hits, so the statistics should be exact.
     568 [ +  - ][ +  - ]:          5 :     TEST_EQUAL(mset2.get_matches_estimated(), mset2.size());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     569 [ +  - ][ +  - ]:          5 :     TEST_EQUAL(mset2.get_matches_lower_bound(), mset2.get_matches_estimated());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     570 [ +  - ][ +  - ]:          5 :     TEST_EQUAL(mset2.get_matches_estimated(), mset2.get_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     571                 :            : 
     572 [ +  - ][ +  - ]:          5 :     TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     573 [ +  - ][ +  - ]:          5 :     TEST_REL(mset2.get_uncollapsed_matches_estimated(),<=,mset2.get_uncollapsed_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     574                 :            : 
     575                 :            :     // Check that the lower bound in mset1 is not greater than the known
     576                 :            :     // number of hits.  This failed until revision 10811.
     577 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_matches_lower_bound(),<=,mset2.size());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     578                 :            : 
     579                 :            :     // Check that the bounds for mset1 make sense.
     580 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_matches_lower_bound(),<=,mset1.get_matches_estimated());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     581 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_matches_estimated(),<=,mset1.get_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     582 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.size(),<=,mset1.get_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     583                 :            : 
     584 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_uncollapsed_matches_lower_bound(),<=,mset1.get_uncollapsed_matches_estimated());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     585 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_uncollapsed_matches_estimated(),<=,mset1.get_uncollapsed_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     586                 :            : 
     587                 :            :     // The uncollapsed match would match all documents but the one the
     588                 :            :     // matchdecider rejects.
     589 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_uncollapsed_matches_upper_bound(),>=,db.get_doccount() - 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     590 [ +  - ][ +  - ]:          5 :     TEST_REL(mset1.get_uncollapsed_matches_upper_bound(),<=,db.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     591 [ +  - ][ +  - ]:          5 :     TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,db.get_doccount() - 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     592 [ +  - ][ +  - ]:          5 :     TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),<=,db.get_doccount());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     593                 :            : 
     594                 :          5 :     return true;
     595                 :            : }
     596                 :            : 
     597                 :            : // tests that mset iterators on msets compare correctly.
     598                 :          7 : DEFINE_TESTCASE(msetiterator1, backend) {
     599 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     600 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     601         [ +  - ]:         14 :     Xapian::MSet mymset = enquire.get_mset(0, 2);
     602                 :            : 
     603         [ +  - ]:         14 :     Xapian::MSetIterator j;
     604 [ +  - ][ +  - ]:          7 :     j = mymset.begin();
     605         [ +  - ]:         14 :     Xapian::MSetIterator k = mymset.end();
     606         [ +  - ]:         14 :     Xapian::MSetIterator l(j);
     607         [ +  - ]:         14 :     Xapian::MSetIterator m(k);
     608         [ +  - ]:         14 :     Xapian::MSetIterator n = mymset.begin();
     609         [ +  - ]:         14 :     Xapian::MSetIterator o = mymset.begin();
     610 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     611 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(l, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     612 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     613 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     614 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, j);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     615 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     616                 :            : 
     617         [ +  - ]:          7 :     k = j;
     618 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     619 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, o);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     620         [ +  - ]:          7 :     k++;
     621 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     622 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     623 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     624 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, o);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     625         [ +  - ]:          7 :     o++;
     626 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, o);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     627         [ +  - ]:          7 :     k++;
     628 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     629 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     630 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     631 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(n, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     632                 :            : 
     633         [ +  - ]:          7 :     n = m;
     634 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(n, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     635 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(n, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     636 [ +  - ][ -  + ]:          7 :     TEST_NOT_EQUAL(n, mymset.begin());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     637 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(n, mymset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     638                 :            : 
     639                 :          7 :     return true;
     640                 :            : }
     641                 :            : 
     642                 :            : // tests that mset iterators on empty msets compare equal.
     643                 :          7 : DEFINE_TESTCASE(msetiterator2, backend) {
     644 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     645 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     646         [ +  - ]:         14 :     Xapian::MSet mymset = enquire.get_mset(0, 0);
     647                 :            : 
     648         [ +  - ]:         14 :     Xapian::MSetIterator j = mymset.begin();
     649         [ +  - ]:         14 :     Xapian::MSetIterator k = mymset.end();
     650         [ +  - ]:         14 :     Xapian::MSetIterator l(j);
     651         [ +  - ]:         14 :     Xapian::MSetIterator m(k);
     652 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     653 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(l, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     654 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     655 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     656 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, j);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     657 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     658                 :            : 
     659                 :          7 :     return true;
     660                 :            : }
     661                 :            : 
     662                 :            : // tests that begin().get_document() works when first != 0
     663                 :          7 : DEFINE_TESTCASE(msetiterator3, backend) {
     664 [ +  - ][ +  - ]:          7 :     Xapian::Database mydb(get_database("apitest_simpledata"));
     665         [ +  - ]:         14 :     Xapian::Enquire enquire(mydb);
     666 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     667                 :            : 
     668         [ +  - ]:         14 :     Xapian::MSet mymset = enquire.get_mset(2, 10);
     669                 :            : 
     670 [ +  - ][ -  + ]:          7 :     TEST(!mymset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     671 [ +  - ][ +  - ]:         14 :     Xapian::Document doc(mymset.begin().get_document());
     672 [ +  - ][ -  + ]:          7 :     TEST(!doc.get_data().empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     673                 :            : 
     674                 :          7 :     return true;
     675                 :            : }
     676                 :            : 
     677                 :            : // tests that eset iterators on empty esets compare equal.
     678                 :          7 : DEFINE_TESTCASE(esetiterator1, backend) {
     679 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     680 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     681                 :            : 
     682         [ +  - ]:         14 :     Xapian::MSet mymset = enquire.get_mset(0, 10);
     683 [ +  - ][ -  + ]:          7 :     TEST(mymset.size() >= 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     684                 :            : 
     685         [ +  - ]:         14 :     Xapian::RSet myrset;
     686         [ +  - ]:         14 :     Xapian::MSetIterator i = mymset.begin();
     687 [ +  - ][ +  - ]:          7 :     myrset.add_document(*i);
     688 [ +  - ][ +  - ]:          7 :     myrset.add_document(*(++i));
     689                 :            : 
     690         [ +  - ]:         14 :     Xapian::ESet myeset = enquire.get_eset(2, myrset);
     691         [ +  - ]:         14 :     Xapian::ESetIterator j;
     692 [ +  - ][ +  - ]:          7 :     j = myeset.begin();
     693         [ +  - ]:         14 :     Xapian::ESetIterator k = myeset.end();
     694         [ +  - ]:         14 :     Xapian::ESetIterator l(j);
     695         [ +  - ]:         14 :     Xapian::ESetIterator m(k);
     696         [ +  - ]:         14 :     Xapian::ESetIterator n = myeset.begin();
     697                 :            : 
     698 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     699 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(l, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     700 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     701 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     702 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, j);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     703 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     704                 :            : 
     705         [ +  - ]:          7 :     k = j;
     706 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     707         [ +  - ]:          7 :     k++;
     708 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     709 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     710 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     711         [ +  - ]:          7 :     k++;
     712 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     713 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(k, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     714 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     715 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(n, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     716                 :            : 
     717         [ +  - ]:          7 :     n = m;
     718 [ -  + ][ #  # ]:          7 :     TEST_NOT_EQUAL(n, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     719 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(n, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     720 [ +  - ][ -  + ]:          7 :     TEST_NOT_EQUAL(n, myeset.begin());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     721 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(n, myeset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     722                 :            : 
     723                 :          7 :     return true;
     724                 :            : }
     725                 :            : 
     726                 :            : // tests that eset iterators on empty esets compare equal.
     727                 :          7 : DEFINE_TESTCASE(esetiterator2, backend) {
     728 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     729 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     730                 :            : 
     731         [ +  - ]:         14 :     Xapian::MSet mymset = enquire.get_mset(0, 10);
     732 [ +  - ][ -  + ]:          7 :     TEST(mymset.size() >= 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     733                 :            : 
     734         [ +  - ]:         14 :     Xapian::RSet myrset;
     735         [ +  - ]:         14 :     Xapian::MSetIterator i = mymset.begin();
     736 [ +  - ][ +  - ]:          7 :     myrset.add_document(*i);
     737 [ +  - ][ +  - ]:          7 :     myrset.add_document(*(++i));
     738                 :            : 
     739         [ +  - ]:         14 :     Xapian::ESet myeset = enquire.get_eset(0, myrset);
     740         [ +  - ]:         14 :     Xapian::ESetIterator j = myeset.begin();
     741         [ +  - ]:         14 :     Xapian::ESetIterator k = myeset.end();
     742         [ +  - ]:         14 :     Xapian::ESetIterator l(j);
     743         [ +  - ]:         14 :     Xapian::ESetIterator m(k);
     744 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     745 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(l, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     746 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, m);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     747 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, l);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     748 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, j);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     749 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(k, k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     750                 :            : 
     751                 :          7 :     return true;
     752                 :            : }
     753                 :            : 
     754                 :            : // tests the collapse-on-key
     755                 :          7 : DEFINE_TESTCASE(collapsekey1, backend) {
     756 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     757 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     758                 :            : 
     759         [ +  - ]:         14 :     Xapian::MSet mymset1 = enquire.get_mset(0, 100);
     760         [ +  - ]:          7 :     Xapian::doccount mymsize1 = mymset1.size();
     761                 :            : 
     762         [ +  + ]:         49 :     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
     763         [ +  - ]:         42 :         enquire.set_collapse_key(value_no);
     764         [ +  - ]:         42 :         Xapian::MSet mymset = enquire.get_mset(0, 100);
     765                 :            : 
     766 [ +  - ][ -  + ]:         42 :         TEST_AND_EXPLAIN(mymsize1 > mymset.size(),
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     767                 :            :                          "Had no fewer items when performing collapse: don't know whether it worked.");
     768                 :            : 
     769         [ +  - ]:         84 :         map<string, Xapian::docid> values;
     770         [ +  - ]:         84 :         Xapian::MSetIterator i = mymset.begin();
     771 [ +  - ][ +  + ]:        154 :         for ( ; i != mymset.end(); ++i) {
     772 [ +  - ][ +  - ]:        112 :             string value = i.get_document().get_value(value_no);
     773 [ +  - ][ -  + ]:        112 :             TEST(values[value] == 0 || value.empty());
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     774 [ +  - ][ +  - ]:        112 :             values[value] = *i;
     775                 :        112 :         }
     776                 :         42 :     }
     777                 :            : 
     778                 :          7 :     return true;
     779                 :            : }
     780                 :            : 
     781                 :            : // tests that collapse-on-key modifies the predicted bounds for the number of
     782                 :            : // matches appropriately.
     783                 :          7 : DEFINE_TESTCASE(collapsekey2, backend) {
     784 [ +  - ][ +  - ]:          7 :     SKIP_TEST("Don't have a suitable database currently");
         [ +  - ][ +  - ]
     785                 :            :     // FIXME: this needs an appropriate database creating, but that's quite
     786                 :            :     // subtle to do it seems.
     787                 :            :     Xapian::Enquire enquire(get_database("apitest_simpledata2"));
     788                 :            :     enquire.set_query(Xapian::Query("this"));
     789                 :            : 
     790                 :            :     Xapian::MSet mset1 = enquire.get_mset(0, 1);
     791                 :            : 
     792                 :            :     // Test that if no duplicates are found, then the upper bound remains
     793                 :            :     // unchanged and the lower bound drops.
     794                 :            :     {
     795                 :            :         enquire.set_query(Xapian::Query("this"));
     796                 :            :         Xapian::valueno value_no = 3;
     797                 :            :         enquire.set_collapse_key(value_no);
     798                 :            :         Xapian::MSet mset = enquire.get_mset(0, 1);
     799                 :            : 
     800                 :            :         TEST_REL(mset.get_matches_lower_bound(),<,mset1.get_matches_lower_bound());
     801                 :            :         TEST_EQUAL(mset.get_matches_upper_bound(), mset1.get_matches_upper_bound());
     802                 :            :     }
     803                 :            : 
     804                 :            :     return true;
     805                 :            : }
     806                 :            : 
     807                 :            : // tests that collapse-on-key modifies the predicted bounds for the number of
     808                 :            : // matches appropriately.
     809                 :          7 : DEFINE_TESTCASE(collapsekey3, backend) {
     810 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     811 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     812                 :            : 
     813         [ +  - ]:         14 :     Xapian::MSet mymset1 = enquire.get_mset(0, 3);
     814                 :            : 
     815         [ +  + ]:         49 :     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
     816         [ +  - ]:         42 :         enquire.set_collapse_key(value_no);
     817         [ +  - ]:         42 :         Xapian::MSet mymset = enquire.get_mset(0, 3);
     818                 :            : 
     819 [ +  - ][ +  - ]:         42 :         TEST_AND_EXPLAIN(mymset1.get_matches_lower_bound() > mymset.get_matches_lower_bound(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     820                 :            :                          "Lower bound was not lower when performing collapse: don't know whether it worked.");
     821 [ +  - ][ +  - ]:         42 :         TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() > mymset.get_matches_upper_bound(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     822                 :            :                          "Upper bound was not lower when performing collapse: don't know whether it worked.");
     823                 :            : 
     824         [ +  - ]:         84 :         map<string, Xapian::docid> values;
     825         [ +  - ]:         84 :         Xapian::MSetIterator i = mymset.begin();
     826 [ +  - ][ +  + ]:        140 :         for ( ; i != mymset.end(); ++i) {
     827 [ +  - ][ +  - ]:         98 :             string value = i.get_document().get_value(value_no);
     828 [ +  - ][ -  + ]:         98 :             TEST(values[value] == 0 || value.empty());
         [ #  # ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     829 [ +  - ][ +  - ]:         98 :             values[value] = *i;
     830                 :         98 :         }
     831                 :         42 :     }
     832                 :            : 
     833                 :            :     // Test that if the collapse value is always empty, then the upper bound
     834                 :            :     // remains unchanged, and the lower bound is the same or lower (it can be
     835                 :            :     // lower because the matcher counts the number of documents with empty
     836                 :            :     // collapse keys, but may have rejected a document because its weight is
     837                 :            :     // too low for the proto-MSet before it even looks at its collapse key).
     838                 :            :     {
     839                 :          7 :         Xapian::valueno value_no = 1000;
     840         [ +  - ]:          7 :         enquire.set_collapse_key(value_no);
     841         [ +  - ]:          7 :         Xapian::MSet mymset = enquire.get_mset(0, 3);
     842                 :            : 
     843 [ +  - ][ +  - ]:          7 :         TEST(mymset.get_matches_lower_bound() <= mymset1.get_matches_lower_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     844 [ +  - ][ +  - ]:          7 :         TEST_EQUAL(mymset.get_matches_upper_bound(), mymset1.get_matches_upper_bound());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     845                 :            : 
     846         [ +  - ]:         14 :         map<string, Xapian::docid> values;
     847         [ +  - ]:         14 :         Xapian::MSetIterator i = mymset.begin();
     848 [ +  - ][ +  + ]:         28 :         for ( ; i != mymset.end(); ++i) {
     849 [ +  - ][ +  - ]:         21 :             string value = i.get_document().get_value(value_no);
     850 [ +  - ][ +  + ]:         21 :             TEST(values[value] == 0 || value.empty());
         [ -  + ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     851 [ +  - ][ +  - ]:         21 :             values[value] = *i;
     852                 :         28 :         }
     853                 :            :     }
     854                 :            : 
     855                 :          7 :     return true;
     856                 :            : }
     857                 :            : 
     858                 :            : // tests that collapse-on-key modifies the predicted bounds for the number of
     859                 :            : // matches appropriately even when no results are requested.
     860                 :          7 : DEFINE_TESTCASE(collapsekey4, backend) {
     861 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     862 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
     863                 :            : 
     864         [ +  - ]:         14 :     Xapian::MSet mymset1 = enquire.get_mset(0, 0);
     865                 :            : 
     866         [ +  + ]:         49 :     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
     867         [ +  - ]:         42 :         enquire.set_collapse_key(value_no);
     868         [ +  - ]:         42 :         Xapian::MSet mymset = enquire.get_mset(0, 0);
     869                 :            : 
     870 [ +  - ][ -  + ]:         42 :         TEST_AND_EXPLAIN(mymset.get_matches_lower_bound() == 1,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     871                 :            :                          "Lower bound was not 1 when performing collapse but not asking for any results.");
     872 [ +  - ][ +  - ]:         42 :         TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() == mymset.get_matches_upper_bound(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     873                 :            :                          "Upper bound was changed when performing collapse but not asking for any results.");
     874                 :            : 
     875         [ +  - ]:         84 :         map<string, Xapian::docid> values;
     876         [ +  - ]:         84 :         Xapian::MSetIterator i = mymset.begin();
     877 [ +  - ][ -  + ]:         42 :         for ( ; i != mymset.end(); ++i) {
     878 [ #  # ][ #  # ]:          0 :             string value = i.get_document().get_value(value_no);
     879 [ #  # ][ #  # ]:          0 :             TEST(values[value] == 0 || value.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     880 [ #  # ][ #  # ]:          0 :             values[value] = *i;
     881                 :          0 :         }
     882                 :         42 :     }
     883                 :            : 
     884                 :          7 :     return true;
     885                 :            : }
     886                 :            : 
     887                 :            : // test for keepalives
     888                 :          2 : DEFINE_TESTCASE(keepalive1, remote) {
     889 [ +  - ][ +  - ]:          2 :     Xapian::Database db(get_remote_database("apitest_simpledata", 5000));
     890                 :            : 
     891                 :            :     /* Test that keep-alives work */
     892         [ +  + ]:         22 :     for (int i = 0; i < 10; ++i) {
     893         [ +  - ]:         20 :         sleep(2);
     894         [ +  - ]:         20 :         db.keep_alive();
     895                 :            :     }
     896         [ +  - ]:          4 :     Xapian::Enquire enquire(db);
     897 [ +  - ][ +  - ]:          2 :     enquire.set_query(Xapian::Query("word"));
                 [ +  - ]
     898         [ +  - ]:          2 :     enquire.get_mset(0, 10);
     899                 :            : 
     900                 :            :     /* Test that things break without keepalives */
     901         [ +  - ]:          2 :     sleep(10);
     902 [ +  - ][ +  - ]:          4 :     enquire.set_query(Xapian::Query("word"));
         [ +  - ][ -  + ]
     903                 :            :     /* Currently this can throw NetworkError or NetworkTimeoutError (which is
     904                 :            :      * a subclass of NetworkError).
     905                 :            :      */
     906 [ +  - ][ -  + ]:          4 :     TEST_EXCEPTION_BASE_CLASS(Xapian::NetworkError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     907                 :            :                               enquire.get_mset(0, 10));
     908                 :            : 
     909                 :          2 :     return true;
     910                 :            : }
     911                 :            : 
     912                 :            : // test that iterating through all terms in a database works.
     913                 :          7 : DEFINE_TESTCASE(allterms1, backend) {
     914 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_allterms"));
     915 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator ati = db.allterms_begin();
     916 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     917 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "one");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     918 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(ati.get_termfreq(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     919                 :            : 
     920         [ +  - ]:          7 :     ati++;
     921 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     922         [ +  - ]:          7 :     if (verbose) {
     923 [ +  - ][ +  - ]:          7 :         tout << "*ati = '" << *ati << "'\n";
         [ +  - ][ +  - ]
     924 [ +  - ][ +  - ]:          7 :         tout << "*ati.length = '" << (*ati).length() << "'\n";
         [ +  - ][ +  - ]
     925 [ +  - ][ +  - ]:          7 :         tout << "*ati == \"one\" = " << (*ati == "one") << "\n";
         [ +  - ][ +  - ]
                 [ +  - ]
     926 [ +  - ][ +  - ]:          7 :         tout << "*ati[3] = " << ((*ati)[3]) << "\n";
         [ +  - ][ +  - ]
                 [ +  - ]
     927 [ +  - ][ +  - ]:          7 :         tout << "*ati = '" << *ati << "'\n";
         [ +  - ][ +  - ]
     928                 :            :     }
     929 [ +  - ][ +  - ]:          7 :     TEST(*ati == "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     930 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     931                 :            : 
     932         [ +  - ]:          7 :     ++ati;
     933 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     934 [ +  - ][ +  - ]:          7 :     TEST(*ati == "two");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     935 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     936                 :            : 
     937         [ +  - ]:          7 :     ati++;
     938 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     939                 :            : 
     940                 :          7 :     return true;
     941                 :            : }
     942                 :            : 
     943                 :            : // test that iterating through all terms in two databases works.
     944                 :          7 : DEFINE_TESTCASE(allterms2, backend) {
     945         [ +  - ]:          7 :     Xapian::Database db;
     946 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms"));
                 [ +  - ]
     947 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms2"));
                 [ +  - ]
     948 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator ati = db.allterms_begin();
     949                 :            : 
     950 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     951 [ +  - ][ +  - ]:          7 :     TEST(*ati == "five");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     952 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     953         [ +  - ]:          7 :     ati++;
     954                 :            : 
     955 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     956 [ +  - ][ +  - ]:          7 :     TEST(*ati == "four");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     957 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     958                 :            : 
     959         [ +  - ]:          7 :     ati++;
     960 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     961 [ +  - ][ +  - ]:          7 :     TEST(*ati == "one");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     962 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     963                 :            : 
     964         [ +  - ]:          7 :     ++ati;
     965 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     966 [ +  - ][ +  - ]:          7 :     TEST(*ati == "six");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     967 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     968                 :            : 
     969         [ +  - ]:          7 :     ati++;
     970 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     971 [ +  - ][ +  - ]:          7 :     TEST(*ati == "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     972 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     973                 :            : 
     974         [ +  - ]:          7 :     ati++;
     975 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     976 [ +  - ][ +  - ]:          7 :     TEST(*ati == "two");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     977 [ +  - ][ -  + ]:          7 :     TEST(ati.get_termfreq() == 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     978                 :            : 
     979         [ +  - ]:          7 :     ati++;
     980 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     981                 :            : 
     982                 :          7 :     return true;
     983                 :            : }
     984                 :            : 
     985                 :            : // test that skip_to sets at_end (regression test)
     986                 :          7 : DEFINE_TESTCASE(allterms3, backend) {
     987         [ +  - ]:          7 :     Xapian::Database db;
     988 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms"));
                 [ +  - ]
     989 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator ati = db.allterms_begin();
     990                 :            : 
     991 [ +  - ][ +  - ]:          7 :     ati.skip_to(string("zzzzzz"));
     992 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     993                 :            : 
     994                 :          7 :     return true;
     995                 :            : }
     996                 :            : 
     997                 :            : // test that next ignores extra entries due to long posting lists being
     998                 :            : // chunked (regression test for quartz)
     999                 :          7 : DEFINE_TESTCASE(allterms4, backend) {
    1000                 :            :     // apitest_allterms4 contains 682 documents each containing just the word
    1001                 :            :     // "foo".  682 was the magic number which started to cause Quartz problems.
    1002 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_allterms4");
    1003                 :            : 
    1004 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator i = db.allterms_begin();
    1005 [ +  - ][ -  + ]:          7 :     TEST(i != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1006 [ +  - ][ +  - ]:          7 :     TEST(*i == "foo");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1007 [ +  - ][ -  + ]:          7 :     TEST(i.get_termfreq() == 682);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1008         [ +  - ]:          7 :     ++i;
    1009 [ +  - ][ -  + ]:          7 :     TEST(i == db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1010                 :            : 
    1011                 :          7 :     return true;
    1012                 :            : }
    1013                 :            : 
    1014                 :            : // test that skip_to with an exact match sets the current term (regression test
    1015                 :            : // for quartz)
    1016                 :          7 : DEFINE_TESTCASE(allterms5, backend) {
    1017         [ +  - ]:          7 :     Xapian::Database db;
    1018 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms"));
                 [ +  - ]
    1019 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator ati = db.allterms_begin();
    1020 [ +  - ][ +  - ]:          7 :     ati.skip_to("three");
    1021 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1022 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1023                 :            : 
    1024                 :          7 :     return true;
    1025                 :            : }
    1026                 :            : 
    1027                 :            : // test allterms iterators with prefixes
    1028                 :          7 : DEFINE_TESTCASE(allterms6, backend) {
    1029         [ +  - ]:          7 :     Xapian::Database db;
    1030 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms"));
                 [ +  - ]
    1031 [ +  - ][ +  - ]:          7 :     db.add_database(get_database("apitest_allterms2"));
                 [ +  - ]
    1032                 :            : 
    1033 [ +  - ][ +  - ]:         14 :     Xapian::TermIterator ati = db.allterms_begin("three");
    1034 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("three"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1035 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1036 [ +  - ][ +  - ]:          7 :     ati.skip_to("three");
    1037 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("three"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1038 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1039         [ +  - ]:          7 :     ati++;
    1040 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end("three"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1041                 :            : 
    1042 [ +  - ][ +  - ]:          7 :     ati = db.allterms_begin("thre");
                 [ +  - ]
    1043 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("thre"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1044 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1045 [ +  - ][ +  - ]:          7 :     ati.skip_to("three");
    1046 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("thre"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1047 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "three");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1048         [ +  - ]:          7 :     ati++;
    1049 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end("thre"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1050                 :            : 
    1051 [ +  - ][ +  - ]:          7 :     ati = db.allterms_begin("f");
                 [ +  - ]
    1052 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1053 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "five");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1054 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1055 [ +  - ][ +  - ]:          7 :     ati.skip_to("three");
    1056 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1057                 :            : 
    1058 [ +  - ][ +  - ]:          7 :     ati = db.allterms_begin("f");
                 [ +  - ]
    1059 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1060 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "five");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1061         [ +  - ]:          7 :     ati++;
    1062 [ +  - ][ -  + ]:          7 :     TEST(ati != db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1063 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*ati, "four");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1064         [ +  - ]:          7 :     ati++;
    1065 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end("f"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1066                 :            : 
    1067 [ +  - ][ +  - ]:          7 :     ati = db.allterms_begin("absent");
                 [ +  - ]
    1068 [ +  - ][ -  + ]:          7 :     TEST(ati == db.allterms_end("absent"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1069                 :            : 
    1070                 :          7 :     return true;
    1071                 :            : }
    1072                 :            : 
    1073                 :            : // test that searching for a term with a special characters in it works
    1074                 :          7 : DEFINE_TESTCASE(specialterms1, backend) {
    1075 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_space"));
                 [ +  - ]
    1076         [ +  - ]:         14 :     Xapian::MSet mymset;
    1077                 :            :     Xapian::doccount count;
    1078         [ +  - ]:         14 :     Xapian::MSetIterator m;
    1079 [ +  - ][ +  - ]:         14 :     Xapian::Stem stemmer("english");
    1080                 :            : 
    1081 [ +  - ][ +  - ]:          7 :     enquire.set_query(stemmer("new\nline"));
         [ +  - ][ +  - ]
    1082 [ +  - ][ +  - ]:          7 :     mymset = enquire.get_mset(0, 10);
    1083 [ +  - ][ -  + ]:          7 :     TEST_MSET_SIZE(mymset, 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1084                 :          7 :     count = 0;
    1085 [ +  - ][ +  - ]:         14 :     for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
         [ +  - ][ +  + ]
    1086 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(count, 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1087                 :            : 
    1088         [ +  + ]:         56 :     for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
    1089 [ +  - ][ +  - ]:         49 :         string value = mymset.begin().get_document().get_value(value_no);
                 [ +  - ]
    1090 [ +  - ][ -  + ]:         49 :         TEST_NOT_EQUAL(value, "");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1091         [ +  + ]:         49 :         if (value_no == 0) {
    1092 [ -  + ][ #  # ]:          7 :             TEST(value.size() > 263);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1093 [ +  - ][ -  + ]:          7 :             TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1094         [ +  + ]:       1799 :             for (int k = 0; k < 256; ++k) {
    1095 [ +  - ][ -  + ]:       1792 :                 TEST_EQUAL(static_cast<unsigned char>(value[k + 7]), k);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1096                 :            :             }
    1097                 :            :         }
    1098                 :         49 :     }
    1099                 :            : 
    1100 [ +  - ][ +  - ]:          7 :     enquire.set_query(stemmer(string("big\0zero", 8)));
         [ +  - ][ +  - ]
    1101 [ +  - ][ +  - ]:          7 :     mymset = enquire.get_mset(0, 10);
    1102 [ +  - ][ -  + ]:          7 :     TEST_MSET_SIZE(mymset, 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1103                 :          7 :     count = 0;
    1104 [ +  - ][ +  - ]:         14 :     for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
         [ +  - ][ +  + ]
    1105 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(count, 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1106                 :            : 
    1107                 :          7 :     return true;
    1108                 :            : }
    1109                 :            : 
    1110                 :            : // test that terms with a special characters in appear correctly when iterating
    1111                 :            : // allterms
    1112                 :          7 : DEFINE_TESTCASE(specialterms2, backend) {
    1113 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_space"));
    1114                 :            : 
    1115                 :            :     // Check the terms are all as expected (after stemming) and that allterms
    1116                 :            :     // copes with iterating over them.
    1117                 :         14 :     Xapian::TermIterator t;
    1118 [ +  - ][ +  - ]:          7 :     t = db.allterms_begin();
                 [ +  - ]
    1119 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "back\\slash"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1120 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, string("big\0zero", 8)); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ +  - ]
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1121 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "new\nlin"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1122 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "one\x01on"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1123 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "space man"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1124 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "tab\tbi"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1125 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, "tu\x02tu"); ++t; TEST_EQUAL(t, db.allterms_end());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1126                 :            : 
    1127                 :            :     // Now check that skip_to exactly a term containing a zero byte works.
    1128                 :            :     // This is a regression test for flint and quartz - an Assert() used to
    1129                 :            :     // fire in debug builds (the Assert was wrong - the actual code handled
    1130                 :            :     // this OK).
    1131 [ +  - ][ +  - ]:          7 :     t = db.allterms_begin();
                 [ +  - ]
    1132 [ +  - ][ +  - ]:          7 :     t.skip_to(string("big\0zero", 8));
    1133 [ +  - ][ -  + ]:          7 :     TEST_NOT_EQUAL(t, db.allterms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1134 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*t, string("big\0zero", 8));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1135                 :            : 
    1136                 :          7 :     return true;
    1137                 :            : }
    1138                 :            : 
    1139                 :            : // test that rsets behave correctly with multiDBs
    1140                 :          6 : DEFINE_TESTCASE(rsetmultidb2, backend && !multi) {
    1141 [ +  - ][ +  - ]:          6 :     Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
                 [ +  - ]
    1142 [ +  - ][ +  - ]:         12 :     Xapian::Database mydb2(get_database("apitest_rset"));
    1143 [ +  - ][ +  - ]:          6 :     mydb2.add_database(get_database("apitest_simpledata2"));
                 [ +  - ]
    1144                 :            : 
    1145         [ +  - ]:         12 :     Xapian::Enquire enquire1(mydb1);
    1146         [ +  - ]:         12 :     Xapian::Enquire enquire2(mydb2);
    1147                 :            : 
    1148 [ +  - ][ +  - ]:         12 :     Xapian::Query myquery = query("is");
    1149                 :            : 
    1150         [ +  - ]:          6 :     enquire1.set_query(myquery);
    1151         [ +  - ]:          6 :     enquire2.set_query(myquery);
    1152                 :            : 
    1153         [ +  - ]:         12 :     Xapian::RSet myrset1;
    1154         [ +  - ]:         12 :     Xapian::RSet myrset2;
    1155         [ +  - ]:          6 :     myrset1.add_document(4);
    1156         [ +  - ]:          6 :     myrset2.add_document(2);
    1157                 :            : 
    1158         [ +  - ]:         12 :     Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
    1159         [ +  - ]:         12 :     Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
    1160         [ +  - ]:         12 :     Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
    1161         [ +  - ]:         12 :     Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
    1162                 :            : 
    1163         [ +  - ]:          6 :     mset_expect_order(mymset1a, 4, 3);
    1164         [ +  - ]:          6 :     mset_expect_order(mymset1b, 4, 3);
    1165         [ +  - ]:          6 :     mset_expect_order(mymset2a, 2, 5);
    1166         [ +  - ]:          6 :     mset_expect_order(mymset2b, 2, 5);
    1167                 :            : 
    1168 [ +  - ][ -  + ]:          6 :     TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1169 [ +  - ][ -  + ]:          6 :     TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1170 [ +  - ][ -  + ]:          6 :     TEST_NOT_EQUAL(mymset1a, mymset1b);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1171 [ +  - ][ -  + ]:          6 :     TEST_NOT_EQUAL(mymset2a, mymset2b);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1172                 :            : 
    1173                 :          6 :     return true;
    1174                 :            : }
    1175                 :            : 
    1176                 :            : // tests an expand across multiple databases
    1177                 :          6 : DEFINE_TESTCASE(multiexpand1, backend && !multi) {
    1178 [ +  - ][ +  - ]:          6 :     Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
                 [ +  - ]
    1179         [ +  - ]:         12 :     Xapian::Enquire enquire1(mydb1);
    1180                 :            : 
    1181 [ +  - ][ +  - ]:         12 :     Xapian::Database mydb2(get_database("apitest_simpledata"));
    1182 [ +  - ][ +  - ]:          6 :     mydb2.add_database(get_database("apitest_simpledata2"));
                 [ +  - ]
    1183         [ +  - ]:         12 :     Xapian::Enquire enquire2(mydb2);
    1184                 :            : 
    1185                 :            :     // make simple equivalent rsets, with a document from each database in each.
    1186         [ +  - ]:         12 :     Xapian::RSet rset1;
    1187         [ +  - ]:         12 :     Xapian::RSet rset2;
    1188         [ +  - ]:          6 :     rset1.add_document(1);
    1189         [ +  - ]:          6 :     rset1.add_document(7);
    1190         [ +  - ]:          6 :     rset2.add_document(1);
    1191         [ +  - ]:          6 :     rset2.add_document(2);
    1192                 :            : 
    1193                 :            :     // Retrieve all the ESet results in each of the three setups:
    1194                 :            : 
    1195                 :            :     // This is the single database one.
    1196         [ +  - ]:         12 :     Xapian::ESet eset1 = enquire1.get_eset(1000, rset1);
    1197                 :            : 
    1198                 :            :     // This is the multi database with approximation
    1199         [ +  - ]:         12 :     Xapian::ESet eset2 = enquire2.get_eset(1000, rset2);
    1200                 :            : 
    1201                 :            :     // This is the multi database without approximation
    1202         [ +  - ]:         12 :     Xapian::ESet eset3 = enquire2.get_eset(1000, rset2, Xapian::Enquire::USE_EXACT_TERMFREQ);
    1203                 :            : 
    1204 [ +  - ][ +  - ]:          6 :     TEST_EQUAL(eset1.size(), eset3.size());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1205                 :            : 
    1206         [ +  - ]:         12 :     Xapian::ESetIterator i = eset1.begin();
    1207         [ +  - ]:         12 :     Xapian::ESetIterator j = eset3.begin();
    1208 [ +  - ][ +  + ]:        222 :     while (i != eset1.end() && j != eset3.end()) {
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
           [ +  +  #  #  
                   #  # ]
    1209 [ +  - ][ +  - ]:        216 :         TEST_EQUAL(*i, *j);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1210 [ +  - ][ +  - ]:        216 :         TEST_EQUAL(i.get_weight(), j.get_weight());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1211                 :        216 :         ++i;
    1212                 :        216 :         ++j;
    1213                 :            :     }
    1214 [ +  - ][ -  + ]:          6 :     TEST(i == eset1.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1215 [ +  - ][ -  + ]:          6 :     TEST(j == eset3.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1216                 :            : 
    1217                 :          6 :     bool eset1_eq_eset2 = true;
    1218 [ +  - ][ +  - ]:          6 :     i = eset1.begin();
    1219 [ +  - ][ +  - ]:          6 :     j = eset2.begin();
    1220 [ +  - ][ +  - ]:          6 :     while (i != eset1.end() && j != eset2.end()) {
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
           [ +  -  #  #  
                   #  # ]
    1221 [ +  - ][ +  - ]:          6 :         if (i.get_weight() != j.get_weight()) {
                 [ +  - ]
    1222                 :          6 :             eset1_eq_eset2 = false;
    1223                 :          6 :             break;
    1224                 :            :         }
    1225                 :          0 :         ++i;
    1226                 :          0 :         ++j;
    1227                 :            :     }
    1228 [ -  + ][ #  # ]:          6 :     TEST(!eset1_eq_eset2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1229                 :            : 
    1230                 :          6 :     return true;
    1231                 :            : }
    1232                 :            : 
    1233                 :            : // tests that opening a non-existent postlist returns an empty list
    1234                 :          7 : DEFINE_TESTCASE(postlist1, backend) {
    1235 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
    1236                 :            : 
    1237 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.postlist_begin("rosebud"), db.postlist_end("rosebud"));
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1238                 :            : 
    1239         [ +  - ]:         14 :     string s = "let_us_see_if_we_can_break_it_with_a_really_really_long_term.";
    1240         [ +  + ]:         63 :     for (int i = 0; i < 8; ++i) {
    1241         [ +  - ]:         56 :         s += s;
    1242 [ +  - ][ -  + ]:         56 :         TEST_EQUAL(db.postlist_begin(s), db.postlist_end(s));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1243                 :            :     }
    1244                 :            : 
    1245                 :            :     // A regression test (no, really!)
    1246 [ +  - ][ +  - ]:          7 :     TEST_NOT_EQUAL(db.postlist_begin("a"), db.postlist_end("a"));
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1247                 :            : 
    1248                 :          7 :     return true;
    1249                 :            : }
    1250                 :            : 
    1251                 :            : // tests that a Xapian::PostingIterator works as an STL iterator
    1252                 :          7 : DEFINE_TESTCASE(postlist2, backend) {
    1253 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
    1254                 :         14 :     Xapian::PostingIterator p;
    1255 [ +  - ][ +  - ]:          7 :     p = db.postlist_begin("this");
                 [ +  - ]
    1256         [ +  - ]:         14 :     Xapian::PostingIterator pend = db.postlist_end("this");
    1257                 :            : 
    1258 [ +  - ][ +  - ]:          7 :     TEST(p.get_description() != "PostingIterator()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1259                 :            : 
    1260                 :            :     // test operator= creates a copy which compares equal
    1261         [ +  - ]:         14 :     Xapian::PostingIterator p_copy = p;
    1262 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(p, p_copy);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1263                 :            : 
    1264 [ +  - ][ +  - ]:          7 :     TEST(p_copy.get_description() != "PostingIterator()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1265                 :            : 
    1266                 :            :     // test copy constructor creates a copy which compares equal
    1267         [ +  - ]:         14 :     Xapian::PostingIterator p_clone(p);
    1268 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(p, p_clone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1269                 :            : 
    1270 [ +  - ][ +  - ]:          7 :     TEST(p_clone.get_description() != "PostingIterator()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1271                 :            : 
    1272 [ +  - ][ +  - ]:         14 :     vector<Xapian::docid> v(p, pend);
                 [ +  - ]
    1273                 :            : 
    1274 [ +  - ][ +  - ]:          7 :     p = db.postlist_begin("this");
                 [ +  - ]
    1275 [ +  - ][ +  - ]:          7 :     pend = db.postlist_end("this");
    1276                 :          7 :     vector<Xapian::docid>::const_iterator i;
    1277         [ +  + ]:         49 :     for (i = v.begin(); i != v.end(); ++i) {
    1278 [ -  + ][ #  # ]:         42 :         TEST_NOT_EQUAL(p, pend);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1279 [ +  - ][ -  + ]:         42 :         TEST_EQUAL(*i, *p);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1280         [ +  - ]:         42 :         p++;
    1281                 :            :     }
    1282 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(p, pend);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1283                 :            : 
    1284 [ +  - ][ +  - ]:          7 :     TEST_STRINGS_EQUAL(p.get_description(), "PostingIterator()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1285 [ +  - ][ +  - ]:          7 :     TEST_STRINGS_EQUAL(pend.get_description(), "PostingIterator()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1286                 :            : 
    1287                 :          7 :     return true;
    1288                 :            : }
    1289                 :            : 
    1290                 :            : // tests that a Xapian::PostingIterator still works when the DB is deleted
    1291                 :          7 : DEFINE_TESTCASE(postlist3, backend) {
    1292                 :          7 :     Xapian::PostingIterator u;
    1293                 :            :     {
    1294 [ +  - ][ +  - ]:          7 :         Xapian::Database db_temp(get_database("apitest_simpledata"));
    1295 [ +  - ][ +  - ]:          7 :         u = db_temp.postlist_begin("this");
                 [ +  - ]
    1296                 :            :     }
    1297                 :            : 
    1298 [ +  - ][ +  - ]:         14 :     Xapian::Database db(get_database("apitest_simpledata"));
    1299 [ +  - ][ +  - ]:         14 :     Xapian::PostingIterator p = db.postlist_begin("this");
    1300         [ +  - ]:         14 :     Xapian::PostingIterator pend = db.postlist_end("this");
    1301                 :            : 
    1302         [ +  + ]:         49 :     while (p != pend) {
    1303 [ +  - ][ +  - ]:         42 :         TEST_EQUAL(*p, *u);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1304         [ +  - ]:         42 :         p++;
    1305         [ +  - ]:         42 :         u++;
    1306                 :            :     }
    1307                 :          7 :     return true;
    1308                 :            : }
    1309                 :            : 
    1310                 :            : // tests skip_to
    1311                 :          7 : DEFINE_TESTCASE(postlist4, backend) {
    1312 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
    1313 [ +  - ][ +  - ]:         14 :     Xapian::PostingIterator i = db.postlist_begin("this");
    1314         [ +  - ]:          7 :     i.skip_to(1);
    1315         [ +  - ]:          7 :     i.skip_to(999999999);
    1316 [ +  - ][ -  + ]:          7 :     TEST(i == db.postlist_end("this"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1317                 :          7 :     return true;
    1318                 :            : }
    1319                 :            : 
    1320                 :            : // tests long postlists
    1321                 :          7 : DEFINE_TESTCASE(postlist5, backend) {
    1322 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_manydocs"));
    1323 [ +  - ][ +  - ]:          7 :     TEST_EQUAL_DOUBLE(db.get_avlength(), 4);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1324 [ +  - ][ +  - ]:         14 :     Xapian::PostingIterator i = db.postlist_begin("this");
    1325                 :          7 :     unsigned int j = 1;
    1326 [ +  - ][ +  + ]:       3591 :     while (i != db.postlist_end("this")) {
    1327 [ +  - ][ -  + ]:       3584 :         TEST_EQUAL(*i, j);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1328         [ +  - ]:       3584 :         i++;
    1329                 :       3584 :         j++;
    1330                 :            :     }
    1331 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(j, 513);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1332                 :          7 :     return true;
    1333                 :            : }
    1334                 :            : 
    1335                 :            : // tests document length in postlists
    1336                 :          7 : DEFINE_TESTCASE(postlist6, backend) {
    1337 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
    1338 [ +  - ][ +  - ]:         14 :     Xapian::PostingIterator i = db.postlist_begin("this");
    1339 [ +  - ][ -  + ]:          7 :     TEST(i != db.postlist_end("this"));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1340 [ +  - ][ +  + ]:         49 :     while (i != db.postlist_end("this")) {
    1341 [ +  - ][ +  - ]:         42 :         TEST_EQUAL(i.get_doclength(), db.get_doclength(*i));
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1342 [ +  - ][ +  - ]:         42 :         TEST_EQUAL(i.get_unique_terms(), db.get_unique_terms(*i));
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1343 [ +  - ][ +  - ]:         42 :         TEST_REL(i.get_wdf(),<=,i.get_doclength());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1344 [ +  - ][ -  + ]:         42 :         TEST_REL(1,<=,i.get_unique_terms());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1345                 :            :         // The next two aren't necessarily true if there are terms with wdf=0
    1346                 :            :         // in the document, but that isn't the case here.
    1347 [ +  - ][ +  - ]:         42 :         TEST_REL(i.get_unique_terms(),<=,i.get_doclength());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1348 [ +  - ][ +  - ]:         42 :         TEST_REL(i.get_wdf() + i.get_unique_terms() - 1,<=,i.get_doclength());
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1349         [ +  - ]:         42 :         ++i;
    1350                 :            :     }
    1351                 :          7 :     return true;
    1352                 :            : }
    1353                 :            : 
    1354                 :            : // tests collection frequency
    1355                 :          7 : DEFINE_TESTCASE(collfreq1, backend) {
    1356 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_simpledata"));
    1357                 :            : 
    1358 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_collection_freq("this"), 11);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1359 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_collection_freq("first"), 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1360 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_collection_freq("last"), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1361 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db.get_collection_freq("word"), 9);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1362                 :            : 
    1363 [ +  - ][ +  - ]:         14 :     Xapian::Database db1(get_database("apitest_simpledata", "apitest_simpledata2"));
                 [ +  - ]
    1364 [ +  - ][ +  - ]:         14 :     Xapian::Database db2(get_database("apitest_simpledata"));
    1365 [ +  - ][ +  - ]:          7 :     db2.add_database(get_database("apitest_simpledata2"));
                 [ +  - ]
    1366                 :            : 
    1367 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db1.get_collection_freq("this"), 15);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1368 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db1.get_collection_freq("first"), 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1369 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db1.get_collection_freq("last"), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1370 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db1.get_collection_freq("word"), 11);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1371 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db2.get_collection_freq("this"), 15);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1372 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db2.get_collection_freq("first"), 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1373 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db2.get_collection_freq("last"), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1374 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(db2.get_collection_freq("word"), 11);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1375                 :            : 
    1376                 :          7 :     return true;
    1377                 :            : }
    1378                 :            : 
    1379                 :            : // Regression test for split msets being incorrect when sorting
    1380                 :          7 : DEFINE_TESTCASE(sortvalue1, backend) {
    1381 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
    1382 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("this"));
                 [ +  - ]
    1383                 :            : 
    1384         [ +  + ]:         21 :     for (int pass = 1; pass <= 2; ++pass) {
    1385         [ +  + ]:         98 :         for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
    1386 [ +  - ][ +  - ]:         84 :             tout << "Sorting on value " << value_no << endl;
                 [ +  - ]
    1387         [ +  - ]:         84 :             enquire.set_sort_by_value(value_no, true);
    1388         [ +  - ]:         84 :             Xapian::MSet allbset = enquire.get_mset(0, 100);
    1389         [ +  - ]:        168 :             Xapian::MSet partbset1 = enquire.get_mset(0, 3);
    1390         [ +  - ]:        168 :             Xapian::MSet partbset2 = enquire.get_mset(3, 97);
    1391 [ +  - ][ +  - ]:         84 :             TEST_EQUAL(allbset.size(), partbset1.size() + partbset2.size());
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1392                 :            : 
    1393                 :         84 :             bool ok = true;
    1394                 :         84 :             int n = 0;
    1395 [ +  - ][ +  - ]:        168 :             Xapian::MSetIterator i, j;
    1396 [ +  - ][ +  - ]:         84 :             j = allbset.begin();
    1397 [ +  - ][ +  - ]:        336 :             for (i = partbset1.begin(); i != partbset1.end(); ++i) {
         [ +  - ][ +  + ]
    1398 [ +  - ][ +  - ]:        252 :                 tout << "Entry " << n << ": " << *i << " | " << *j << endl;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1399 [ +  - ][ -  + ]:        252 :                 TEST(j != allbset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1400 [ +  - ][ +  - ]:        252 :                 if (*i != *j) ok = false;
                 [ -  + ]
    1401                 :        252 :                 ++j;
    1402                 :        252 :                 ++n;
    1403                 :            :             }
    1404         [ +  - ]:         84 :             tout << "===\n";
    1405 [ +  - ][ +  - ]:        336 :             for (i = partbset2.begin(); i != partbset2.end(); ++i) {
         [ +  - ][ +  + ]
    1406 [ +  - ][ +  - ]:        252 :                 tout << "Entry " << n << ": " << *i << " | " << *j << endl;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
    1407 [ +  - ][ -  + ]:        252 :                 TEST(j != allbset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1408 [ +  - ][ +  - ]:        252 :                 if (*i != *j) ok = false;
                 [ -  + ]
    1409                 :        252 :                 ++j;
    1410                 :        252 :                 ++n;
    1411                 :            :             }
    1412 [ +  - ][ -  + ]:         84 :             TEST(j == allbset.end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1413         [ -  + ]:         84 :             if (!ok)
    1414 [ #  # ][ #  # ]:          0 :                 FAIL_TEST("Split msets aren't consistent with unsplit");
         [ #  # ][ #  # ]
    1415                 :         84 :         }
    1416         [ +  - ]:         14 :         enquire.set_docid_order(Xapian::Enquire::DESCENDING);
    1417                 :            :     }
    1418                 :            : 
    1419                 :          7 :     return true;
    1420                 :            : }
    1421                 :            : 
    1422                 :            : // consistency check match - vary mset size and check results agree.
    1423                 :            : // consistency1 will run on the remote backend, but it's particularly slow
    1424                 :            : // with that, and testing it there doesn't actually improve the test
    1425                 :            : // coverage really.
    1426                 :          5 : DEFINE_TESTCASE(consistency1, backend && !remote) {
    1427 [ +  - ][ +  - ]:          5 :     Xapian::Database db(get_database("etext"));
    1428         [ +  - ]:         10 :     Xapian::Enquire enquire(db);
    1429 [ +  - ][ +  - ]:          5 :     enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, Xapian::Query("the"), Xapian::Query("sky")));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
    1430                 :          5 :     Xapian::doccount lots = 214;
    1431         [ +  - ]:         10 :     Xapian::MSet bigmset = enquire.get_mset(0, lots);
    1432 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(bigmset.size(), lots);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1433                 :            :     try {
    1434         [ +  + ]:       1075 :         for (Xapian::doccount start = 0; start < lots; ++start) {
    1435         [ +  + ]:     116095 :             for (Xapian::doccount size = 0; size < lots - start; ++size) {
    1436         [ +  - ]:     115025 :                 Xapian::MSet mset = enquire.get_mset(start, size);
    1437 [ +  - ][ +  + ]:     115025 :                 if (mset.size()) {
    1438 [ +  - ][ +  - ]:     113955 :                     TEST_EQUAL(start + mset.size(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1439                 :            :                                min(start + size, bigmset.size()));
    1440         [ -  + ]:       1070 :                 } else if (size) {
    1441                 :            : //              tout << start << mset.size() << bigmset.size() << endl;
    1442 [ #  # ][ #  # ]:          0 :                     TEST(start >= bigmset.size());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1443                 :            :                 }
    1444 [ +  - ][ +  + ]:    8281800 :                 for (Xapian::doccount i = 0; i < mset.size(); ++i) {
    1445 [ +  - ][ +  - ]:    8166775 :                     TEST_EQUAL(*mset[i], *bigmset[start + i]);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1446 [ +  - ][ +  - ]:    8166775 :                     TEST_EQUAL_DOUBLE(mset[i].get_weight(),
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1447                 :            :                                       bigmset[start + i].get_weight());
    1448                 :            :                 }
    1449                 :     115025 :             }
    1450                 :            :         }
    1451         [ #  # ]:          0 :     } catch (const Xapian::NetworkTimeoutError &) {
    1452                 :            :         // consistency1 is a long test - may timeout with the remote backend...
    1453   [ #  #  #  #  :          0 :         SKIP_TEST("Test taking too long");
             #  #  #  # ]
    1454                 :            :     }
    1455                 :          5 :     return true;
    1456                 :            : }
    1457                 :            : 
    1458                 :            : // tests that specifying a nonexistent input file throws an exception.
    1459                 :          1 : DEFINE_TESTCASE(glassdatabasenotfounderror1, glass) {
    1460                 :            : #ifdef XAPIAN_HAS_GLASS_BACKEND
    1461                 :          1 :     mkdir(".glass", 0755);
    1462                 :            : 
    1463 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::DatabaseNotFoundError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1464                 :            :             Xapian::Database(".glass/nosuchdirectory",
    1465                 :            :                 Xapian::DB_BACKEND_GLASS));
    1466 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseNotFoundError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1467                 :            :             Xapian::WritableDatabase(".glass/nosuchdirectory",
    1468                 :            :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_GLASS));
    1469                 :            : 
    1470                 :          1 :     mkdir(".glass/emptydirectory", 0700);
    1471 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseNotFoundError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1472                 :            :             Xapian::Database(".glass/emptydirectory",
    1473                 :            :                 Xapian::DB_BACKEND_GLASS));
    1474                 :            : 
    1475 [ +  - ][ +  - ]:          1 :     touch(".glass/somefile");
    1476 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::DatabaseNotFoundError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
    1477                 :            :             Xapian::Database(".glass/somefile",
    1478                 :            :                 Xapian::DB_BACKEND_GLASS));
    1479 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseNotFoundError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1480                 :            :             Xapian::WritableDatabase(".glass/somefile",
    1481                 :            :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_GLASS));
    1482 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseCreateError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1483                 :            :             Xapian::WritableDatabase(".glass/somefile",
    1484                 :            :                 Xapian::DB_CREATE|Xapian::DB_BACKEND_GLASS));
    1485 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseCreateError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1486                 :            :             Xapian::WritableDatabase(".glass/somefile",
    1487                 :            :                 Xapian::DB_CREATE_OR_OPEN|Xapian::DB_BACKEND_GLASS));
    1488 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::DatabaseCreateError,
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  +  - ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
    1489                 :            :             Xapian::WritableDatabase(".glass/somefile",
    1490                 :            :                 Xapian::DB_CREATE_OR_OVERWRITE|Xapian::DB_BACKEND_GLASS));
    1491                 :            : #endif
    1492                 :            : 
    1493                 :          1 :     return true;
    1494                 :            : }
    1495                 :            : 
    1496                 :            : /// Test opening of a glass database
    1497                 :          1 : DEFINE_TESTCASE(glassdatabaseopen1, glass) {
    1498                 :            : #ifdef XAPIAN_HAS_GLASS_BACKEND
    1499         [ +  - ]:          1 :     const string dbdir = ".glass/test_glassdatabaseopen1";
    1500                 :          1 :     mkdir(".glass", 0755);
    1501                 :            : 
    1502                 :            :     {
    1503         [ +  - ]:          1 :         rm_rf(dbdir);
    1504                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1505         [ +  - ]:          1 :                 Xapian::DB_CREATE|Xapian::DB_BACKEND_GLASS);
    1506 [ +  - ][ -  + ]:          1 :         TEST_EXCEPTION(Xapian::DatabaseLockError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
    1507                 :            :             Xapian::WritableDatabase(dbdir,
    1508                 :            :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_GLASS));
    1509         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1510                 :            :     }
    1511                 :            : 
    1512                 :            :     {
    1513         [ +  - ]:          1 :         rm_rf(dbdir);
    1514                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1515         [ +  - ]:          1 :                 Xapian::DB_CREATE_OR_OPEN|Xapian::DB_BACKEND_GLASS);
    1516 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::DatabaseLockError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
    1517                 :            :             Xapian::WritableDatabase(dbdir,
    1518                 :            :                 Xapian::DB_CREATE_OR_OVERWRITE|Xapian::DB_BACKEND_GLASS));
    1519         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1520                 :            :     }
    1521                 :            : 
    1522                 :            :     {
    1523         [ +  - ]:          1 :         rm_rf(dbdir);
    1524                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1525         [ +  - ]:          1 :                 Xapian::DB_CREATE_OR_OVERWRITE|Xapian::DB_BACKEND_GLASS);
    1526 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::DatabaseLockError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
    1527                 :            :             Xapian::WritableDatabase(dbdir,
    1528                 :            :                 Xapian::DB_CREATE_OR_OPEN|Xapian::DB_BACKEND_GLASS));
    1529         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1530                 :            :     }
    1531                 :            : 
    1532                 :            :     {
    1533 [ +  - ][ -  +  :          1 :         TEST_EXCEPTION(Xapian::DatabaseCreateError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
    1534                 :            :             Xapian::WritableDatabase(dbdir,
    1535                 :            :                 Xapian::DB_CREATE|Xapian::DB_BACKEND_GLASS));
    1536                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1537         [ +  - ]:          1 :                 Xapian::DB_CREATE_OR_OVERWRITE|Xapian::DB_BACKEND_GLASS);
    1538         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1539                 :            :     }
    1540                 :            : 
    1541                 :            :     {
    1542                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1543         [ +  - ]:          1 :                 Xapian::DB_CREATE_OR_OPEN|Xapian::DB_BACKEND_GLASS);
    1544         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1545                 :            :     }
    1546                 :            : 
    1547                 :            :     {
    1548                 :            :         Xapian::WritableDatabase wdb(dbdir,
    1549         [ +  - ]:          1 :                 Xapian::DB_OPEN|Xapian::DB_BACKEND_GLASS);
    1550         [ +  - ]:          1 :         Xapian::Database(dbdir, Xapian::DB_BACKEND_GLASS);
    1551                 :            :     }
    1552                 :            : #endif
    1553                 :            : 
    1554                 :          1 :     return true;
    1555                 :            : }
    1556                 :            : 
    1557                 :            : // feature test for Enquire:
    1558                 :            : // set_sort_by_value
    1559                 :            : // set_sort_by_value_then_relevance
    1560                 :            : // set_sort_by_relevance_then_value
    1561                 :            : // Prior to 1.2.17 and 1.3.2, order8 and order9 were swapped, and
    1562                 :            : // set_sort_by_relevance_then_value was buggy, so this testcase now serves as
    1563                 :            : // a regression test for that bug.
    1564                 :          7 : DEFINE_TESTCASE(sortrel1, backend) {
    1565 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_sortrel"));
                 [ +  - ]
    1566         [ +  - ]:          7 :     enquire.set_sort_by_value(1, true);
    1567 [ +  - ][ +  - ]:          7 :     enquire.set_query(Xapian::Query("woman"));
                 [ +  - ]
    1568                 :            : 
    1569                 :            :     static const Xapian::docid order1[] = { 1,2,3,4,5,6,7,8,9 };
    1570                 :            :     static const Xapian::docid order2[] = { 2,1,3,6,5,4,7,9,8 };
    1571                 :            :     static const Xapian::docid order3[] = { 3,2,1,6,5,4,9,8,7 };
    1572                 :            :     static const Xapian::docid order4[] = { 7,8,9,4,5,6,1,2,3 };
    1573                 :            :     static const Xapian::docid order5[] = { 9,8,7,6,5,4,3,2,1 };
    1574                 :            :     static const Xapian::docid order6[] = { 7,9,8,6,5,4,2,1,3 };
    1575                 :            :     static const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 };
    1576                 :            :     static const Xapian::docid order8[] = { 2,6,7,1,5,9,3,4,8 };
    1577                 :            :     static const Xapian::docid order9[] = { 7,6,2,9,5,1,8,4,3 };
    1578                 :            : 
    1579         [ +  - ]:         14 :     Xapian::MSet mset;
    1580                 :            :     size_t i;
    1581                 :            : 
    1582 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1583 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1584         [ +  + ]:         70 :     for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
    1585 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order1[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1586                 :            :     }
    1587                 :            : 
    1588         [ +  - ]:          7 :     enquire.set_sort_by_value_then_relevance(1, true);
    1589                 :            : 
    1590 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1591 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1592         [ +  + ]:         70 :     for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
    1593 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order2[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1594                 :            :     }
    1595                 :            : 
    1596         [ +  - ]:          7 :     enquire.set_sort_by_value(1, true);
    1597                 :            : 
    1598 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1599 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1600         [ +  + ]:         70 :     for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
    1601 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order1[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1602                 :            :     }
    1603                 :            : 
    1604         [ +  - ]:          7 :     enquire.set_sort_by_value_then_relevance(1, true);
    1605         [ +  - ]:          7 :     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
    1606                 :            : 
    1607 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1608 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1609         [ +  + ]:         70 :     for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
    1610 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order2[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1611                 :            :     }
    1612                 :            : 
    1613         [ +  - ]:          7 :     enquire.set_sort_by_value(1, true);
    1614         [ +  - ]:          7 :     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
    1615                 :            : 
    1616 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1617 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order3) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1618         [ +  + ]:         70 :     for (i = 0; i < sizeof(order3) / sizeof(Xapian::docid); ++i) {
    1619 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order3[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1620                 :            :     }
    1621                 :            : 
    1622         [ +  - ]:          7 :     enquire.set_sort_by_value(1, false);
    1623         [ +  - ]:          7 :     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
    1624 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1625 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order4) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1626         [ +  + ]:         70 :     for (i = 0; i < sizeof(order4) / sizeof(Xapian::docid); ++i) {
    1627 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order4[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1628                 :            :     }
    1629                 :            : 
    1630         [ +  - ]:          7 :     enquire.set_sort_by_value(1, false);
    1631         [ +  - ]:          7 :     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
    1632 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1633 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order5) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1634         [ +  + ]:         70 :     for (i = 0; i < sizeof(order5) / sizeof(Xapian::docid); ++i) {
    1635 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order5[i]);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1636                 :            :     }
    1637                 :            : 
    1638         [ +  - ]:          7 :     enquire.set_sort_by_value_then_relevance(1, false);
    1639         [ +  - ]:          7 :     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
    1640 [ +  - ][ +  - ]:          7 :     mset = enquire.get_mset(0, 10);
    1641 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), sizeof(order6) / sizeof(Xapian::docid));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1642         [ +  + ]:         70 :     for (i = 0; i < sizeof(order6) / sizeof(Xapian::docid); ++i) {
    1643 [ +  - ][ +  - ]:         63 :         TEST_EQUAL(*mset[i], order6[i]);
         [ -  + ][ #  # ]
         [