LCOV - code coverage report
Current view: top level - home/olly/git/atia-xapian/xapian-core/tests - api_postingsource.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 294 307 95.8 %
Date: 2011-08-21 Functions: 60 67 89.6 %
Branches: 79 258 30.6 %

           Branch data     Line data    Source code
       1                 :            : /* api_postingsource.cc: tests of posting sources
       2                 :            :  *
       3                 :            :  * Copyright 2008,2009 Olly Betts
       4                 :            :  * Copyright 2008,2009 Lemur Consulting Ltd
       5                 :            :  * Copyright 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_postingsource.h"
      26                 :            : 
      27                 :            : #include <xapian.h>
      28                 :            : 
      29                 :            : #include <string>
      30                 :            : 
      31                 :            : #include "testutils.h"
      32                 :            : #include "str.h"
      33                 :            : #include "apitest.h"
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : 
      37 [ +  - ][ -  + ]:         48 : class MyOddPostingSource : public Xapian::PostingSource {
      38                 :            :     Xapian::doccount num_docs;
      39                 :            : 
      40                 :            :     Xapian::doccount last_docid;
      41                 :            : 
      42                 :            :     Xapian::docid did;
      43                 :            : 
      44                 :         38 :     MyOddPostingSource(Xapian::doccount num_docs_,
      45                 :            :                        Xapian::doccount last_docid_)
      46                 :         38 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
      47                 :         38 :     { }
      48                 :            : 
      49                 :            :   public:
      50                 :         10 :     MyOddPostingSource(const Xapian::Database &db)
      51                 :         10 :         : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
      52                 :         10 :     { }
      53                 :            : 
      54                 :         38 :     PostingSource * clone() const { return new MyOddPostingSource(num_docs, last_docid); }
      55                 :            : 
      56                 :          8 :     void init(const Xapian::Database &) { did = 0; }
      57                 :            : 
      58                 :            :     // These bounds could be better, but that's not important here.
      59                 :          8 :     Xapian::doccount get_termfreq_min() const { return 0; }
      60                 :            : 
      61                 :         12 :     Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
      62                 :            : 
      63                 :          8 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
      64                 :            : 
      65                 :         64 :     void next(Xapian::weight wt) {
      66                 :            :         (void)wt;
      67                 :         64 :         ++did;
      68         [ +  + ]:         64 :         if (did % 2 == 0) ++did;
      69                 :         64 :     }
      70                 :            : 
      71                 :          4 :     void skip_to(Xapian::docid to_did, Xapian::weight wt) {
      72                 :            :         (void)wt;
      73                 :          4 :         did = to_did;
      74         [ +  - ]:          4 :         if (did % 2 == 0) ++did;
      75                 :          4 :     }
      76                 :            : 
      77                 :         68 :     bool at_end() const {
      78                 :            :         // Doesn't work if last_docid is 2^32 - 1.
      79                 :         68 :         return did > last_docid;
      80                 :            :     }
      81                 :            : 
      82                 :         64 :     Xapian::docid get_docid() const { return did; }
      83                 :            : 
      84                 :          0 :     string get_description() const { return "MyOddPostingSource"; }
      85                 :            : };
      86                 :            : 
      87                 :          4 : DEFINE_TESTCASE(externalsource1, backend && !remote && !multi) {
      88                 :            :     // Doesn't work for remote without registering with the server.
      89                 :            :     // Doesn't work for multi because it checks the docid in the
      90                 :            :     // subdatabase.
      91                 :          4 :     Xapian::Database db(get_database("apitest_phrase"));
      92                 :          4 :     Xapian::Enquire enq(db);
      93                 :          4 :     MyOddPostingSource src(db);
      94                 :            : 
      95                 :            :     // Check that passing NULL is rejected as intended.
      96 [ +  - ][ -  + ]:          8 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(NULL));
         [ #  # ][ -  + ]
      97                 :          4 :     Xapian::PostingSource * nullsrc = NULL;
      98 [ +  - ][ -  + ]:          8 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(nullsrc));
         [ #  # ][ -  + ]
      99                 :            :                 
     100                 :          4 :     enq.set_query(Xapian::Query(&src));
     101                 :            : 
     102                 :          4 :     Xapian::MSet mset = enq.get_mset(0, 10);
     103                 :          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
     104                 :            : 
     105                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     106                 :            :                     Xapian::Query("leav"),
     107                 :          4 :                     Xapian::Query(&src));
     108                 :          4 :     enq.set_query(q);
     109                 :            : 
     110                 :          4 :     mset = enq.get_mset(0, 10);
     111                 :          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     112                 :            : 
     113                 :          4 :     return true;
     114                 :            : }
     115                 :            : 
     116                 :            : // Test that trying to use PostingSource with the remote backend throws
     117                 :            : // Xapian::UnimplementedError as expected (we need to register the class
     118                 :            : // in xapian-tcpsrv/xapian-progsrv for this to work).
     119                 :          6 : DEFINE_TESTCASE(externalsource2, remote) {
     120                 :          6 :     Xapian::Database db(get_database("apitest_phrase"));
     121                 :          6 :     Xapian::Enquire enq(db);
     122                 :          6 :     MyOddPostingSource src(db);
     123                 :            : 
     124                 :          6 :     enq.set_query(Xapian::Query(&src));
     125                 :            : 
     126 [ +  - ][ -  + ]:         12 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ -  + ]
     127                 :            :                    Xapian::MSet mset = enq.get_mset(0, 10));
     128                 :            : 
     129                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     130                 :            :                     Xapian::Query("leav"),
     131                 :          6 :                     Xapian::Query(&src));
     132                 :          6 :     enq.set_query(q);
     133                 :            : 
     134 [ +  - ][ -  + ]:         12 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ -  + ]
     135                 :            :                    Xapian::MSet mset = enq.get_mset(0, 10));
     136                 :            : 
     137                 :          6 :     return true;
     138                 :            : }
     139                 :            : 
     140 [ +  - ][ -  + ]:         52 : class MyOddWeightingPostingSource : public Xapian::PostingSource {
     141                 :            :     Xapian::doccount num_docs;
     142                 :            : 
     143                 :            :     Xapian::doccount last_docid;
     144                 :            : 
     145                 :            :     Xapian::docid did;
     146                 :            : 
     147                 :         48 :     MyOddWeightingPostingSource(Xapian::doccount num_docs_,
     148                 :            :                                 Xapian::doccount last_docid_)
     149                 :         48 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
     150                 :            :     {
     151                 :         48 :         set_maxweight(1000);
     152                 :         48 :     }
     153                 :            : 
     154                 :            :   public:
     155                 :          4 :     MyOddWeightingPostingSource(const Xapian::Database &db)
     156                 :          4 :         : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
     157                 :          4 :     { }
     158                 :            : 
     159                 :         48 :     PostingSource * clone() const {
     160                 :         48 :         return new MyOddWeightingPostingSource(num_docs, last_docid);
     161                 :            :     }
     162                 :            : 
     163                 :         20 :     void init(const Xapian::Database &) { did = 0; }
     164                 :            : 
     165                 :        304 :     Xapian::weight get_weight() const {
     166         [ +  + ]:        304 :         return (did % 2) ? 1000 : 0.001;
     167                 :            :     }
     168                 :            : 
     169                 :            :     // These bounds could be better, but that's not important here.
     170                 :         20 :     Xapian::doccount get_termfreq_min() const { return 0; }
     171                 :            : 
     172                 :         32 :     Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
     173                 :            : 
     174                 :         20 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
     175                 :            : 
     176                 :        316 :     void next(Xapian::weight wt) {
     177                 :            :         (void)wt;
     178                 :        316 :         ++did;
     179                 :        316 :     }
     180                 :            : 
     181                 :         12 :     void skip_to(Xapian::docid to_did, Xapian::weight wt) {
     182                 :            :         (void)wt;
     183                 :         12 :         did = to_did;
     184                 :         12 :     }
     185                 :            : 
     186                 :        328 :     bool at_end() const {
     187                 :            :         // Doesn't work if last_docid is 2^32 - 1.
     188                 :        328 :         return did > last_docid;
     189                 :            :     }
     190                 :            : 
     191                 :        316 :     Xapian::docid get_docid() const { return did; }
     192                 :            : 
     193                 :          0 :     string get_description() const {
     194                 :          0 :         return "MyOddWeightingPostingSource";
     195                 :            :     }
     196                 :            : };
     197                 :            : 
     198                 :            : // Like externalsource1, except we use the weight to favour odd documents.
     199                 :          4 : DEFINE_TESTCASE(externalsource3, backend && !remote && !multi) {
     200                 :            :     // Doesn't work for remote without registering with the server.
     201                 :            :     // Doesn't work for multi because it checks the docid in the
     202                 :            :     // subdatabase.
     203                 :          4 :     Xapian::Database db(get_database("apitest_phrase"));
     204                 :          4 :     Xapian::Enquire enq(db);
     205                 :          4 :     MyOddWeightingPostingSource src(db);
     206                 :            : 
     207                 :          4 :     enq.set_query(Xapian::Query(&src));
     208                 :            : 
     209                 :          4 :     Xapian::MSet mset = enq.get_mset(0, 10);
     210                 :          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17, 2);
     211                 :            : 
     212                 :            :     Xapian::Query q(Xapian::Query::OP_OR,
     213                 :            :                     Xapian::Query("leav"),
     214                 :          4 :                     Xapian::Query(&src));
     215                 :          4 :     enq.set_query(q);
     216                 :            : 
     217                 :          4 :     mset = enq.get_mset(0, 5);
     218                 :          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     219                 :            : 
     220                 :          4 :     tout << "max possible weight = " << mset.get_max_possible() << endl;
     221   [ -  +  #  # ]:          4 :     TEST(mset.get_max_possible() > 1000);
     222                 :            : 
     223                 :          4 :     enq.set_cutoff(0, 1000.001);
     224                 :          4 :     mset = enq.get_mset(0, 10);
     225                 :          4 :     mset_expect_order(mset, 5, 7, 11, 13, 9);
     226                 :            : 
     227                 :          4 :     tout << "max possible weight = " << mset.get_max_possible() << endl;
     228   [ -  +  #  # ]:          4 :     TEST(mset.get_max_possible() > 1000);
     229                 :            : 
     230                 :          4 :     enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 0.5));
     231                 :          4 :     mset = enq.get_mset(0, 10);
     232   [ -  +  #  # ]:          4 :     TEST(mset.empty());
     233                 :            : 
     234 [ -  + ][ #  # ]:          4 :     TEST_EQUAL(mset.get_max_possible(), 500);
     235                 :            : 
     236                 :          4 :     enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 2));
     237                 :          4 :     mset = enq.get_mset(0, 10);
     238                 :          4 :     mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
     239                 :            : 
     240   [ -  +  #  # ]:          4 :     TEST_EQUAL(mset.get_max_possible(), 2000);
     241                 :            : 
     242                 :          4 :     return true;
     243                 :            : }
     244                 :            : 
     245 [ +  - ][ -  + ]:         62 : class MyDontAskWeightPostingSource : public Xapian::PostingSource {
     246                 :            :     Xapian::doccount num_docs;
     247                 :            : 
     248                 :            :     Xapian::doccount last_docid;
     249                 :            : 
     250                 :            :     Xapian::docid did;
     251                 :            : 
     252                 :         55 :     MyDontAskWeightPostingSource(Xapian::doccount num_docs_,
     253                 :            :                                  Xapian::doccount last_docid_)
     254                 :         55 :         : num_docs(num_docs_), last_docid(last_docid_), did(0)
     255                 :         55 :     { }
     256                 :            : 
     257                 :            :   public:
     258                 :          7 :     MyDontAskWeightPostingSource() : Xapian::PostingSource() {}
     259                 :            : 
     260                 :         55 :     PostingSource * clone() const { return new MyDontAskWeightPostingSource(num_docs, last_docid); }
     261                 :            : 
     262                 :         20 :     void init(const Xapian::Database &db) {
     263                 :         20 :         num_docs = db.get_doccount();
     264                 :         20 :         last_docid = db.get_lastdocid();
     265                 :         20 :         did = 0;
     266                 :         20 :     }
     267                 :            : 
     268                 :          0 :     Xapian::weight get_weight() const {
     269         [ #  # ]:          0 :         FAIL_TEST("MyDontAskWeightPostingSource::get_weight() called");
     270                 :            :     }
     271                 :            : 
     272                 :            :     // These bounds could be better, but that's not important here.
     273                 :         20 :     Xapian::doccount get_termfreq_min() const { return num_docs; }
     274                 :            : 
     275                 :         30 :     Xapian::doccount get_termfreq_est() const { return num_docs; }
     276                 :            : 
     277                 :         20 :     Xapian::doccount get_termfreq_max() const { return num_docs; }
     278                 :            : 
     279                 :         77 :     void next(Xapian::weight wt) {
     280                 :            :         (void)wt;
     281                 :         77 :         ++did;
     282                 :         77 :     }
     283                 :            : 
     284                 :         77 :     void skip_to(Xapian::docid to_did, Xapian::weight wt) {
     285                 :            :         (void)wt;
     286                 :         77 :         did = to_did;
     287                 :         77 :     }
     288                 :            : 
     289                 :        154 :     bool at_end() const {
     290                 :            :         // Doesn't work if last_docid is 2^32 - 1.
     291                 :        154 :         return did > last_docid;
     292                 :            :     }
     293                 :            : 
     294                 :        148 :     Xapian::docid get_docid() const { return did; }
     295                 :            : 
     296                 :          0 :     string get_description() const {
     297                 :          0 :         return "MyDontAskWeightPostingSource";
     298                 :            :     }
     299                 :            : };
     300                 :            : 
     301                 :            : // Check that boolean use doesn't call get_weight().
     302                 :          7 : DEFINE_TESTCASE(externalsource4, backend && !remote) {
     303                 :          7 :     Xapian::Database db(get_database("apitest_phrase"));
     304                 :          7 :     Xapian::Enquire enq(db);
     305                 :          7 :     MyDontAskWeightPostingSource src;
     306                 :            : 
     307                 :          7 :     tout << "OP_SCALE_WEIGHT 0" << endl;
     308                 :          7 :     enq.set_query(Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT, Xapian::Query(&src), 0));
     309                 :            : 
     310                 :          7 :     Xapian::MSet mset = enq.get_mset(0, 5);
     311                 :          7 :     mset_expect_order(mset, 1, 2, 3, 4, 5);
     312                 :            : 
     313                 :          7 :     tout << "OP_FILTER" << endl;
     314                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     315                 :            :                     Xapian::Query("leav"),
     316                 :          7 :                     Xapian::Query(&src));
     317                 :          7 :     enq.set_query(q);
     318                 :            : 
     319                 :          7 :     mset = enq.get_mset(0, 5);
     320                 :          7 :     mset_expect_order(mset, 8, 6, 4, 5, 7);
     321                 :            : 
     322                 :          7 :     tout << "BoolWeight" << endl;
     323                 :          7 :     enq.set_query(Xapian::Query(&src));
     324                 :          7 :     enq.set_weighting_scheme(Xapian::BoolWeight());
     325                 :            : 
     326                 :            :     //mset = enq.get_mset(0, 5);
     327                 :            :     //mset_expect_order(mset, 1, 2, 3, 4, 5);
     328                 :            : 
     329                 :          7 :     return true;
     330                 :            : }
     331                 :            : 
     332                 :            : // Check that valueweightsource works correctly.
     333                 :         13 : DEFINE_TESTCASE(valueweightsource1, backend) {
     334                 :         13 :     Xapian::Database db(get_database("apitest_phrase"));
     335                 :         13 :     Xapian::Enquire enq(db);
     336                 :         13 :     Xapian::ValueWeightPostingSource src(11);
     337                 :            : 
     338                 :            :     // Should be in descending order of length
     339                 :         13 :     tout << "RAW" << endl;
     340                 :         13 :     enq.set_query(Xapian::Query(&src));
     341                 :         13 :     Xapian::MSet mset = enq.get_mset(0, 5);
     342                 :         13 :     mset_expect_order(mset, 3, 1, 2, 8, 14);
     343                 :            : 
     344                 :            :     // In relevance order
     345                 :         13 :     tout << "OP_FILTER" << endl;
     346                 :            :     Xapian::Query q(Xapian::Query::OP_FILTER,
     347                 :            :                     Xapian::Query("leav"),
     348                 :         13 :                     Xapian::Query(&src));
     349                 :         13 :     enq.set_query(q);
     350                 :         13 :     mset = enq.get_mset(0, 5);
     351                 :         13 :     mset_expect_order(mset, 8, 6, 4, 5, 7);
     352                 :            : 
     353                 :            :     // Should be in descending order of length
     354                 :         13 :     tout << "OP_FILTER other way" << endl;
     355                 :            :     q = Xapian::Query(Xapian::Query::OP_FILTER,
     356                 :            :                       Xapian::Query(&src),
     357                 :         13 :                       Xapian::Query("leav"));
     358                 :         13 :     enq.set_query(q);
     359                 :         13 :     mset = enq.get_mset(0, 5);
     360                 :         13 :     mset_expect_order(mset, 8, 14, 9, 13, 7);
     361                 :            : 
     362                 :         13 :     return true;
     363                 :            : }
     364                 :            : 
     365                 :            : // Check that valueweightsource gives the correct bounds for those databases
     366                 :            : // which support value statistics.
     367                 :          9 : DEFINE_TESTCASE(valueweightsource2, valuestats) {
     368                 :          9 :     Xapian::Database db(get_database("apitest_phrase"));
     369                 :          9 :     Xapian::ValueWeightPostingSource src(11);
     370                 :          9 :     src.init(db);
     371   [ -  +  #  # ]:          9 :     TEST_EQUAL(src.get_termfreq_min(), 17);
     372 [ -  + ][ #  # ]:          9 :     TEST_EQUAL(src.get_termfreq_est(), 17);
     373 [ -  + ][ #  # ]:          9 :     TEST_EQUAL(src.get_termfreq_max(), 17);
     374 [ -  + ][ #  # ]:          9 :     TEST_EQUAL(src.get_maxweight(), 135);
     375                 :            : 
     376                 :          9 :     return true;
     377                 :            : }
     378                 :            : 
     379                 :            : // Check that valueweightsource skip_to() can stay in the same position.
     380                 :          7 : DEFINE_TESTCASE(valueweightsource3, valuestats && !multi) {
     381                 :            :     // FIXME: multi doesn't support iterating valuestreams yet.
     382                 :          7 :     Xapian::Database db(get_database("apitest_phrase"));
     383                 :          7 :     Xapian::ValueWeightPostingSource src(11);
     384                 :          7 :     src.init(db);
     385   [ -  +  #  # ]:          7 :     TEST(!src.at_end());
     386                 :          7 :     src.skip_to(8, 0.0);
     387   [ -  +  #  # ]:          7 :     TEST(!src.at_end());
     388 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(src.get_docid(), 8);
     389                 :          7 :     src.skip_to(8, 0.0);
     390   [ -  +  #  # ]:          7 :     TEST(!src.at_end());
     391 [ -  + ][ #  # ]:          7 :     TEST_EQUAL(src.get_docid(), 8);
     392                 :            : 
     393                 :          7 :     return true;
     394                 :            : }
     395                 :            : 
     396                 :            : // Check that fixedweightsource works correctly.
     397                 :         13 : DEFINE_TESTCASE(fixedweightsource1, backend) {
     398                 :         13 :     Xapian::Database db(get_database("apitest_phrase"));
     399                 :         13 :     Xapian::Enquire enq(db);
     400                 :         13 :     double wt = 5.6;
     401                 :            : 
     402                 :            :     {
     403                 :         13 :         Xapian::FixedWeightPostingSource src(wt);
     404                 :            : 
     405                 :            :         // Should be in increasing order of docid.
     406                 :         13 :         enq.set_query(Xapian::Query(&src));
     407                 :         13 :         Xapian::MSet mset = enq.get_mset(0, 5);
     408                 :         13 :         mset_expect_order(mset, 1, 2, 3, 4, 5);
     409                 :            : 
     410         [ +  + ]:         78 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
     411 [ -  + ][ #  # ]:         65 :             TEST_EQUAL(i.get_weight(), wt);
     412                 :         13 :         }
     413                 :            :     }
     414                 :            : 
     415                 :            :     // Do some direct tests, to check the skip_to() and check() methods work.
     416                 :            :     {
     417                 :            :         // Check next and skip_to().
     418                 :         13 :         Xapian::FixedWeightPostingSource src(wt);
     419                 :         13 :         src.init(db);
     420                 :            : 
     421                 :         13 :         src.next(1.0);
     422   [ -  +  #  # ]:         13 :         TEST(!src.at_end());
     423 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 1);
     424                 :         13 :         src.next(1.0);
     425   [ -  +  #  # ]:         13 :         TEST(!src.at_end());
     426 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 2);
     427                 :         13 :         src.skip_to(5, 1.0);
     428   [ -  +  #  # ]:         13 :         TEST(!src.at_end());
     429 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 5);
     430                 :         13 :         src.next(wt * 2);
     431   [ -  +  #  # ]:         13 :         TEST(src.at_end());
     432                 :            :     }
     433                 :            :     {
     434                 :            :         // Check check() as the first operation, followed by next.
     435                 :         13 :         Xapian::FixedWeightPostingSource src(wt);
     436                 :         13 :         src.init(db);
     437                 :            : 
     438   [ -  +  #  # ]:         13 :         TEST_EQUAL(src.check(5, 1.0), true);
     439 [ -  + ][ #  # ]:         13 :         TEST(!src.at_end());
     440 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 5);
     441                 :         13 :         src.next(1.0);
     442   [ -  +  #  # ]:         13 :         TEST(!src.at_end());
     443 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 6);
     444                 :            :     }
     445                 :            :     {
     446                 :            :         // Check check() as the first operation, followed by skip_to().
     447                 :         13 :         Xapian::FixedWeightPostingSource src(wt);
     448                 :         13 :         src.init(db);
     449                 :            : 
     450   [ -  +  #  # ]:         13 :         TEST_EQUAL(src.check(5, 1.0), true);
     451 [ -  + ][ #  # ]:         13 :         TEST(!src.at_end());
     452 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 5);
     453                 :         13 :         src.skip_to(6, 1.0);
     454   [ -  +  #  # ]:         13 :         TEST(!src.at_end());
     455 [ -  + ][ #  # ]:         13 :         TEST_EQUAL(src.get_docid(), 6);
     456                 :         13 :         src.skip_to(7, wt * 2);
     457   [ -  +  #  # ]:         13 :         TEST(src.at_end());
     458                 :            :     }
     459                 :            : 
     460                 :         13 :     return true;
     461                 :            : }
     462                 :            : 
     463                 :            : // A posting source which changes the maximum weight.
     464 [ #  # ][ -  + ]:          8 : class ChangeMaxweightPostingSource : public Xapian::PostingSource {
     465                 :            :     Xapian::docid did;
     466                 :            : 
     467                 :            :     // Maximum docid that get_weight() should be called for.
     468                 :            :     Xapian::docid maxid_accessed;
     469                 :            : 
     470                 :            :   public:
     471                 :          8 :     ChangeMaxweightPostingSource(Xapian::docid maxid_accessed_)
     472                 :          8 :             : did(0), maxid_accessed(maxid_accessed_) { }
     473                 :            : 
     474                 :          8 :     void init(const Xapian::Database &) { did = 0; }
     475                 :            : 
     476                 :         28 :     Xapian::weight get_weight() const {
     477         [ -  + ]:         28 :         if (did > maxid_accessed) {
     478         [ #  # ]:          0 :             FAIL_TEST("ChangeMaxweightPostingSource::get_weight() called "
     479                 :            :                       "for docid " + str(did) + ", max id accessed "
     480                 :            :                       "should be " + str(maxid_accessed));
     481                 :            :         }
     482                 :         28 :         return 5 - did;
     483                 :            :     }
     484                 :            : 
     485                 :          8 :     Xapian::doccount get_termfreq_min() const { return 4; }
     486                 :         16 :     Xapian::doccount get_termfreq_est() const { return 4; }
     487                 :          8 :     Xapian::doccount get_termfreq_max() const { return 4; }
     488                 :            : 
     489                 :         32 :     void next(Xapian::weight) {
     490                 :         32 :         ++did;
     491                 :         32 :         set_maxweight(5 - did);
     492                 :         32 :     }
     493                 :            : 
     494                 :          0 :     void skip_to(Xapian::docid to_did, Xapian::weight) {
     495                 :          0 :         did = to_did;
     496                 :          0 :         set_maxweight(5 - did);
     497                 :          0 :     }
     498                 :            : 
     499                 :         40 :     bool at_end() const { return did >= 5; }
     500                 :         32 :     Xapian::docid get_docid() const { return did; }
     501                 :          0 :     string get_description() const { return "ChangeMaxweightPostingSource"; }
     502                 :            : };
     503                 :            : 
     504                 :            : // Test a posting source with a variable maxweight.
     505                 :          4 : DEFINE_TESTCASE(changemaxweightsource1, backend && !remote && !multi) {
     506                 :            :     // The ChangeMaxweightPostingSource doesn't work with multi or remote.
     507                 :          4 :     Xapian::Database db(get_database("apitest_phrase"));
     508                 :          4 :     Xapian::Enquire enq(db);
     509                 :            : 
     510                 :            :     {
     511                 :          4 :         ChangeMaxweightPostingSource src1(5);
     512                 :          4 :         Xapian::FixedWeightPostingSource src2(2.5);
     513                 :            : 
     514                 :            :         Xapian::Query q(Xapian::Query::OP_AND,
     515                 :          4 :                         Xapian::Query(&src1), Xapian::Query(&src2));
     516                 :          4 :         enq.set_query(q);
     517                 :            :         // Set descending docid order so that the matcher isn't able to
     518                 :            :         // terminate early after 4 documents just because weight == maxweight.
     519                 :          4 :         enq.set_docid_order(enq.DESCENDING);
     520                 :            : 
     521                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 4);
     522   [ -  +  #  # ]:          4 :         TEST(src1.at_end());
     523                 :          4 :         mset_expect_order(mset, 1, 2, 3, 4);
     524         [ +  + ]:         20 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
     525 [ -  + ][ #  # ]:         16 :             TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
     526                 :          4 :         }
     527                 :            :     }
     528                 :            : 
     529                 :            :     {
     530                 :          4 :         ChangeMaxweightPostingSource src1(3);
     531                 :          4 :         Xapian::FixedWeightPostingSource src2(2.5);
     532                 :            : 
     533                 :            :         Xapian::Query q(Xapian::Query::OP_AND,
     534                 :          4 :                         Xapian::Query(&src1), Xapian::Query(&src2));
     535                 :          4 :         enq.set_query(q);
     536                 :            : 
     537                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 2);
     538   [ -  +  #  # ]:          4 :         TEST(!src1.at_end());
     539 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(src1.get_docid(), 3);
     540 [ -  + ][ #  # ]:          4 :         TEST_EQUAL_DOUBLE(src1.get_maxweight(), 2.0);
     541                 :          4 :         mset_expect_order(mset, 1, 2);
     542         [ +  + ]:         12 :         for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
     543 [ -  + ][ #  # ]:          8 :             TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
     544                 :          4 :         }
     545                 :            :     }
     546                 :            : 
     547                 :          4 :     return true;
     548                 :            : }
     549                 :            : 
     550                 :            : // Test using a valueweightpostingsource which has no entries.
     551                 :          4 : DEFINE_TESTCASE(emptyvalwtsource1, backend && !remote && !multi) {
     552                 :          4 :     Xapian::Database db(get_database("apitest_phrase"));
     553                 :          4 :     Xapian::Enquire enq(db);
     554                 :            : 
     555                 :          4 :     Xapian::ValueWeightPostingSource src2(11); // A non-empty slot.
     556                 :          4 :     Xapian::ValueWeightPostingSource src3(100); // An empty slot.
     557                 :          4 :     Xapian::Query q1("leav");
     558                 :          4 :     Xapian::Query q2(&src2);
     559                 :          4 :     Xapian::Query q3(&src3);
     560                 :          4 :     Xapian::Query q(Xapian::Query::OP_OR, Xapian::Query(Xapian::Query::OP_AND_MAYBE, q1, q2), q3);
     561                 :            : 
     562                 :            :     // Perform search without ORring with the posting source.
     563                 :            :     Xapian::doccount size1;
     564                 :            :     {
     565                 :          4 :         enq.set_query(q1);
     566                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     567   [ -  +  #  # ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
     568                 :          4 :         size1 = mset.size();
     569   [ -  +  #  # ]:          4 :         TEST_REL(size1, >, 0);
     570                 :            :     }
     571                 :            : 
     572                 :            :     // Perform a search with just the non-empty posting source, checking it
     573                 :            :     // returns something.
     574                 :            :     {
     575                 :          4 :         enq.set_query(q2);
     576                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     577   [ -  +  #  # ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
     578 [ -  + ][ #  # ]:          4 :         TEST_REL(mset.size(), >, 0);
     579                 :            :     }
     580                 :            : 
     581                 :            :     // Perform a search with just the empty posting source, checking it returns
     582                 :            :     // nothing.
     583                 :            :     {
     584                 :          4 :         enq.set_query(q3);
     585                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     586                 :            : 
     587                 :            :         // get_max_possible() returns 0 here for backends which track the upper
     588                 :            :         // bound on value slot entries, MAX_DBL for backends which don't.
     589                 :            :         // Either is valid.
     590   [ -  +  #  # ]:          4 :         TEST_REL(mset.get_max_possible(), >=, 0.0);
     591                 :            : 
     592 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(mset.size(), 0);
     593                 :            :     }
     594                 :            : 
     595                 :            :     // Perform a search with the posting source ORred with the normal query.
     596                 :            :     // This is a regression test - it used to return nothing.
     597                 :            :     {
     598                 :          4 :         enq.set_query(q);
     599                 :          4 :         Xapian::MSet mset = enq.get_mset(0, 10);
     600   [ -  +  #  # ]:          4 :         TEST_REL(mset.get_max_possible(), >, 0.0);
     601 [ -  + ][ #  # ]:          4 :         TEST_REL(mset.size(), >, 0.0);
     602 [ -  + ][ #  # ]:          4 :         TEST_EQUAL(mset.size(), size1);
     603                 :            :     }
     604                 :            : 
     605                 :          4 :     return true;
     606                 :            : }

Generated by: LCOV version 1.8