LCOV - code coverage report
Current view: top level - home/olly/git/atia-xapian/xapian-core/tests - api_backend.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 434 447 97.1 %
Date: 2011-08-21 Functions: 32 34 94.1 %
Branches: 146 374 39.0 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_backend.cc
       2                 :            :  * @brief Backend-related tests.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2008,2009,2010,2011 Olly Betts
       5                 :            :  * Copyright (C) 2010 Richard Boulton
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or
       8                 :            :  * modify it under the terms of the GNU General Public License as
       9                 :            :  * published by the Free Software Foundation; either version 2 of the
      10                 :            :  * License, or (at your option) any later version.
      11                 :            :  *
      12                 :            :  * This program is distributed in the hope that it will be useful,
      13                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15                 :            :  * GNU General Public License for more details.
      16                 :            :  *
      17                 :            :  * You should have received a copy of the GNU General Public License
      18                 :            :  * along with this program; if not, write to the Free Software
      19                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include "api_backend.h"
      26                 :            : 
      27                 :            : #define XAPIAN_DEPRECATED(X) X
      28                 :            : #include <xapian.h>
      29                 :            : 
      30                 :            : #include "str.h"
      31                 :            : #include "testsuite.h"
      32                 :            : #include "testutils.h"
      33                 :            : #include "utils.h"
      34                 :            : 
      35                 :            : #include "apitest.h"
      36                 :            : 
      37                 :            : #include "safeunistd.h"
      38                 :            : 
      39                 :            : using namespace std;
      40                 :            : 
      41                 :            : /// Regression test - lockfile should honour umask, was only user-readable.
      42                 :          3 : DEFINE_TESTCASE(lockfileumask1, brass || chert || flint) {
      43                 :            : #if !defined __WIN32__ && !defined __CYGWIN__ && !defined __EMX__
      44                 :          3 :     mode_t old_umask = umask(022);
      45                 :            :     try {
      46                 :          3 :         Xapian::WritableDatabase db = get_named_writable_database("lockfileumask1");
      47                 :            : 
      48                 :          3 :         string path = get_named_writable_database_path("lockfileumask1");
      49                 :          3 :         path += "/flintlock";
      50                 :            : 
      51                 :            :         struct stat statbuf;
      52   [ -  +  #  # ]:          3 :         TEST(stat(path, &statbuf) == 0);
      53 [ -  + ][ #  # ]:          3 :         TEST_EQUAL(statbuf.st_mode & 0777, 0644);
      54                 :          0 :     } catch (...) {
      55                 :          0 :         umask(old_umask);
      56                 :          0 :         throw;
      57                 :            :     }
      58                 :            : 
      59                 :          3 :     umask(old_umask);
      60                 :            : #endif
      61                 :            : 
      62                 :          3 :     return true;
      63                 :            : }
      64                 :            : 
      65                 :            : /// Check that the backend handles total document length > 0xffffffff.
      66                 :         10 : DEFINE_TESTCASE(totaldoclen1, writable) {
      67                 :         10 :     Xapian::WritableDatabase db = get_writable_database();
      68                 :         10 :     Xapian::Document doc;
      69                 :         10 :     doc.add_posting("foo", 1, 2000000000);
      70                 :         10 :     db.add_document(doc);
      71                 :         10 :     db.add_document(doc);
      72   [ -  +  #  # ]:         10 :     TEST_EQUAL(db.get_avlength(), 2000000000);
      73                 :         10 :     db.commit();
      74   [ -  +  #  # ]:         10 :     TEST_EQUAL(db.get_avlength(), 2000000000);
      75         [ +  + ]:         10 :     if (get_dbtype() != "inmemory") {
      76                 :            :         // InMemory doesn't support get_writable_database_as_database().
      77                 :          9 :         Xapian::Database dbr = get_writable_database_as_database();
      78   [ -  +  #  # ]:          9 :         TEST_EQUAL(dbr.get_avlength(), 2000000000);
      79                 :            :     }
      80                 :         10 :     return true;
      81                 :            : }
      82                 :            : 
      83                 :         13 : DEFINE_TESTCASE(dbstats1, backend) {
      84                 :         13 :     Xapian::Database db = get_database("etext");
      85                 :            : 
      86                 :            :     // Use precalculated values to avoid expending CPU cycles to calculate
      87                 :            :     // these every time without improving test coverage.
      88                 :         13 :     const Xapian::termcount min_len = 2;
      89                 :         13 :     const Xapian::termcount max_len = 532;
      90                 :         13 :     const Xapian::termcount max_wdf = 22;
      91                 :            : 
      92   [ +  +  +  + ]:         13 :     if (get_dbtype().find("chert") != string::npos ||
         [ +  + ][ #  # ]
         [ #  # ][ +  - ]
                 [ +  + ]
      93                 :            :         get_dbtype().find("brass") != string::npos) {
      94                 :            :         // Should be exact for brass and chert as no deletions have happened.
      95 [ -  + ][ #  # ]:          8 :         TEST_EQUAL(db.get_doclength_upper_bound(), max_len);
      96 [ -  + ][ #  # ]:          8 :         TEST_EQUAL(db.get_doclength_lower_bound(), min_len);
      97                 :            :     } else {
      98                 :            :         // For other backends, we usually give rather loose bounds.
      99 [ -  + ][ #  # ]:          5 :         TEST_REL(db.get_doclength_upper_bound(),>=,max_len);
     100 [ -  + ][ #  # ]:          5 :         TEST_REL(db.get_doclength_lower_bound(),<=,min_len);
     101                 :            :     }
     102                 :            : 
     103 [ -  + ][ #  # ]:         13 :     TEST_REL(db.get_wdf_upper_bound("the"),>=,max_wdf);
     104                 :            : 
     105                 :         13 :     return true;
     106                 :            : }
     107                 :            : 
     108                 :            : /// Check handling of alldocs on an empty database.
     109                 :         13 : DEFINE_TESTCASE(alldocspl3, backend) {
     110                 :         13 :     Xapian::Database db = get_database(string());
     111                 :            : 
     112 [ -  + ][ #  # ]:         13 :     TEST_EQUAL(db.get_termfreq(string()), 0);
     113 [ -  + ][ #  # ]:         13 :     TEST_EQUAL(db.get_collection_freq(string()), 0);
     114 [ -  + ][ #  # ]:         13 :     TEST(db.postlist_begin(string()) == db.postlist_end(string()));
     115                 :            : 
     116                 :         13 :     return true;
     117                 :            : }
     118                 :            : 
     119                 :            : /// Regression test for bug#392 in ModifiedPostList iteration, fixed in 1.0.15.
     120                 :         10 : DEFINE_TESTCASE(modifiedpostlist1, writable) {
     121                 :         10 :     Xapian::WritableDatabase db = get_writable_database();
     122                 :         10 :     Xapian::Document a, b;
     123                 :         10 :     Xapian::Enquire enq(db);
     124                 :            :    
     125                 :         10 :     a.add_term("T");
     126                 :         10 :     enq.set_query(Xapian::Query("T"));
     127                 :            :    
     128                 :         10 :     db.replace_document(2, a);
     129                 :         10 :     db.commit();
     130                 :         10 :     db.replace_document(1, a);
     131                 :         10 :     db.replace_document(1, b);
     132                 :            :    
     133                 :         10 :     mset_expect_order(enq.get_mset(0, 2), 2);
     134                 :            :    
     135                 :         10 :     return true;
     136                 :            : }
     137                 :            : 
     138                 :            : /// Regression test for chert bug fixed in 1.1.3 (ticket#397).
     139                 :         10 : DEFINE_TESTCASE(doclenaftercommit1, writable) {
     140                 :         10 :     Xapian::WritableDatabase db = get_writable_database();
     141 [ +  - ][ -  + ]:         20 :     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(1));
         [ #  # ][ -  + ]
     142                 :         10 :     db.replace_document(1, Xapian::Document());
     143                 :         10 :     db.commit();
     144   [ -  +  #  # ]:         10 :     TEST_EQUAL(db.get_doclength(1), 0);;
     145                 :         10 :     return true;
     146                 :            : }
     147                 :            : 
     148                 :         10 : DEFINE_TESTCASE(valuesaftercommit1, writable) {
     149                 :         10 :     Xapian::WritableDatabase db = get_writable_database();
     150                 :         10 :     Xapian::Document doc;
     151                 :         10 :     doc.add_value(0, "value");
     152                 :         10 :     db.replace_document(2, doc);
     153                 :         10 :     db.commit();
     154                 :         10 :     db.replace_document(1, doc);
     155                 :         10 :     db.replace_document(3, doc);
     156 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(db.get_document(3).get_value(0), "value");
     157                 :         10 :     db.commit();
     158 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(db.get_document(3).get_value(0), "value");
     159                 :         10 :     return true;
     160                 :            : }
     161                 :            : 
     162                 :          3 : DEFINE_TESTCASE(lockfilefd0or1, brass || chert || flint) {
     163                 :            : #if !defined __WIN32__ && !defined __CYGWIN__ && !defined __EMX__
     164                 :          3 :     int old_stdin = dup(0);
     165                 :          3 :     int old_stdout = dup(1);
     166                 :            :     try {
     167                 :            :         // With fd 0 available.
     168                 :          3 :         close(0);
     169                 :            :         {
     170                 :          3 :             Xapian::WritableDatabase db = get_writable_database();
     171 [ +  - ][ -  + ]:          6 :             TEST_EXCEPTION(Xapian::DatabaseLockError,
         [ #  # ][ -  + ]
     172                 :          3 :                            (void)get_writable_database_again());
     173                 :            :         }
     174                 :            :         // With fd 0 and fd 1 available.
     175                 :          3 :         close(1);
     176                 :            :         {
     177                 :          3 :             Xapian::WritableDatabase db = get_writable_database();
     178 [ +  - ][ -  + ]:          6 :             TEST_EXCEPTION(Xapian::DatabaseLockError,
         [ #  # ][ -  + ]
     179                 :          3 :                            (void)get_writable_database_again());
     180                 :            :         }
     181                 :            :         // With fd 1 available.
     182                 :          3 :         dup2(old_stdin, 0);
     183                 :            :         {
     184                 :          3 :             Xapian::WritableDatabase db = get_writable_database();
     185 [ +  - ][ -  + ]:          6 :             TEST_EXCEPTION(Xapian::DatabaseLockError,
         [ #  # ][ -  + ]
     186                 :          3 :                            (void)get_writable_database_again());
     187                 :            :         }
     188                 :          0 :     } catch (...) {
     189                 :          0 :         dup2(old_stdin, 0);
     190                 :          0 :         dup2(old_stdout, 1);
     191                 :          0 :         close(old_stdin);
     192                 :          0 :         close(old_stdout);
     193                 :          0 :         throw;
     194                 :            :     }
     195                 :            : 
     196                 :          3 :     dup2(old_stdout, 1);
     197                 :          3 :     close(old_stdin);
     198                 :          3 :     close(old_stdout);
     199                 :            : #endif
     200                 :            : 
     201                 :          3 :     return true;
     202                 :            : }
     203                 :            : 
     204 [ #  # ][ -  + ]:         12 : struct MyMatchDecider : public Xapian::MatchDecider {
     205                 :            :     mutable bool called;
     206                 :            :   
     207                 :         12 :     MyMatchDecider() : called(false) { }
     208                 :            : 
     209                 :          0 :     bool operator()(const Xapian::Document &) const {
     210                 :          0 :         called = true;
     211                 :          0 :         return true;
     212                 :            :     }
     213                 :            : };
     214                 :            : 
     215                 :            : /// Test Xapian::MatchDecider with remote backend fails.
     216                 :          6 : DEFINE_TESTCASE(matchdecider4, remote) {
     217                 :          6 :     Xapian::Database db(get_database("apitest_simpledata"));
     218                 :          6 :     Xapian::Enquire enquire(db);
     219                 :          6 :     enquire.set_query(Xapian::Query("paragraph"));
     220                 :            : 
     221                 :          6 :     MyMatchDecider mdecider, mspyold;
     222                 :          6 :     Xapian::MSet mset;
     223                 :            : 
     224 [ +  - ][ -  + ]:         12 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ -  + ]
     225                 :            :         mset = enquire.get_mset(0, 10, NULL, &mdecider));
     226   [ -  +  #  # ]:          6 :     TEST(!mdecider.called);
     227                 :            : 
     228 [ +  - ][ -  + ]:         12 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ -  + ]
     229                 :            :         mset = enquire.get_mset(0, 10, 0, NULL, NULL, &mspyold));
     230   [ -  +  #  # ]:          6 :     TEST(!mspyold.called);
     231                 :            : 
     232 [ +  - ][ -  + ]:         12 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ -  + ]
     233                 :            :         mset = enquire.get_mset(0, 10, 0, NULL, &mdecider, &mspyold));
     234   [ -  +  #  # ]:          6 :     TEST(!mdecider.called);
     235 [ -  + ][ #  # ]:          6 :     TEST(!mspyold.called);
     236                 :            : 
     237                 :          6 :     return true;
     238                 :            : }
     239                 :            : 
     240                 :            : /** Check that replacing an unmodified document doesn't increase the automatic
     241                 :            :  *  flush counter.  Regression test for bug fixed in 1.1.4/1.0.18.
     242                 :            :  */
     243                 :          3 : DEFINE_TESTCASE(replacedoc7, writable && !inmemory && !remote) {
     244                 :            :     // The inmemory backend doesn't batch changes, so there's nothing to
     245                 :            :     // check there.
     246                 :            :     //
     247                 :            :     // The remote backend doesn't implement the lazy replacement of documents
     248                 :            :     // optimisation currently.
     249                 :          3 :     Xapian::WritableDatabase db(get_writable_database());
     250                 :          3 :     Xapian::Document doc;
     251                 :          3 :     doc.set_data("fish");
     252                 :          3 :     doc.add_term("Hlocalhost");
     253                 :          3 :     doc.add_posting("hello", 1);
     254                 :          3 :     doc.add_posting("world", 2);
     255                 :          3 :     doc.add_value(1, "myvalue");
     256                 :          3 :     db.add_document(doc);
     257                 :          3 :     db.commit();
     258                 :            : 
     259                 :            :     // We add a second document, and then replace the first document with
     260                 :            :     // itself 10000 times.  If the document count for the database reopened
     261                 :            :     // read-only is 2, then we triggered an automatic commit.
     262                 :            : 
     263                 :          3 :     doc.add_term("XREV2");
     264                 :          3 :     db.add_document(doc);
     265                 :            : 
     266         [ +  + ]:      30003 :     for (int i = 0; i < 10000; ++i) {
     267                 :      30000 :         doc = db.get_document(1);
     268                 :      30000 :         db.replace_document(1, doc);
     269                 :            :     }
     270                 :            : 
     271                 :          3 :     Xapian::Database rodb(get_writable_database_as_database());
     272   [ -  +  #  # ]:          3 :     TEST_EQUAL(rodb.get_doccount(), 1);
     273                 :            : 
     274                 :          3 :     db.flush();
     275                 :          3 :     rodb.reopen();
     276                 :            : 
     277   [ -  +  #  # ]:          3 :     TEST_EQUAL(rodb.get_doccount(), 2);
     278                 :          3 :     return true;
     279                 :            : }
     280                 :            : 
     281                 :            : /** Check that replacing a document deleted since the last flush works.
     282                 :            :  *  Prior to 1.1.4/1.0.18, this failed to update the collection frequency and
     283                 :            :  *  wdf, and caused an assertion failure when assertions were enabled.
     284                 :            :  */
     285                 :         10 : DEFINE_TESTCASE(replacedoc8, writable) {
     286                 :         10 :     Xapian::WritableDatabase db(get_writable_database());
     287                 :            :     {
     288                 :         10 :         Xapian::Document doc;
     289                 :         10 :         doc.set_data("fish");
     290                 :         10 :         doc.add_term("takeaway");
     291                 :         10 :         db.add_document(doc);
     292                 :            :     }
     293                 :         10 :     db.delete_document(1);
     294                 :            :     {
     295                 :         10 :         Xapian::Document doc;
     296                 :         10 :         doc.set_data("chips");
     297                 :         10 :         doc.add_term("takeaway", 2);
     298                 :         10 :         db.replace_document(1, doc);
     299                 :            :     }
     300                 :         10 :     db.flush();
     301 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(db.get_collection_freq("takeaway"), 2);
     302                 :         10 :     Xapian::PostingIterator p = db.postlist_begin("takeaway");
     303 [ -  + ][ #  # ]:         10 :     TEST(p != db.postlist_end("takeaway"));
     304 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(p.get_wdf(), 2);
     305                 :         10 :     return true;
     306                 :            : }
     307                 :            : 
     308                 :            : /// Test coverage for DatabaseModifiedError.
     309                 :          3 : DEFINE_TESTCASE(databasemodified1, writable && !inmemory && !remote) {
     310                 :            :     // The inmemory backend doesn't support revisions.
     311                 :            :     //
     312                 :            :     // The remote backend doesn't work as expected here, I think due to
     313                 :            :     // test harness issues.
     314                 :          3 :     Xapian::WritableDatabase db(get_writable_database());
     315                 :          3 :     Xapian::Document doc;
     316                 :          3 :     doc.set_data("cargo");
     317                 :          3 :     doc.add_term("abc");
     318                 :          3 :     doc.add_term("def");
     319                 :          3 :     doc.add_term("ghi");
     320                 :          3 :     const int N = 500;
     321         [ +  + ]:       1503 :     for (int i = 0; i < N; ++i) {
     322                 :       1500 :         db.add_document(doc);
     323                 :            :     }
     324                 :          3 :     db.commit();
     325                 :            : 
     326                 :          3 :     Xapian::Database rodb(get_writable_database_as_database());
     327                 :          3 :     db.add_document(doc);
     328                 :          3 :     db.commit();
     329                 :            : 
     330                 :          3 :     db.add_document(doc);
     331                 :          3 :     db.commit();
     332                 :            : 
     333                 :          3 :     db.add_document(doc);
     334                 :            :     try {
     335 [ #  # ][ #  # ]:          3 :         TEST_EQUAL(*rodb.termlist_begin(N - 1), "abc");
     336                 :          0 :         return false;
     337                 :          3 :     } catch (const Xapian::DatabaseModifiedError &) {
     338                 :            :     }
     339                 :            : 
     340                 :            :     try {
     341                 :          3 :         Xapian::Enquire enq(rodb);
     342                 :          3 :         enq.set_query(Xapian::Query("abc"));
     343                 :          3 :         Xapian::MSet mset = enq.get_mset(0, 10);
     344                 :          3 :         return false;
     345                 :          3 :     } catch (const Xapian::DatabaseModifiedError &) {
     346                 :            :     }
     347                 :            : 
     348                 :          3 :     return true;
     349                 :            : }
     350                 :            : 
     351                 :            : /// Regression test for bug#462 fixed in 1.0.19 and 1.1.5.
     352                 :          9 : DEFINE_TESTCASE(qpmemoryleak1, writable && !inmemory) {
     353                 :            :     // Inmemory never throws DatabaseModifiedError.
     354                 :          9 :     Xapian::WritableDatabase wdb(get_writable_database());
     355                 :          9 :     Xapian::Document doc;
     356                 :            : 
     357                 :          9 :     doc.add_term("foo");
     358         [ +  + ]:        189 :     for (int i = 100; i < 120; ++i) {
     359                 :        180 :         doc.add_term(str(i));
     360                 :            :     }
     361                 :            : 
     362         [ +  + ]:        459 :     for (int j = 0; j < 50; ++j) {
     363                 :        450 :         wdb.add_document(doc);
     364                 :            :     }
     365                 :          9 :     wdb.commit();
     366                 :            : 
     367                 :          9 :     Xapian::Database database(get_writable_database_as_database());
     368                 :          9 :     Xapian::QueryParser queryparser;
     369                 :          9 :     queryparser.set_database(database);
     370 [ +  - ][ -  + ]:         60 :     TEST_EXCEPTION(Xapian::DatabaseModifiedError,
         [ +  - ][ #  # ]
                 [ -  + ]
     371                 :            :         for (int k = 0; k < 3; ++k) {
     372                 :            :             wdb.add_document(doc);
     373                 :            :             wdb.commit();
     374                 :            :             (void)queryparser.parse_query("1", queryparser.FLAG_PARTIAL);
     375                 :            :         }
     376                 :            :     );
     377                 :            : 
     378                 :          9 :     return true;
     379                 :            : }
     380                 :            : 
     381                 :            : static void
     382                 :          3 : make_msize1_db(Xapian::WritableDatabase &db, const string &)
     383                 :            : {
     384                 :            :     const char * value0 =
     385                 :          3 :         "ABBCDEFGHIJKLMMNOPQQRSTTUUVVWXYZZaabcdefghhijjkllmnopqrsttuvwxyz";
     386                 :            :     const char * value1 =
     387                 :          3 :         "EMLEMMMMMMMNMMLMELEDNLEDMLMLDMLMLMLMEDGFHPOPBAHJIQJNGRKCGF";
     388         [ +  + ]:        195 :     while (*value0) {
     389                 :        192 :         Xapian::Document doc;
     390                 :        192 :         doc.add_value(0, string(1, *value0++));
     391         [ +  + ]:        192 :         if (*value1) {
     392                 :        174 :             doc.add_value(1, string(1, *value1++));
     393                 :        174 :             doc.add_term("K1");
     394                 :            :         }
     395                 :        192 :         db.add_document(doc);
     396                 :            :     }
     397                 :          3 : }
     398                 :            : 
     399                 :            : /// Regression test for ticket#464, fixed in 1.1.6 and 1.0.20.
     400                 :          3 : DEFINE_TESTCASE(msize1, generated) {
     401                 :          3 :     Xapian::Database db = get_database("msize1", make_msize1_db);
     402                 :          3 :     Xapian::Enquire enq(db);
     403                 :          3 :     enq.set_sort_by_value(1, false);
     404                 :          3 :     enq.set_collapse_key(0);
     405                 :          3 :     enq.set_query(Xapian::Query("K1"));
     406                 :            : 
     407                 :          3 :     Xapian::MSet mset = enq.get_mset(0, 10, 1000);
     408                 :          3 :     Xapian::doccount lb = mset.get_matches_lower_bound();
     409                 :          3 :     Xapian::doccount ub = mset.get_matches_upper_bound();
     410                 :          3 :     Xapian::doccount est = mset.get_matches_estimated();
     411   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb, ub);
     412 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb, est);
     413                 :            : 
     414                 :          3 :     Xapian::MSet mset2 = enq.get_mset(50, 10, 1000);
     415                 :          3 :     Xapian::doccount lb2 = mset2.get_matches_lower_bound();
     416                 :          3 :     Xapian::doccount ub2 = mset2.get_matches_upper_bound();
     417                 :          3 :     Xapian::doccount est2 = mset2.get_matches_estimated();
     418   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb2, ub2);
     419 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb2, est2);
     420 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(est, est2);
     421                 :            : 
     422                 :          3 :     Xapian::MSet mset3 = enq.get_mset(0, 60);
     423                 :          3 :     Xapian::doccount lb3 = mset3.get_matches_lower_bound();
     424                 :          3 :     Xapian::doccount ub3 = mset3.get_matches_upper_bound();
     425                 :          3 :     Xapian::doccount est3 = mset3.get_matches_estimated();
     426   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb3, ub3);
     427 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb3, est3);
     428 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(est, est3);
     429                 :            : 
     430                 :          3 :     return true;
     431                 :            : }
     432                 :            : 
     433                 :            : static void
     434                 :          3 : make_msize2_db(Xapian::WritableDatabase &db, const string &)
     435                 :            : {
     436                 :          3 :     const char * value0 = "AAABCDEEFGHIIJJKLLMNNOOPPQQRSTTUVWXYZ";
     437                 :          3 :     const char * value1 = "MLEMNMLMLMEDEDEMLEMLMLMLPOAHGF";
     438         [ +  + ]:        114 :     while (*value0) {
     439                 :        111 :         Xapian::Document doc;
     440                 :        111 :         doc.add_value(0, string(1, *value0++));
     441         [ +  + ]:        111 :         if (*value1) {
     442                 :         90 :             doc.add_value(1, string(1, *value1++));
     443                 :         90 :             doc.add_term("K1");
     444                 :            :         }
     445                 :        111 :         db.add_document(doc);
     446                 :            :     }
     447                 :          3 : }
     448                 :            : 
     449                 :            : /// Regression test for bug related to ticket#464, fixed in 1.1.6 and 1.0.20.
     450                 :          3 : DEFINE_TESTCASE(msize2, generated) {
     451                 :          3 :     Xapian::Database db = get_database("msize2", make_msize2_db);
     452                 :          3 :     Xapian::Enquire enq(db);
     453                 :          3 :     enq.set_sort_by_value(1, false);
     454                 :          3 :     enq.set_collapse_key(0);
     455                 :          3 :     enq.set_query(Xapian::Query("K1"));
     456                 :            : 
     457                 :          3 :     Xapian::MSet mset = enq.get_mset(0, 10, 1000);
     458                 :          3 :     Xapian::doccount lb = mset.get_matches_lower_bound();
     459                 :          3 :     Xapian::doccount ub = mset.get_matches_upper_bound();
     460                 :          3 :     Xapian::doccount est = mset.get_matches_estimated();
     461   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb, ub);
     462 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb, est);
     463                 :            : 
     464                 :          3 :     Xapian::MSet mset2 = enq.get_mset(50, 10, 1000);
     465                 :          3 :     Xapian::doccount lb2 = mset2.get_matches_lower_bound();
     466                 :          3 :     Xapian::doccount ub2 = mset2.get_matches_upper_bound();
     467                 :          3 :     Xapian::doccount est2 = mset2.get_matches_estimated();
     468   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb2, ub2);
     469 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb2, est2);
     470 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(est, est2);
     471                 :            : 
     472                 :          3 :     Xapian::MSet mset3 = enq.get_mset(0, 60);
     473                 :          3 :     Xapian::doccount lb3 = mset3.get_matches_lower_bound();
     474                 :          3 :     Xapian::doccount ub3 = mset3.get_matches_upper_bound();
     475                 :          3 :     Xapian::doccount est3 = mset3.get_matches_estimated();
     476   [ -  +  #  # ]:          3 :     TEST_EQUAL(lb3, ub3);
     477 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(lb3, est3);
     478 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(est, est3);
     479                 :            : 
     480                 :          3 :     return true;
     481                 :            : }
     482                 :            : 
     483                 :            : static void
     484                 :          3 : make_xordecay1_db(Xapian::WritableDatabase &db, const string &)
     485                 :            : {
     486         [ +  + ]:        150 :     for (int n = 1; n != 50; ++n) {
     487                 :        147 :         Xapian::Document doc;
     488         [ +  + ]:       7350 :         for (int i = 1; i != 50; ++i) {
     489         [ +  + ]:       7203 :             if (n % i == 0)
     490                 :        603 :                 doc.add_term("N" + str(i));
     491                 :            :         }
     492                 :        147 :         db.add_document(doc);
     493                 :            :     }
     494                 :          3 : }
     495                 :            : 
     496                 :            : /// Regression test for bug in decay of XOR, fixed in 1.2.1 and 1.0.21.
     497                 :          3 : DEFINE_TESTCASE(xordecay1, generated) {
     498                 :          3 :     Xapian::Database db = get_database("xordecay1", make_xordecay1_db);
     499                 :          3 :     Xapian::Enquire enq(db);
     500                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_XOR,
     501                 :            :                                 Xapian::Query("N10"),
     502                 :            :                                 Xapian::Query(Xapian::Query::OP_OR,
     503                 :            :                                               Xapian::Query("N2"),
     504                 :          3 :                                               Xapian::Query("N3"))));
     505                 :          3 :     Xapian::MSet mset1 = enq.get_mset(0, 1);
     506                 :          3 :     Xapian::MSet msetall = enq.get_mset(0, db.get_doccount());
     507                 :            : 
     508   [ -  +  #  # ]:          3 :     TEST(mset_range_is_same(mset1, 0, msetall, 0, mset1.size()));
     509                 :          3 :     return true;
     510                 :            : }
     511                 :            : 
     512                 :            : static void
     513                 :          3 : make_ordecay_db(Xapian::WritableDatabase &db, const string &)
     514                 :            : {
     515                 :          3 :     const char * p = "VJ=QC]LUNTaARLI;715RR^];A4O=P4ZG<2CS4EM^^VS[A6QENR";
     516         [ +  + ]:        153 :     for (int d = 0; p[d]; ++d) {
     517                 :        150 :         int l = int(p[d] - '0');
     518                 :        150 :         Xapian::Document doc;
     519         [ +  + ]:       3867 :         for (int n = 1; n < l; ++n) {
     520                 :       3717 :             doc.add_term("N" + str(n));
     521         [ +  + ]:       3717 :             if (n % (d + 1) == 0) {
     522                 :        309 :                 doc.add_term("M" + str(n));
     523                 :            :             }
     524                 :            :         }
     525                 :        150 :         db.add_document(doc);
     526                 :            :     }
     527                 :          3 : }
     528                 :            : 
     529                 :            : /// Regression test for bug in decay of OR to AND, fixed in 1.2.1 and 1.0.21.
     530                 :          3 : DEFINE_TESTCASE(ordecay1, generated) {
     531                 :          3 :     Xapian::Database db = get_database("ordecay", make_ordecay_db);
     532                 :          3 :     Xapian::Enquire enq(db);
     533                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_OR,
     534                 :            :                                 Xapian::Query("N20"),
     535                 :          3 :                                 Xapian::Query("N21")));
     536                 :            : 
     537                 :          3 :     Xapian::MSet msetall = enq.get_mset(0, db.get_doccount());
     538         [ +  + ]:         96 :     for (unsigned int i = 1; i < msetall.size(); ++i) {
     539                 :         93 :         Xapian::MSet submset = enq.get_mset(0, i);
     540   [ -  +  #  # ]:         93 :         TEST(mset_range_is_same(submset, 0, msetall, 0, submset.size()));
     541                 :            :     }
     542                 :          3 :     return true;
     543                 :            : }
     544                 :            : 
     545                 :            : /** Regression test for bug in decay of OR to AND_MAYBE, fixed in 1.2.1 and
     546                 :            :  *  1.0.21.
     547                 :            :  */
     548                 :          3 : DEFINE_TESTCASE(ordecay2, generated) {
     549                 :          3 :     Xapian::Database db = get_database("ordecay", make_ordecay_db);
     550                 :          3 :     Xapian::Enquire enq(db);
     551                 :          3 :     std::vector<Xapian::Query> q;
     552                 :          3 :     q.push_back(Xapian::Query("M20"));
     553                 :          3 :     q.push_back(Xapian::Query("N21"));
     554                 :          3 :     q.push_back(Xapian::Query("N22"));
     555                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_OR,
     556                 :            :                                 Xapian::Query("N25"),
     557                 :            :                                 Xapian::Query(Xapian::Query::OP_AND,
     558                 :            :                                               q.begin(),
     559                 :          3 :                                               q.end())));
     560                 :            : 
     561                 :          3 :     Xapian::MSet msetall = enq.get_mset(0, db.get_doccount());
     562         [ +  + ]:         84 :     for (unsigned int i = 1; i < msetall.size(); ++i) {
     563                 :         81 :         Xapian::MSet submset = enq.get_mset(0, i);
     564   [ -  +  #  # ]:         81 :         TEST(mset_range_is_same(submset, 0, msetall, 0, submset.size()));
     565                 :            :     }
     566                 :          3 :     return true;
     567                 :            : }
     568                 :            : 
     569                 :            : static void
     570                 :          3 : make_orcheck_db(Xapian::WritableDatabase &db, const string &)
     571                 :            : {
     572                 :            :     static const int t1[6] = {2, 4, 6, 8, 10, 0};
     573                 :            :     static const int t2[11] = {6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 0};
     574                 :            :     static const int t3[11] = {3, 7, 8, 11, 12, 13, 14, 15, 16, 17, 0};
     575                 :            : 
     576         [ +  + ]:         54 :     for (unsigned i = 1; i <= 17; ++i) {
     577                 :         51 :         Xapian::Document doc;
     578                 :         51 :         db.replace_document(i, doc);
     579                 :            :     }
     580         [ +  + ]:         18 :     for (const int * p = t1; *p != 0; ++p) {
     581                 :         15 :         Xapian::Document doc(db.get_document(*p));
     582                 :         15 :         doc.add_term("T1");
     583                 :         15 :         db.replace_document(*p, doc);
     584                 :            :     }
     585         [ +  + ]:         33 :     for (const int * p = t2; *p != 0; ++p) {
     586                 :         30 :         Xapian::Document doc(db.get_document(*p));
     587                 :         30 :         doc.add_term("T2");
     588         [ +  + ]:         30 :         if (*p < 17) {
     589                 :         27 :             doc.add_term("T2_lowfreq");
     590                 :            :         }
     591                 :         30 :         doc.add_value(2, "1");
     592                 :         30 :         db.replace_document(*p, doc);
     593                 :            :     }
     594         [ +  + ]:         33 :     for (const int * p = t3; *p != 0; ++p) {
     595                 :         30 :         Xapian::Document doc(db.get_document(*p));
     596                 :         30 :         doc.add_term("T3");
     597         [ +  + ]:         30 :         if (*p < 17) {
     598                 :         27 :             doc.add_term("T3_lowfreq");
     599                 :            :         }
     600                 :         30 :         doc.add_value(3, "1");
     601                 :         30 :         db.replace_document(*p, doc);
     602                 :            :     }
     603                 :          3 : }
     604                 :            : 
     605                 :            : /** Regression test for bugs in the check() method of OrPostList. (ticket #485)
     606                 :            :  *  Bugs introduced and fixed between 1.2.0 and 1.2.1 (never in a release).
     607                 :            :  */
     608                 :          3 : DEFINE_TESTCASE(orcheck1, generated) {
     609                 :          3 :     Xapian::Database db = get_database("orcheck1", make_orcheck_db);
     610                 :          3 :     Xapian::Enquire enq(db);
     611                 :          3 :     Xapian::Query q1("T1");
     612                 :          3 :     Xapian::Query q2("T2");
     613                 :          3 :     Xapian::Query q2l("T2_lowfreq");
     614                 :          3 :     Xapian::Query q3("T3");
     615                 :          3 :     Xapian::Query q3l("T3_lowfreq");
     616                 :          3 :     Xapian::Query v2(Xapian::Query::OP_VALUE_RANGE, 2, "0", "2");
     617                 :          3 :     Xapian::Query v3(Xapian::Query::OP_VALUE_RANGE, 3, "0", "2");
     618                 :            : 
     619                 :          3 :     tout << "Checking q2 OR q3\n";
     620                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_AND, q1,
     621                 :          3 :                                 Xapian::Query(Xapian::Query::OP_OR, q2, q3)));
     622                 :          3 :     mset_expect_order(enq.get_mset(0, db.get_doccount()), 8, 6);
     623                 :            : 
     624                 :          3 :     tout << "Checking q2l OR q3\n";
     625                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_AND, q1,
     626                 :          3 :                                 Xapian::Query(Xapian::Query::OP_OR, q2l, q3)));
     627                 :          3 :     mset_expect_order(enq.get_mset(0, db.get_doccount()), 8, 6);
     628                 :            : 
     629                 :          3 :     tout << "Checking q2 OR q3l\n";
     630                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_AND, q1,
     631                 :          3 :                                 Xapian::Query(Xapian::Query::OP_OR, q2, q3l)));
     632                 :          3 :     mset_expect_order(enq.get_mset(0, db.get_doccount()), 8, 6);
     633                 :            : 
     634                 :          3 :     tout << "Checking v2 OR q3\n";
     635                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_AND, q1,
     636                 :          3 :                                 Xapian::Query(Xapian::Query::OP_OR, v2, q3)));
     637                 :          3 :     mset_expect_order(enq.get_mset(0, db.get_doccount()), 8, 6);
     638                 :            : 
     639                 :          3 :     tout << "Checking q2 OR v3\n";
     640                 :            :     enq.set_query(Xapian::Query(Xapian::Query::OP_AND, q1,
     641                 :          3 :                                 Xapian::Query(Xapian::Query::OP_OR, q2, v3)));
     642                 :            :     // Order of results in this one is different, because v3 gives no weight,
     643                 :            :     // both documents are in q2, and document 8 has a higher length.
     644                 :          3 :     mset_expect_order(enq.get_mset(0, db.get_doccount()), 6, 8);
     645                 :            : 
     646                 :          3 :     return true;
     647                 :            : }
     648                 :            : 
     649                 :            : /** Regression test for bug fixed in 1.2.1 and 1.0.21.
     650                 :            :  *
     651                 :            :  *  We failed to mark the Btree as unmodified after cancel().
     652                 :            :  */
     653                 :          3 : DEFINE_TESTCASE(failedreplace1, brass || chert || flint) {
     654                 :          3 :     Xapian::WritableDatabase db(get_writable_database());
     655                 :          3 :     Xapian::Document doc;
     656                 :          3 :     doc.add_term("foo");
     657                 :          3 :     db.add_document(doc);
     658                 :          3 :     Xapian::docid did = db.add_document(doc);
     659                 :          3 :     doc.add_term("abc");
     660                 :          3 :     doc.add_term(string(1000, 'm'));
     661                 :          3 :     doc.add_term("xyz");
     662 [ +  - ][ -  + ]:          6 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.replace_document(did, doc));
         [ #  # ][ -  + ]
     663                 :          3 :     db.commit();
     664   [ -  +  #  # ]:          3 :     TEST_EQUAL(db.get_doccount(), 0);
     665 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(db.get_termfreq("foo"), 0);
     666                 :          3 :     return true;
     667                 :            : }
     668                 :            : 
     669                 :          3 : DEFINE_TESTCASE(failedreplace2, brass || chert || flint) {
     670                 :          3 :     Xapian::WritableDatabase db(get_writable_database("apitest_simpledata"));
     671                 :          3 :     db.commit();
     672                 :          3 :     Xapian::doccount db_size = db.get_doccount();
     673                 :          3 :     Xapian::Document doc;
     674                 :          3 :     doc.set_data("wibble");
     675                 :          3 :     doc.add_term("foo");
     676                 :          3 :     doc.add_value(0, "seven");
     677                 :          3 :     db.add_document(doc);
     678                 :          3 :     Xapian::docid did = db.add_document(doc);
     679                 :          3 :     doc.add_term("abc");
     680                 :          3 :     doc.add_term(string(1000, 'm'));
     681                 :          3 :     doc.add_term("xyz");
     682                 :          3 :     doc.add_value(0, "six");
     683 [ +  - ][ -  + ]:          6 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.replace_document(did, doc));
         [ #  # ][ -  + ]
     684                 :          3 :     db.commit();
     685   [ -  +  #  # ]:          3 :     TEST_EQUAL(db.get_doccount(), db_size);
     686 [ -  + ][ #  # ]:          3 :     TEST_EQUAL(db.get_termfreq("foo"), 0);
     687                 :          3 :     return true;
     688                 :            : }
     689                 :            : 
     690                 :            : /// Coverage for SelectPostList::skip_to().
     691                 :         13 : DEFINE_TESTCASE(phrase3, positional) {
     692                 :         13 :     Xapian::Database db = get_database("apitest_phrase");
     693                 :            : 
     694                 :         13 :     const char * phrase_words[] = { "phrase", "near" };
     695                 :         13 :     Xapian::Query q(Xapian::Query::OP_NEAR, phrase_words, phrase_words + 2, 12);
     696                 :         13 :     q = Xapian::Query(Xapian::Query::OP_AND_MAYBE, Xapian::Query("pad"), q);
     697                 :            : 
     698                 :         13 :     Xapian::Enquire enquire(db);
     699                 :         13 :     enquire.set_query(q);
     700                 :         13 :     Xapian::MSet mset = enquire.get_mset(0, 5);
     701                 :            : 
     702                 :         13 :     return true;
     703                 :            : }
     704                 :            : 
     705                 :            : /// Check that get_mset(<large number>, 10) doesn't exhaust memory needlessly.
     706                 :            : // Regression test for fix in 1.2.4.
     707                 :         13 : DEFINE_TESTCASE(msetfirst2, backend) {
     708                 :         13 :     Xapian::Database db(get_database("apitest_simpledata"));
     709                 :         13 :     Xapian::Enquire enquire(db);
     710                 :         13 :     enquire.set_query(Xapian::Query("paragraph"));
     711                 :         13 :     Xapian::MSet mset;
     712                 :            :     // Before the fix, this tried to allocated too much memory.
     713                 :         13 :     mset = enquire.get_mset(0xfffffff0, 1);
     714   [ -  +  #  # ]:         13 :     TEST_EQUAL(mset.get_firstitem(), 0xfffffff0);
     715                 :            :     // Check that the number of documents gets clamped too.
     716                 :         13 :     mset = enquire.get_mset(1, 0xfffffff0);
     717   [ -  +  #  # ]:         13 :     TEST_EQUAL(mset.get_firstitem(), 1);
     718                 :            :     // Another regression test - MatchNothing used to give an MSet with
     719                 :            :     // get_firstitem() returning 0.
     720                 :         13 :     enquire.set_query(Xapian::Query::MatchNothing);
     721                 :         13 :     mset = enquire.get_mset(1, 1);
     722   [ -  +  #  # ]:         13 :     TEST_EQUAL(mset.get_firstitem(), 1);
     723                 :         13 :     return true;
     724                 :            : }
     725                 :            : 
     726                 :         13 : DEFINE_TESTCASE(bm25weight2, backend) {
     727                 :         13 :     Xapian::Database db(get_database("etext"));
     728                 :         13 :     Xapian::Enquire enquire(db);
     729                 :         13 :     enquire.set_query(Xapian::Query("the"));
     730                 :         13 :     enquire.set_weighting_scheme(Xapian::BM25Weight(0, 0, 0, 0, 1));
     731                 :         13 :     Xapian::MSet mset = enquire.get_mset(0, 100);
     732   [ -  +  #  # ]:         13 :     TEST_REL(mset.size(),>=,2);
     733                 :         13 :     Xapian::weight weight0 = mset[0].get_weight();
     734         [ +  + ]:       1300 :     for (size_t i = 1; i != mset.size(); ++i) {
     735 [ -  + ][ #  # ]:       1287 :         TEST_EQUAL(weight0, mset[i].get_weight());
     736                 :            :     }
     737                 :         13 :     return true;
     738                 :            : }
     739                 :            : 
     740                 :         13 : DEFINE_TESTCASE(tradweight2, backend) {
     741                 :         13 :     Xapian::Database db(get_database("etext"));
     742                 :         13 :     Xapian::Enquire enquire(db);
     743                 :         13 :     enquire.set_query(Xapian::Query("the"));
     744                 :         13 :     enquire.set_weighting_scheme(Xapian::TradWeight(0));
     745                 :         13 :     Xapian::MSet mset = enquire.get_mset(0, 100);
     746   [ -  +  #  # ]:         13 :     TEST_REL(mset.size(),>=,2);
     747                 :         13 :     Xapian::weight weight0 = mset[0].get_weight();
     748         [ +  + ]:       1300 :     for (size_t i = 1; i != mset.size(); ++i) {
     749 [ -  + ][ #  # ]:       1287 :         TEST_EQUAL(weight0, mset[i].get_weight());
     750                 :            :     }
     751                 :         13 :     return true;
     752                 :            : }

Generated by: LCOV version 1.8