LCOV - code coverage report
Current view: top level - tests - api_postingsource.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 388 416 93.3 %
Date: 2019-06-30 05:20:33 Functions: 83 100 83.0 %
Branches: 384 1962 19.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_postingsource.cc
       2                 :            :  * @brief tests of posting sources
       3                 :            :  */
       4                 :            : /* Copyright 2008,2009,2011,2015,2016,2019 Olly Betts
       5                 :            :  * Copyright 2008,2009 Lemur Consulting Ltd
       6                 :            :  * Copyright 2010 Richard Boulton
       7                 :            :  *
       8                 :            :  * This program is free software; you can redistribute it and/or
       9                 :            :  * modify it under the terms of the GNU General Public License as
      10                 :            :  * published by the Free Software Foundation; either version 2 of the
      11                 :            :  * License, or (at your option) any later version.
      12                 :            :  *
      13                 :            :  * This program is distributed in the hope that it will be useful,
      14                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16                 :            :  * GNU General Public License for more details.
      17                 :            :  *
      18                 :            :  * You should have received a copy of the GNU General Public License
      19                 :            :  * along with this program; if not, write to the Free Software
      20                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      21                 :            :  * USA
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <config.h>
      25                 :            : 
      26                 :            : #include "api_postingsource.h"
      27                 :            : 
      28                 :            : #include <xapian.h>
      29                 :            : 
      30                 :            : #include <string>
      31                 :            : #include "safeunistd.h"
      32                 :            : 
      33                 :            : #include "str.h"
      34                 :            : #include "testutils.h"
      35                 :            : #include "apitest.h"
      36                 :            : 
      37                 :            : using namespace std;
      38                 :            : 
      39         [ -  + ]:         92 : class MyOddPostingSource : public Xapian::PostingSource {
      40                 :            :     Xapian::doccount num_docs;
      41                 :            : 
      42                 :            :     Xapian::doccount last_docid;
      43                 :            : 
      44                 :            :     Xapian::docid did;
      45                 :            : 
      46                 :         20 :     MyOddPostingSource(Xapian::doccount num_docs_,
      47                 :            :                        Xapian::doccount last_docid_)
      48                 :         20 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
      49                 :         20 :     { }
      50                 :            : 
      51                 :            :   public:
      52                 :          6 :     MyOddPostingSource(const Xapian::Database &db)
      53 [ +  - ][ +  - ]:          6 :         : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
      54                 :          6 :     { }
      55                 :            : 
      56                 :         40 :     PostingSource * clone() const { return new MyOddPostingSource(num_docs, last_docid); }
      57                 :            : 
      58                 :          8 :     void init(const Xapian::Database &) { did = 0; }
      59                 :            : 
      60                 :            :     // These bounds could be better, but that's not important here.
      61                 :         16 :     Xapian::doccount get_termfreq_min() const { return 0; }
      62                 :            : 
      63                 :         24 :     Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
      64                 :            : 
      65                 :         16 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
      66                 :            : 
      67                 :         64 :     void next(double wt) {
      68                 :            :         (void)wt;
      69                 :         64 :         ++did;
      70         [ +  + ]:         64 :         if (did % 2 == 0) ++did;
      71                 :         64 :     }
      72                 :            : 
      73                 :          4 :     void skip_to(Xapian::docid to_did, double wt) {
      74                 :            :         (void)wt;
      75                 :          4 :         did = to_did;
      76         [ +  - ]:          4 :         if (did % 2 == 0) ++did;
      77                 :          4 :     }
      78                 :            : 
      79                 :         68 :     bool at_end() const {
      80                 :            :         // Doesn't work if last_docid is 2^32 - 1.
      81                 :         68 :         return did > last_docid;
      82                 :            :     }
      83                 :            : 
      84                 :        128 :     Xapian::docid get_docid() const { return did; }
      85                 :            : 
      86         [ #  # ]:          0 :     string get_description() const { return "MyOddPostingSource"; }
      87                 :            : };
      88                 :            : 
      89                 :          4 : DEFINE_TESTCASE(externalsource1, backend && !remote && !multi) {
      90                 :            :     // Doesn't work for remote without registering with the server.
      91                 :            :     // Doesn't work for multi because it checks the docid in the
      92                 :            :     // subdatabase.
      93 [ +  - ][ +  - ]:          4 :     Xapian::Database db(get_database("apitest_phrase"));
      94         [ +  - ]:          8 :     Xapian::Enquire enq(db);
      95         [ +  - ]:          8 :     MyOddPostingSource src(db);
      96                 :            : 
      97                 :            :     // Check that passing NULL is rejected as intended.
      98                 :          4 :     Xapian::PostingSource * nullsrc = NULL;
      99 [ +  - ][ -  + ]:          4 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(nullsrc));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     100                 :            : 
     101 [ +  - ][ +  - ]:          4 :     enq.set_query(Xapian::Query(&src));
     102                 :            : 
     103         [ +  - ]:          8 :     Xapian::MSet mset = enq.get_mset(0, 10);
     104         [ +  - ]:          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
     105                 :            : 
     106                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     107                 :            :                     Xapian::Query("leav"),
     108 [ +  - ][ +  - ]:          8 :                     Xapian::Query(&src));
         [ +  - ][ +  - ]
     109         [ +  - ]:          4 :     enq.set_query(q);
     110                 :            : 
     111 [ +  - ][ +  - ]:          4 :     mset = enq.get_mset(0, 10);
     112         [ +  - ]:          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     113                 :            : 
     114                 :          4 :     return true;
     115                 :            : }
     116                 :            : 
     117                 :            : // Test that trying to use PostingSource with the remote backend throws
     118                 :            : // Xapian::UnimplementedError as expected (we need to register the class
     119                 :            : // in xapian-tcpsrv/xapian-progsrv for this to work).
     120                 :          2 : DEFINE_TESTCASE(externalsource2, remote) {
     121 [ +  - ][ +  - ]:          2 :     Xapian::Database db(get_database("apitest_phrase"));
     122         [ +  - ]:          4 :     Xapian::Enquire enq(db);
     123         [ +  - ]:          4 :     MyOddPostingSource src(db);
     124                 :            : 
     125 [ +  - ][ +  - ]:          2 :     enq.set_query(Xapian::Query(&src));
     126                 :            : 
     127 [ +  - ][ -  + ]:          2 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     128                 :            :                    Xapian::MSet mset = enq.get_mset(0, 10));
     129                 :            : 
     130                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     131                 :            :                     Xapian::Query("leav"),
     132 [ +  - ][ +  - ]:          4 :                     Xapian::Query(&src));
         [ +  - ][ +  - ]
     133         [ +  - ]:          2 :     enq.set_query(q);
     134                 :            : 
     135 [ +  - ][ -  +  :          2 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     136                 :            :                    Xapian::MSet mset = enq.get_mset(0, 10));
     137                 :            : 
     138                 :          2 :     return true;
     139                 :            : }
     140                 :            : 
     141         [ -  + ]:        152 : class MyOddWeightingPostingSource : public Xapian::PostingSource {
     142                 :            :     Xapian::doccount num_docs;
     143                 :            : 
     144                 :            :     Xapian::doccount last_docid;
     145                 :            : 
     146                 :            :     Xapian::docid did;
     147                 :            : 
     148                 :         36 :     MyOddWeightingPostingSource(Xapian::doccount num_docs_,
     149                 :            :                                 Xapian::doccount last_docid_)
     150                 :         36 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
     151                 :            :     {
     152         [ +  - ]:         36 :         set_maxweight(1000);
     153                 :         36 :     }
     154                 :            : 
     155                 :            :   public:
     156                 :          4 :     MyOddWeightingPostingSource(const Xapian::Database &db)
     157 [ +  - ][ +  - ]:          4 :         : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
     158                 :          4 :     { }
     159                 :            : 
     160                 :         36 :     PostingSource * clone() const {
     161         [ +  - ]:         36 :         return new MyOddWeightingPostingSource(num_docs, last_docid);
     162                 :            :     }
     163                 :            : 
     164                 :         20 :     void init(const Xapian::Database &) { did = 0; }
     165                 :            : 
     166                 :        236 :     double get_weight() const {
     167         [ +  + ]:        236 :         return (did % 2) ? 1000 : 0.001;
     168                 :            :     }
     169                 :            : 
     170                 :            :     // These bounds could be better, but that's not important here.
     171                 :         40 :     Xapian::doccount get_termfreq_min() const { return 0; }
     172                 :            : 
     173                 :         72 :     Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
     174                 :            : 
     175                 :         40 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
     176                 :            : 
     177                 :        240 :     void next(double wt) {
     178                 :            :         (void)wt;
     179                 :        240 :         ++did;
     180                 :        240 :     }
     181                 :            : 
     182                 :         16 :     void skip_to(Xapian::docid to_did, double wt) {
     183                 :            :         (void)wt;
     184                 :         16 :         did = to_did;
     185                 :         16 :     }
     186                 :            : 
     187                 :        256 :     bool at_end() const {
     188                 :            :         // Doesn't work if last_docid is 2^32 - 1.
     189                 :        256 :         return did > last_docid;
     190                 :            :     }
     191                 :            : 
     192                 :        496 :     Xapian::docid get_docid() const { return did; }
     193                 :            : 
     194                 :          0 :     string get_description() const {
     195         [ #  # ]:          0 :         return "MyOddWeightingPostingSource";
     196                 :            :     }
     197                 :            : };
     198                 :            : 
     199                 :            : // Like externalsource1, except we use the weight to favour odd documents.
     200                 :          4 : DEFINE_TESTCASE(externalsource3, backend && !remote && !multi) {
     201                 :            :     // Doesn't work for remote without registering with the server.
     202                 :            :     // Doesn't work for multi because it checks the docid in the
     203                 :            :     // subdatabase.
     204 [ +  - ][ +  - ]:          4 :     Xapian::Database db(get_database("apitest_phrase"));
     205         [ +  - ]:          8 :     Xapian::Enquire enq(db);
     206         [ +  - ]:          8 :     MyOddWeightingPostingSource src(db);
     207                 :            : 
     208 [ +  - ][ +  - ]:          4 :     enq.set_query(Xapian::Query(&src));
     209                 :            : 
     210         [ +  - ]:          8 :     Xapian::MSet mset = enq.get_mset(0, 10);
     211         [ +  - ]:          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17, 2);
     212                 :            : 
     213                 :            :     Xapian::Query q(Xapian::Query::OP_OR,
     214                 :            :                     Xapian::Query("leav"),
     215 [ +  - ][ +  - ]:          8 :                     Xapian::Query(&src));
         [ +  - ][ +  - ]
     216         [ +  - ]:          4 :     enq.set_query(q);
     217                 :            : 
     218 [ +  - ][ +  - ]:          4 :     mset = enq.get_mset(0, 5);
     219         [ +  - ]:          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     220                 :            : 
     221 [ +  - ][ +  - ]:          4 :     tout << "max possible weight = " << mset.get_max_possible() << endl;
         [ +  - ][ +  - ]
     222 [ +  - ][ -  + ]:          4 :     TEST(mset.get_max_possible() > 1000);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     223                 :            : 
     224         [ +  - ]:          4 :     enq.set_cutoff(0, 1000.001);
     225 [ +  - ][ +  - ]:          4 :     mset = enq.get_mset(0, 10);
     226         [ +  - ]:          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     227                 :            : 
     228 [ +  - ][ +  - ]:          4 :     tout << "max possible weight = " << mset.get_max_possible() << endl;
         [ +  - ][ +  - ]
     229 [ +  - ][ -  + ]:          4 :     TEST(mset.get_max_possible() > 1000);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     230                 :            : 
     231 [ +  - ][ +  - ]:          4 :     enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 0.5));
                 [ +  - ]
     232 [ +  - ][ +  - ]:          4 :     mset = enq.get_mset(0, 10);
     233 [ +  - ][ -  + ]:          4 :     TEST(mset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     234                 :            : 
     235 [ +  - ][ -  + ]:          4 :     TEST_EQUAL(mset.get_max_possible(), 500);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     236                 :            : 
     237 [ +  - ][ +  - ]:          4 :     enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 2));
                 [ +  - ]
     238 [ +  - ][ +  - ]:          4 :     mset = enq.get_mset(0, 10);
     239         [ +  - ]:          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
     240                 :            : 
     241 [ +  - ][ -  + ]:          4 :     TEST_EQUAL(mset.get_max_possible(), 2000);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     242                 :            : 
     243                 :          4 :     return true;
     244                 :            : }
     245                 :            : 
     246         [ -  + ]:        118 : class MyDontAskWeightPostingSource : public Xapian::PostingSource {
     247                 :            :     Xapian::doccount num_docs;
     248                 :            : 
     249                 :            :     Xapian::doccount last_docid;
     250                 :            : 
     251                 :            :     Xapian::docid did;
     252                 :            : 
     253                 :         27 :     MyDontAskWeightPostingSource(Xapian::doccount num_docs_,
     254                 :            :                                  Xapian::doccount last_docid_)
     255                 :         27 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
     256                 :         27 :     { }
     257                 :            : 
     258                 :            :   public:
     259                 :         10 :     MyDontAskWeightPostingSource() : Xapian::PostingSource() {}
     260                 :            : 
     261                 :         54 :     PostingSource * clone() const { return new MyDontAskWeightPostingSource(num_docs, last_docid); }
     262                 :            : 
     263                 :         12 :     void init(const Xapian::Database &db) {
     264                 :         12 :         num_docs = db.get_doccount();
     265                 :         12 :         last_docid = db.get_lastdocid();
     266                 :         12 :         did = 0;
     267                 :         12 :     }
     268                 :            : 
     269                 :          0 :     double get_weight() const {
     270         [ #  # ]:          0 :         FAIL_TEST("MyDontAskWeightPostingSource::get_weight() called");
     271                 :            :     }
     272                 :            : 
     273                 :            :     // These bounds could be better, but that's not important here.
     274                 :         24 :     Xapian::doccount get_termfreq_min() const { return num_docs; }
     275                 :            : 
     276                 :         36 :     Xapian::doccount get_termfreq_est() const { return num_docs; }
     277                 :            : 
     278                 :         24 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
     279                 :            : 
     280                 :         39 :     void next(double wt) {
     281                 :            :         (void)wt;
     282                 :         39 :         ++did;
     283                 :         39 :     }
     284                 :            : 
     285                 :         55 :     void skip_to(Xapian::docid to_did, double wt) {
     286                 :            :         (void)wt;
     287                 :         55 :         did = to_did;
     288                 :         55 :     }
     289                 :            : 
     290                 :         94 :     bool at_end() const {
     291                 :            :         // Doesn't work if last_docid is 2^32 - 1.
     292                 :         94 :         return did > last_docid;
     293                 :            :     }
     294                 :            : 
     295                 :        184 :     Xapian::docid get_docid() const { return did; }
     296                 :            : 
     297                 :          0 :     string get_description() const {
     298         [ #  # ]:          0 :         return "MyDontAskWeightPostingSource";
     299                 :            :     }
     300                 :            : };
     301                 :            : 
     302                 :            : // Check that boolean use doesn't call get_weight().
     303                 :          5 : DEFINE_TESTCASE(externalsource4, backend && !remote) {
     304 [ +  - ][ +  - ]:          5 :     Xapian::Database db(get_database("apitest_phrase"));
     305         [ +  - ]:         10 :     Xapian::Enquire enq(db);
     306                 :         10 :     MyDontAskWeightPostingSource src;
     307                 :            : 
     308 [ +  - ][ +  - ]:          5 :     tout << "OP_SCALE_WEIGHT 0" << endl;
     309 [ +  - ][ +  - ]:          5 :     enq.set_query(Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT, Xapian::Query(&src), 0));
                 [ +  - ]
     310                 :            : 
     311         [ +  - ]:         10 :     Xapian::MSet mset = enq.get_mset(0, 5);
     312         [ +  - ]:          5 :     mset_expect_order(mset, 1, 2, 3, 4, 5);
     313                 :            : 
     314 [ +  - ][ +  - ]:          5 :     tout << "OP_FILTER" << endl;
     315                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     316                 :            :                     Xapian::Query("leav"),
     317 [ +  - ][ +  - ]:         10 :                     Xapian::Query(&src));
         [ +  - ][ +  - ]
     318         [ +  - ]:          5 :     enq.set_query(q);
     319                 :            : 
     320 [ +  - ][ +  - ]:          5 :     mset = enq.get_mset(0, 5);
     321         [ +  - ]:          5 :     mset_expect_order(mset, 8, 6, 4, 5, 7);
     322                 :            : 
     323 [ +  - ][ +  - ]:          5 :     tout << "BoolWeight" << endl;
     324 [ +  - ][ +  - ]:          5 :     enq.set_query(Xapian::Query(&src));
     325         [ +  - ]:          5 :     enq.set_weighting_scheme(Xapian::BoolWeight());
     326                 :            : 
     327                 :            :     // mset = enq.get_mset(0, 5);
     328                 :            :     // mset_expect_order(mset, 1, 2, 3, 4, 5);
     329                 :            : 
     330                 :          5 :     return true;
     331                 :            : }
     332                 :            : 
     333                 :            : // Check that valueweightsource works correctly.
     334                 :          7 : DEFINE_TESTCASE(valueweightsource1, backend) {
     335 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     336         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     337         [ +  - ]:         14 :     Xapian::ValueWeightPostingSource src(11);
     338                 :            : 
     339                 :            :     // Should be in descending order of length
     340 [ +  - ][ +  - ]:          7 :     tout << "RAW" << endl;
     341 [ +  - ][ +  - ]:          7 :     enq.set_query(Xapian::Query(&src));
     342         [ +  - ]:         14 :     Xapian::MSet mset = enq.get_mset(0, 5);
     343         [ +  - ]:          7 :     mset_expect_order(mset, 3, 1, 2, 8, 14);
     344                 :            : 
     345                 :            :     // In relevance order
     346 [ +  - ][ +  - ]:          7 :     tout << "OP_FILTER" << endl;
     347                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     348                 :            :                     Xapian::Query("leav"),
     349 [ +  - ][ +  - ]:         14 :                     Xapian::Query(&src));
         [ +  - ][ +  - ]
     350         [ +  - ]:          7 :     enq.set_query(q);
     351 [ +  - ][ +  - ]:          7 :     mset = enq.get_mset(0, 5);
     352         [ +  - ]:          7 :     mset_expect_order(mset, 8, 6, 4, 5, 7);
     353                 :            : 
     354                 :            :     // Should be in descending order of length
     355 [ +  - ][ +  - ]:          7 :     tout << "OP_FILTER other way" << endl;
     356 [ +  - ][ +  - ]:         14 :     q = Xapian::Query(Xapian::Query::OP_FILTER,
         [ +  - ][ +  - ]
     357                 :            :                       Xapian::Query(&src),
     358         [ +  - ]:          7 :                       Xapian::Query("leav"));
     359         [ +  - ]:          7 :     enq.set_query(q);
     360 [ +  - ][ +  - ]:          7 :     mset = enq.get_mset(0, 5);
     361         [ +  - ]:          7 :     mset_expect_order(mset, 8, 14, 9, 13, 7);
     362                 :            : 
     363                 :          7 :     return true;
     364                 :            : }
     365                 :            : 
     366                 :            : // Check that valueweightsource gives the correct bounds for those databases
     367                 :            : // which support value statistics.
     368                 :          7 : DEFINE_TESTCASE(valueweightsource2, valuestats) {
     369 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     370         [ +  - ]:         14 :     Xapian::ValueWeightPostingSource src(11);
     371         [ +  - ]:          7 :     src.init(db);
     372 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(src.get_termfreq_min(), 17);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     373 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(src.get_termfreq_est(), 17);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     374 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(src.get_termfreq_max(), 17);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     375 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(src.get_maxweight(), 135);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     376                 :            : 
     377                 :          7 :     return true;
     378                 :            : }
     379                 :            : 
     380                 :            : // Check that valueweightsource skip_to() can stay in the same position.
     381                 :          6 : DEFINE_TESTCASE(valueweightsource3, valuestats && !multi) {
     382                 :            :     // FIXME: multi doesn't support iterating valuestreams yet.
     383 [ +  - ][ +  - ]:          6 :     Xapian::Database db(get_database("apitest_phrase"));
     384         [ +  - ]:         12 :     Xapian::ValueWeightPostingSource src(11);
     385         [ +  - ]:          6 :     src.init(db);
     386 [ +  - ][ -  + ]:          6 :     TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     387         [ +  - ]:          6 :     src.skip_to(8, 0.0);
     388 [ +  - ][ -  + ]:          6 :     TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     389 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(src.get_docid(), 8);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     390         [ +  - ]:          6 :     src.skip_to(8, 0.0);
     391 [ +  - ][ -  + ]:          6 :     TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     392 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(src.get_docid(), 8);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     393                 :            : 
     394                 :          6 :     return true;
     395                 :            : }
     396                 :            : 
     397                 :            : // Check that fixedweightsource works correctly.
     398                 :          7 : DEFINE_TESTCASE(fixedweightsource1, backend) {
     399 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     400         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     401                 :          7 :     double wt = 5.6;
     402                 :            : 
     403                 :            :     {
     404         [ +  - ]:          7 :         Xapian::FixedWeightPostingSource src(wt);
     405                 :            : 
     406                 :            :         // Should be in increasing order of docid.
     407 [ +  - ][ +  - ]:          7 :         enq.set_query(Xapian::Query(&src));
     408         [ +  - ]:         14 :         Xapian::MSet mset = enq.get_mset(0, 5);
     409         [ +  - ]:          7 :         mset_expect_order(mset, 1, 2, 3, 4, 5);
     410                 :            : 
     411 [ +  - ][ +  - ]:         42 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
                 [ +  + ]
     412 [ +  - ][ -  + ]:         35 :             TEST_EQUAL(i.get_weight(), wt);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     413                 :         14 :         }
     414                 :            :     }
     415                 :            : 
     416                 :            :     // Do some direct tests, to check the skip_to() and check() methods work.
     417                 :            :     {
     418                 :            :         // Check next and skip_to().
     419         [ +  - ]:          7 :         Xapian::FixedWeightPostingSource src(wt);
     420         [ +  - ]:          7 :         src.init(db);
     421                 :            : 
     422         [ +  - ]:          7 :         src.next(1.0);
     423 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     424 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     425         [ +  - ]:          7 :         src.next(1.0);
     426 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     427 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     428         [ +  - ]:          7 :         src.skip_to(5, 1.0);
     429 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     430 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 5);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     431         [ +  - ]:          7 :         src.next(wt * 2);
     432 [ +  - ][ -  + ]:          7 :         TEST(src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     433                 :            :     }
     434                 :            :     {
     435                 :            :         // Check check() as the first operation, followed by next.
     436         [ +  - ]:          7 :         Xapian::FixedWeightPostingSource src(wt);
     437         [ +  - ]:          7 :         src.init(db);
     438                 :            : 
     439 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.check(5, 1.0), true);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     440 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     441 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 5);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     442         [ +  - ]:          7 :         src.next(1.0);
     443 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     444 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     445                 :            :     }
     446                 :            :     {
     447                 :            :         // Check check() as the first operation, followed by skip_to().
     448         [ +  - ]:          7 :         Xapian::FixedWeightPostingSource src(wt);
     449         [ +  - ]:          7 :         src.init(db);
     450                 :            : 
     451 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.check(5, 1.0), true);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     452 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     453 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 5);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     454         [ +  - ]:          7 :         src.skip_to(6, 1.0);
     455 [ +  - ][ -  + ]:          7 :         TEST(!src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     456 [ +  - ][ -  + ]:          7 :         TEST_EQUAL(src.get_docid(), 6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     457         [ +  - ]:          7 :         src.skip_to(7, wt * 2);
     458 [ +  - ][ -  + ]:          7 :         TEST(src.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     459                 :            :     }
     460                 :            : 
     461                 :          7 :     return true;
     462                 :            : }
     463                 :            : 
     464                 :            : // A posting source which changes the maximum weight.
     465         [ -  + ]:         16 : class ChangeMaxweightPostingSource : public Xapian::PostingSource {
     466                 :            :     Xapian::docid did;
     467                 :            : 
     468                 :            :     // Maximum docid that get_weight() should be called for.
     469                 :            :     Xapian::docid maxid_accessed;
     470                 :            : 
     471                 :            :   public:
     472                 :          8 :     ChangeMaxweightPostingSource(Xapian::docid maxid_accessed_)
     473                 :          8 :             : did(0), maxid_accessed(maxid_accessed_) { }
     474                 :            : 
     475                 :          8 :     void init(const Xapian::Database &) { did = 0; }
     476                 :            : 
     477                 :         28 :     double get_weight() const {
     478         [ -  + ]:         28 :         if (did > maxid_accessed) {
     479 [ #  # ][ #  # ]:          0 :             FAIL_TEST("ChangeMaxweightPostingSource::get_weight() called "
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     480                 :            :                       "for docid " + str(did) + ", max id accessed "
     481                 :            :                       "should be " + str(maxid_accessed));
     482                 :            :         }
     483                 :         28 :         return 5 - did;
     484                 :            :     }
     485                 :            : 
     486                 :         16 :     Xapian::doccount get_termfreq_min() const { return 4; }
     487                 :         32 :     Xapian::doccount get_termfreq_est() const { return 4; }
     488                 :         16 :     Xapian::doccount get_termfreq_max() const { return 4; }
     489                 :            : 
     490                 :         32 :     void next(double) {
     491                 :         32 :         ++did;
     492                 :         32 :         set_maxweight(5 - did);
     493                 :         32 :     }
     494                 :            : 
     495                 :          0 :     void skip_to(Xapian::docid to_did, double) {
     496                 :          0 :         did = to_did;
     497                 :          0 :         set_maxweight(5 - did);
     498                 :          0 :     }
     499                 :            : 
     500                 :         80 :     bool at_end() const { return did >= 5; }
     501                 :         64 :     Xapian::docid get_docid() const { return did; }
     502         [ #  # ]:          0 :     string get_description() const { return "ChangeMaxweightPostingSource"; }
     503                 :            : };
     504                 :            : 
     505                 :            : // Test a posting source with a variable maxweight.
     506                 :          4 : DEFINE_TESTCASE(changemaxweightsource1, backend && !remote && !multi) {
     507                 :            :     // The ChangeMaxweightPostingSource doesn't work with multi or remote.
     508 [ +  - ][ +  - ]:          4 :     Xapian::Database db(get_database("apitest_phrase"));
     509         [ +  - ]:          8 :     Xapian::Enquire enq(db);
     510                 :            : 
     511                 :            :     {
     512                 :          4 :         ChangeMaxweightPostingSource src1(5);
     513         [ +  - ]:          8 :         Xapian::FixedWeightPostingSource src2(2.5);
     514                 :            : 
     515                 :            :         Xapian::Query q(Xapian::Query::OP_AND,
     516 [ +  - ][ +  - ]:          8 :                         Xapian::Query(&src1), Xapian::Query(&src2));
                 [ +  - ]
     517         [ +  - ]:          4 :         enq.set_query(q);
     518                 :            :         // Set descending docid order so that the matcher isn't able to
     519                 :            :         // terminate early after 4 documents just because weight == maxweight.
     520         [ +  - ]:          4 :         enq.set_docid_order(enq.DESCENDING);
     521                 :            : 
     522         [ +  - ]:          8 :         Xapian::MSet mset = enq.get_mset(0, 4);
     523 [ -  + ][ #  # ]:          4 :         TEST(src1.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     524         [ +  - ]:          4 :         mset_expect_order(mset, 1, 2, 3, 4);
     525 [ +  - ][ +  - ]:         20 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
                 [ +  + ]
     526 [ +  - ][ +  - ]:         16 :             TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     527                 :          8 :         }
     528                 :            :     }
     529                 :            : 
     530                 :            :     {
     531                 :          4 :         ChangeMaxweightPostingSource src1(3);
     532         [ +  - ]:          8 :         Xapian::FixedWeightPostingSource src2(2.5);
     533                 :            : 
     534                 :            :         Xapian::Query q(Xapian::Query::OP_AND,
     535 [ +  - ][ +  - ]:          8 :                         Xapian::Query(&src1), Xapian::Query(&src2));
                 [ +  - ]
     536         [ +  - ]:          4 :         enq.set_query(q);
     537                 :            : 
     538         [ +  - ]:          8 :         Xapian::MSet mset = enq.get_mset(0, 2);
     539 [ -  + ][ #  # ]:          4 :         TEST(!src1.at_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     540 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(src1.get_docid(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     541 [ +  - ][ -  + ]:          4 :         TEST_EQUAL_DOUBLE(src1.get_maxweight(), 2.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     542         [ +  - ]:          4 :         mset_expect_order(mset, 1, 2);
     543 [ +  - ][ +  - ]:         12 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
                 [ +  + ]
     544 [ +  - ][ +  - ]:          8 :             TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     545                 :          8 :         }
     546                 :            :     }
     547                 :            : 
     548                 :          4 :     return true;
     549                 :            : }
     550                 :            : 
     551                 :            : // Test using a valueweightpostingsource which has no entries.
     552                 :          4 : DEFINE_TESTCASE(emptyvalwtsource1, backend && !remote && !multi) {
     553 [ +  - ][ +  - ]:          4 :     Xapian::Database db(get_database("apitest_phrase"));
     554         [ +  - ]:          8 :     Xapian::Enquire enq(db);
     555                 :            : 
     556         [ +  - ]:          8 :     Xapian::ValueWeightPostingSource src2(11); // A non-empty slot.
     557         [ +  - ]:          8 :     Xapian::ValueWeightPostingSource src3(100); // An empty slot.
     558 [ +  - ][ +  - ]:          8 :     Xapian::Query q1("leav");
     559         [ +  - ]:          8 :     Xapian::Query q2(&src2);
     560         [ +  - ]:          8 :     Xapian::Query q3(&src3);
     561 [ +  - ][ +  - ]:          8 :     Xapian::Query q(Xapian::Query::OP_OR, Xapian::Query(Xapian::Query::OP_AND_MAYBE, q1, q2), q3);
     562                 :            : 
     563                 :            :     // Perform search without ORring with the posting source.
     564                 :            :     Xapian::doccount size1;
     565                 :            :     {
     566         [ +  - ]:          4 :         enq.set_query(q1);
     567         [ +  - ]:          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     568 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     569         [ +  - ]:          4 :         size1 = mset.size();
     570 [ -  + ][ #  # ]:          4 :         TEST_REL(size1, >, 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     571                 :            :     }
     572                 :            : 
     573                 :            :     // Perform a search with just the non-empty posting source, checking it
     574                 :            :     // returns something.
     575                 :            :     {
     576         [ +  - ]:          4 :         enq.set_query(q2);
     577         [ +  - ]:          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     578 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     579 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.size(), >, 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     580                 :            :     }
     581                 :            : 
     582                 :            :     // Perform a search with just the empty posting source, checking it returns
     583                 :            :     // nothing.
     584                 :            :     {
     585         [ +  - ]:          4 :         enq.set_query(q3);
     586         [ +  - ]:          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     587                 :            : 
     588                 :            :         // get_max_possible() returns 0 here for backends which track the upper
     589                 :            :         // bound on value slot entries, MAX_DBL for backends which don't.
     590                 :            :         // Either is valid.
     591 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.get_max_possible(), >=, 0.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     592                 :            : 
     593 [ +  - ][ -  + ]:          4 :         TEST_EQUAL(mset.size(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     594                 :            :     }
     595                 :            : 
     596                 :            :     // Perform a search with the posting source ORred with the normal query.
     597                 :            :     // This is a regression test - it used to return nothing.
     598                 :            :     {
     599         [ +  - ]:          4 :         enq.set_query(q);
     600         [ +  - ]:          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     601 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     602 [ +  - ][ -  + ]:          4 :         TEST_REL(mset.size(), >, 0.0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     603 [ +  - ][ -  + ]:          4 :         TEST_EQUAL(mset.size(), size1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     604                 :            :     }
     605                 :            : 
     606                 :          4 :     return true;
     607                 :            : }
     608                 :            : 
     609         [ -  + ]:         44 : class SlowDecreasingValueWeightPostingSource
     610                 :            :     : public Xapian::DecreasingValueWeightPostingSource {
     611                 :            :   public:
     612                 :            :     int & count;
     613                 :            : 
     614                 :         13 :     SlowDecreasingValueWeightPostingSource(int & count_)
     615                 :         13 :         : Xapian::DecreasingValueWeightPostingSource(0), count(count_) { }
     616                 :            : 
     617                 :          9 :     SlowDecreasingValueWeightPostingSource * clone() const
     618                 :            :     {
     619         [ +  - ]:          9 :         return new SlowDecreasingValueWeightPostingSource(count);
     620                 :            :     }
     621                 :            : 
     622                 :          8 :     void next(double min_wt) {
     623                 :          8 :         sleep(1);
     624                 :          8 :         ++count;
     625                 :          8 :         return Xapian::DecreasingValueWeightPostingSource::next(min_wt);
     626                 :            :     }
     627                 :            : };
     628                 :            : 
     629                 :            : static void
     630                 :          4 : make_matchtimelimit1_db(Xapian::WritableDatabase &db, const string &)
     631                 :            : {
     632         [ +  + ]:         84 :     for (int wt = 20; wt > 0; --wt) {
     633         [ +  - ]:         80 :         Xapian::Document doc;
     634 [ +  - ][ +  - ]:         80 :         doc.add_value(0, Xapian::sortable_serialise(double(wt)));
     635         [ +  - ]:         80 :         db.add_document(doc);
     636                 :         80 :     }
     637                 :          4 : }
     638                 :            : 
     639                 :            : // FIXME: This doesn't run for remote databases (we'd need to register
     640                 :            : // SlowDecreasingValueWeightPostingSource on the remote).
     641                 :          4 : DEFINE_TESTCASE(matchtimelimit1, generated && !remote)
     642                 :            : {
     643                 :            : #ifndef HAVE_TIMER_CREATE
     644                 :            :     SKIP_TEST("Enquire::set_time_limit() not implemented for this platform");
     645                 :            : #endif
     646                 :            :     Xapian::Database db = get_database("matchtimelimit1",
     647 [ +  - ][ +  - ]:          4 :                                        make_matchtimelimit1_db);
                 [ +  - ]
     648                 :            : 
     649                 :          4 :     int count = 0;
     650         [ +  - ]:          8 :     SlowDecreasingValueWeightPostingSource src(count);
     651         [ +  - ]:          4 :     src.init(db);
     652         [ +  - ]:          8 :     Xapian::Enquire enquire(db);
     653 [ +  - ][ +  - ]:          4 :     enquire.set_query(Xapian::Query(&src));
     654                 :            : 
     655         [ +  - ]:          4 :     enquire.set_time_limit(1.5);
     656                 :            : 
     657         [ +  - ]:          8 :     Xapian::MSet mset = enquire.get_mset(0, 1, 1000);
     658 [ +  - ][ -  + ]:          4 :     TEST_EQUAL(mset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     659 [ -  + ][ #  # ]:          4 :     TEST_EQUAL(count, 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     660                 :            : 
     661                 :          4 :     return true;
     662                 :            : }
     663                 :            : 
     664         [ -  + ]:         54 : class CheckBoundsPostingSource
     665                 :            :     : public Xapian::DecreasingValueWeightPostingSource {
     666                 :            :   public:
     667                 :            :     Xapian::doccount& doclen_lb;
     668                 :            : 
     669                 :            :     Xapian::doccount& doclen_ub;
     670                 :            : 
     671                 :         16 :     CheckBoundsPostingSource(Xapian::doccount& doclen_lb_,
     672                 :            :                              Xapian::doccount& doclen_ub_)
     673                 :            :         : Xapian::DecreasingValueWeightPostingSource(0),
     674                 :            :           doclen_lb(doclen_lb_),
     675                 :         16 :           doclen_ub(doclen_ub_) { }
     676                 :            : 
     677                 :         11 :     CheckBoundsPostingSource * clone() const
     678                 :            :     {
     679         [ +  - ]:         11 :         return new CheckBoundsPostingSource(doclen_lb, doclen_ub);
     680                 :            :     }
     681                 :            : 
     682                 :          6 :     void init(const Xapian::Database& database) {
     683                 :          6 :         doclen_lb = database.get_doclength_lower_bound();
     684                 :          6 :         doclen_ub = database.get_doclength_upper_bound();
     685                 :          6 :         Xapian::DecreasingValueWeightPostingSource::init(database);
     686                 :          6 :     }
     687                 :            : };
     688                 :            : 
     689                 :            : // Test that doclength bounds are correct.
     690                 :            : // Regression test for bug fixed in 1.2.25 and 1.4.1.
     691                 :          5 : DEFINE_TESTCASE(postingsourcebounds1, backend && !remote)
     692                 :            : {
     693 [ +  - ][ +  - ]:          5 :     Xapian::Database db = get_database("apitest_simpledata");
     694                 :            : 
     695                 :          5 :     Xapian::doccount doclen_lb = 0, doclen_ub = 0;
     696         [ +  - ]:         10 :     CheckBoundsPostingSource ps(doclen_lb, doclen_ub);
     697                 :            : 
     698         [ +  - ]:         10 :     Xapian::Enquire enquire(db);
     699 [ +  - ][ +  - ]:          5 :     enquire.set_query(Xapian::Query(&ps));
     700                 :            : 
     701         [ +  - ]:         10 :     Xapian::MSet mset = enquire.get_mset(0, 1);
     702                 :            : 
     703 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(doclen_lb, db.get_doclength_lower_bound());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     704 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(doclen_ub, db.get_doclength_upper_bound());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     705                 :            : 
     706                 :          5 :     return true;
     707                 :            : }
     708                 :            : 
     709                 :            : // PostingSource which really just counts the clone() calls.
     710                 :            : // Never actually matches anything, but pretends it might.
     711         [ -  + ]:         10 : class CloneTestPostingSource : public Xapian::PostingSource {
     712                 :            :     int& clone_count;
     713                 :            : 
     714                 :            :   public:
     715                 :          3 :     CloneTestPostingSource(int& clone_count_)
     716                 :          3 :         : clone_count(clone_count_)
     717                 :          3 :     { }
     718                 :            : 
     719                 :          1 :     PostingSource * clone() const {
     720                 :          1 :         ++clone_count;
     721                 :          1 :         return new CloneTestPostingSource(clone_count);
     722                 :            :     }
     723                 :            : 
     724                 :          0 :     void init(const Xapian::Database&) { }
     725                 :            : 
     726                 :          0 :     Xapian::doccount get_termfreq_min() const { return 0; }
     727                 :            : 
     728                 :          0 :     Xapian::doccount get_termfreq_est() const { return 1; }
     729                 :            : 
     730                 :          0 :     Xapian::doccount get_termfreq_max() const { return 2; }
     731                 :            : 
     732                 :          0 :     void next(double) { }
     733                 :            : 
     734                 :          0 :     void skip_to(Xapian::docid, double) { }
     735                 :            : 
     736                 :          0 :     bool at_end() const {
     737                 :          0 :         return true;
     738                 :            :     }
     739                 :            : 
     740                 :          0 :     Xapian::docid get_docid() const { return 0; }
     741                 :            : 
     742         [ #  # ]:          0 :     string get_description() const { return "CloneTestPostingSource"; }
     743                 :            : };
     744                 :            : 
     745                 :            : /// Test cloning of initial object, which regressed in 1.3.5.
     746                 :          1 : DEFINE_TESTCASE(postingsourceclone1, !backend)
     747                 :            : {
     748                 :            :     // This fails with 1.3.5-1.4.0 inclusive.
     749                 :            :     {
     750                 :          1 :         int clones = 0;
     751                 :          1 :         CloneTestPostingSource ps(clones);
     752 [ -  + ][ #  # ]:          1 :         TEST_EQUAL(clones, 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     753         [ +  - ]:          2 :         Xapian::Query q(&ps);
     754 [ -  + ][ #  # ]:          2 :         TEST_EQUAL(clones, 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     755                 :            :     }
     756                 :            : 
     757                 :            :     // Check that clone() isn't needlessly called if reference counting has
     758                 :            :     // been turned on for the PostingSource.
     759                 :            :     {
     760                 :          1 :         int clones = 0;
     761         [ +  - ]:          1 :         CloneTestPostingSource* ps = new CloneTestPostingSource(clones);
     762 [ -  + ][ #  # ]:          1 :         TEST_EQUAL(clones, 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     763         [ +  - ]:          1 :         Xapian::Query q(ps->release());
     764 [ -  + ][ #  # ]:          1 :         TEST_EQUAL(clones, 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     765                 :            :     }
     766                 :            : 
     767                 :          1 :     return true;
     768                 :            : }
     769                 :            : 
     770         [ -  + ]:         12 : class OnlyTheFirstPostingSource : public Xapian::PostingSource {
     771                 :            :     Xapian::doccount last_docid;
     772                 :            : 
     773                 :            :     Xapian::docid did;
     774                 :            : 
     775                 :            :   public:
     776                 :          6 :     OnlyTheFirstPostingSource() {}
     777                 :            : 
     778                 :          4 :     PostingSource * clone() const { return new OnlyTheFirstPostingSource(); }
     779                 :            : 
     780                 :          2 :     void reset(const Xapian::Database& db, Xapian::doccount shard_index) {
     781                 :          2 :         did = 0;
     782         [ +  + ]:          2 :         if (shard_index == 0) {
     783                 :          1 :             last_docid = db.get_lastdocid();
     784                 :            :         } else {
     785                 :          1 :             last_docid = 0;
     786                 :            :         }
     787                 :          2 :     }
     788                 :            : 
     789                 :          4 :     Xapian::doccount get_termfreq_min() const { return 0; }
     790                 :            : 
     791                 :          4 :     Xapian::doccount get_termfreq_est() const { return last_docid / 2; }
     792                 :            : 
     793                 :          4 :     Xapian::doccount get_termfreq_max() const { return last_docid; }
     794                 :            : 
     795                 :          5 :     void next(double wt) {
     796                 :            :         (void)wt;
     797                 :          5 :         ++did;
     798         [ +  + ]:          5 :         if (did > last_docid) did = 0;
     799                 :          5 :     }
     800                 :            : 
     801                 :          0 :     void skip_to(Xapian::docid to_did, double wt) {
     802                 :            :         (void)wt;
     803                 :          0 :         did = to_did;
     804         [ #  # ]:          0 :         if (did > last_docid) did = 0;
     805                 :          0 :     }
     806                 :            : 
     807                 :          5 :     bool at_end() const {
     808                 :          5 :         return did == 0;
     809                 :            :     }
     810                 :            : 
     811                 :          6 :     Xapian::docid get_docid() const { return did; }
     812                 :            : 
     813         [ #  # ]:          0 :     string get_description() const { return "OnlyTheFirstPostingSource"; }
     814                 :            : };
     815                 :            : 
     816                 :          1 : DEFINE_TESTCASE(postingsourceshardindex1, multi) {
     817 [ +  - ][ +  - ]:          1 :     Xapian::Database db = get_database("apitest_simpledata");
     818                 :            : 
     819         [ +  - ]:          2 :     Xapian::Enquire enquire(db);
     820         [ +  - ]:          1 :     auto ps = new OnlyTheFirstPostingSource;
     821 [ +  - ][ +  - ]:          1 :     enquire.set_query(Xapian::Query(ps->release()));
     822                 :            : 
     823         [ +  - ]:          2 :     Xapian::MSet mset = enquire.get_mset(0, 10);
     824         [ +  - ]:          1 :     mset_expect_order(mset, 1, 3, 5);
     825                 :            : 
     826                 :          1 :     return true;
     827                 :            : }

Generated by: LCOV version 1.11