LCOV - code coverage report
Current view: top level - tests - api_opvalue.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 266 266 100.0 %
Date: 2019-06-30 05:20:33 Functions: 16 16 100.0 %
Branches: 470 2344 20.1 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_opvalue.cc
       2                 :            :  * @brief Tests of the OP_VALUE_* query operators.
       3                 :            :  */
       4                 :            : /* Copyright 2007,2008,2009,2010,2010,2011,2017,2019 Olly Betts
       5                 :            :  * Copyright 2008 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_opvalue.h"
      27                 :            : 
      28                 :            : #include <xapian.h>
      29                 :            : 
      30                 :            : #include "apitest.h"
      31                 :            : #include "testsuite.h"
      32                 :            : #include "testutils.h"
      33                 :            : 
      34                 :            : #include <string>
      35                 :            : 
      36                 :            : using namespace std;
      37                 :            : 
      38                 :            : // Feature test for Query::OP_VALUE_RANGE.
      39                 :          7 : DEFINE_TESTCASE(valuerange1, backend) {
      40 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
      41         [ +  - ]:         14 :     Xapian::Enquire enq(db);
      42                 :            :     static const char * const vals[] = {
      43                 :            :         "", " ", "a", "aa", "abcd", "e", "g", "h", "hzz", "i", "l", "z"
      44                 :            :     };
      45         [ +  + ]:         91 :     for (auto start : vals) {
      46         [ +  + ]:       1092 :         for (auto end : vals) {
      47 [ +  - ][ +  - ]:       1008 :             Xapian::Query query(Xapian::Query::OP_VALUE_RANGE, 1, start, end);
                 [ +  - ]
      48         [ +  - ]:       1008 :             enq.set_query(query);
      49         [ +  - ]:       2016 :             Xapian::MSet mset = enq.get_mset(0, 20);
      50                 :            :             // Check that documents in the MSet match the value range filter.
      51         [ +  - ]:       2016 :             set<Xapian::docid> matched;
      52         [ +  - ]:       2016 :             Xapian::MSetIterator i;
      53 [ +  - ][ +  - ]:       4186 :             for (i = mset.begin(); i != mset.end(); ++i) {
         [ +  - ][ +  + ]
      54 [ +  - ][ +  - ]:       3178 :                 matched.insert(*i);
      55 [ +  - ][ +  - ]:       3178 :                 string value = db.get_document(*i).get_value(1);
                 [ +  - ]
      56 [ +  - ][ -  + ]:       3178 :                 TEST_REL(value,>=,start);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      57 [ +  - ][ -  + ]:       3178 :                 TEST_REL(value,<=,end);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      58                 :       3178 :             }
      59                 :            :             // Check that documents not in the MSet don't match the value range filter.
      60 [ +  - ][ +  + ]:      18144 :             for (Xapian::docid j = db.get_lastdocid(); j != 0; --j) {
      61 [ +  - ][ +  + ]:      17136 :                 if (matched.find(j) == matched.end()) {
      62 [ +  - ][ +  - ]:      13958 :                     string value = db.get_document(j).get_value(1);
      63 [ +  - ][ +  - ]:      13958 :                     tout << value << " < '" << start << "' or > '" << end << "'" << endl;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
      64 [ +  - ][ +  + ]:      13958 :                     TEST(value < start || value > end);
         [ +  - ][ -  + ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      65                 :            :                 }
      66                 :            :             }
      67                 :       1008 :         }
      68                 :            :     }
      69                 :          7 :     return true;
      70                 :            : }
      71                 :            : 
      72                 :            : // Regression test for Query::OP_VALUE_LE - used to return document IDs for
      73                 :            : // non-existent documents.
      74                 :          5 : DEFINE_TESTCASE(valuerange2, writable) {
      75 [ +  - ][ +  - ]:          5 :     Xapian::WritableDatabase db = get_writable_database();
      76         [ +  - ]:         10 :     Xapian::Document doc;
      77 [ +  - ][ +  - ]:          5 :     doc.set_data("5");
      78 [ +  - ][ +  - ]:          5 :     doc.add_value(0, "5");
      79         [ +  - ]:          5 :     db.replace_document(5, doc);
      80         [ +  - ]:         10 :     Xapian::Enquire enq(db);
      81                 :            : 
      82 [ +  - ][ +  - ]:         10 :     Xapian::Query query(Xapian::Query::OP_VALUE_LE, 0, "6");
      83         [ +  - ]:          5 :     enq.set_query(query);
      84         [ +  - ]:         10 :     Xapian::MSet mset = enq.get_mset(0, 20);
      85                 :            : 
      86 [ +  - ][ -  + ]:          5 :     TEST_EQUAL(mset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      87 [ +  - ][ +  - ]:          5 :     TEST_EQUAL(*(mset[0]), 5);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      88                 :          5 :     return true;
      89                 :            : }
      90                 :            : 
      91                 :            : static void
      92                 :          4 : make_valuerange5(Xapian::WritableDatabase &db, const string &)
      93                 :            : {
      94         [ +  - ]:          4 :     Xapian::Document doc;
      95 [ +  - ][ +  - ]:          4 :     doc.add_value(0, "BOOK");
      96         [ +  - ]:          4 :     db.add_document(doc);
      97 [ +  - ][ +  - ]:          4 :     doc.add_value(0, "VOLUME");
      98         [ +  - ]:          4 :     db.add_document(doc);
      99                 :          4 : }
     100                 :            : 
     101                 :            : // Check that lower and upper bounds are used.
     102                 :          6 : DEFINE_TESTCASE(valuerange5, generated) {
     103 [ +  - ][ +  - ]:          6 :     Xapian::Database db = get_database("valuerange5", make_valuerange5);
                 [ +  - ]
     104                 :            : 
     105                 :            :     // If the lower bound is empty, either the specified value slot is
     106                 :            :     // never used in the database, or the backend doesn't track value bounds.
     107                 :            :     // Neither should be true here.
     108 [ +  - ][ -  + ]:          6 :     TEST(!db.get_value_lower_bound(0).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     109                 :            : 
     110         [ +  - ]:         12 :     Xapian::Enquire enq(db);
     111                 :            : 
     112 [ +  - ][ +  - ]:         12 :     Xapian::Query query(Xapian::Query::OP_VALUE_RANGE, 0, "APPLE", "BANANA");
                 [ +  - ]
     113         [ +  - ]:          6 :     enq.set_query(query);
     114         [ +  - ]:         12 :     Xapian::MSet mset = enq.get_mset(0, 0);
     115 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     116                 :            : 
     117 [ +  - ][ +  - ]:         12 :     Xapian::Query query2(Xapian::Query::OP_VALUE_RANGE, 0, "WALRUS", "ZEBRA");
                 [ +  - ]
     118         [ +  - ]:          6 :     enq.set_query(query2);
     119 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     120 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     121                 :            : 
     122                 :          6 :     return true;
     123                 :            : }
     124                 :            : 
     125                 :            : static void
     126                 :          4 : make_singularvalue_db(Xapian::WritableDatabase &db, const string &)
     127                 :            : {
     128         [ +  - ]:          4 :     Xapian::Document doc;
     129         [ +  - ]:          4 :     db.add_document(doc);
     130 [ +  - ][ +  - ]:          4 :     doc.add_value(0, "SINGULAR");
     131         [ +  - ]:          4 :     db.add_document(doc);
     132         [ +  - ]:          4 :     db.add_document(doc);
     133                 :          4 : }
     134                 :            : 
     135                 :            : // Check handling of bounds when bounds are equal.
     136                 :          6 : DEFINE_TESTCASE(valuerange6, generated) {
     137                 :          6 :     const auto OP_VALUE_RANGE = Xapian::Query::OP_VALUE_RANGE;
     138 [ +  - ][ +  - ]:          6 :     Xapian::Database db = get_database("singularvalue", make_singularvalue_db);
                 [ +  - ]
     139                 :            : 
     140         [ +  - ]:         12 :     Xapian::Enquire enq(db);
     141                 :            : 
     142                 :         12 :     Xapian::Query query;
     143 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SATSUMA", "SLOE");
         [ +  - ][ +  - ]
     144         [ +  - ]:          6 :     enq.set_query(query);
     145         [ +  - ]:         12 :     Xapian::MSet mset = enq.get_mset(0, 0);
     146 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     147 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     148 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     149                 :            : 
     150 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "PEACH", "PLUM");
         [ +  - ][ +  - ]
     151         [ +  - ]:          6 :     enq.set_query(query);
     152 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     153 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     154 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     155 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     156                 :            : 
     157 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "PEACH", "PEACH");
         [ +  - ][ +  - ]
     158         [ +  - ]:          6 :     enq.set_query(query);
     159 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     160 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     161 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     162 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     163                 :            : 
     164 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "PEACH", "PEACHERINE");
         [ +  - ][ +  - ]
     165         [ +  - ]:          6 :     enq.set_query(query);
     166 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     167 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     168 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     169 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     170                 :            : 
     171 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SING", "SINGULARITY");
         [ +  - ][ +  - ]
     172         [ +  - ]:          6 :     enq.set_query(query);
     173 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     174 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     175 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     176 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     177                 :            : 
     178 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SING", "SINGULAR");
         [ +  - ][ +  - ]
     179         [ +  - ]:          6 :     enq.set_query(query);
     180 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     181 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     182 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     183 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     184                 :            : 
     185 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULAR", "SINGULARITY");
         [ +  - ][ +  - ]
     186         [ +  - ]:          6 :     enq.set_query(query);
     187 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     188 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     189 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     190 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     191                 :            : 
     192 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULAR", "SINGULAR");
         [ +  - ][ +  - ]
     193         [ +  - ]:          6 :     enq.set_query(query);
     194 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     195 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     196 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     197 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     198                 :            : 
     199 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULARITY", "SINGULARITY");
         [ +  - ][ +  - ]
     200         [ +  - ]:          6 :     enq.set_query(query);
     201 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     202 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     203 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     204 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     205                 :            : 
     206 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULARITY", "SINGULARITIES");
         [ +  - ][ +  - ]
     207         [ +  - ]:          6 :     enq.set_query(query);
     208 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     209 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     210 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     211 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     212                 :            : 
     213 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULARITY", "SINNER");
         [ +  - ][ +  - ]
     214         [ +  - ]:          6 :     enq.set_query(query);
     215 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     216 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     217 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     218 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     219                 :            : 
     220 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGULARITY", "ZEBRA");
         [ +  - ][ +  - ]
     221         [ +  - ]:          6 :     enq.set_query(query);
     222 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     223 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     224 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     225 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     226                 :            : 
     227 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "SINGE", "SINGER");
         [ +  - ][ +  - ]
     228         [ +  - ]:          6 :     enq.set_query(query);
     229 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     230 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     231 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     232 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     233                 :            : 
     234                 :            :     // Check no assertions when slot is empty.  Regression test for bug
     235                 :            :     // introduced and fixed between 1.4.5 and 1.4.6.
     236 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 1, "MONK", "MONKEY");
         [ +  - ][ +  - ]
     237         [ +  - ]:          6 :     enq.set_query(query);
     238 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     239 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     240 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     241 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     242                 :            : 
     243                 :          6 :     return true;
     244                 :            : }
     245                 :            : 
     246                 :            : static void
     247                 :          4 : make_valprefixbounds_db(Xapian::WritableDatabase &db, const string &)
     248                 :            : {
     249         [ +  - ]:          4 :     Xapian::Document doc;
     250         [ +  - ]:          4 :     db.add_document(doc);
     251 [ +  - ][ +  - ]:          4 :     doc.add_value(0, "ZERO");
     252         [ +  - ]:          4 :     db.add_document(doc);
     253 [ +  - ][ +  - ]:          4 :     doc.add_value(0, string("ZERO\0", 5));
     254         [ +  - ]:          4 :     db.add_document(doc);
     255                 :          4 : }
     256                 :            : 
     257                 :            : // Check handling of bounds when low is a prefix of high.
     258                 :          6 : DEFINE_TESTCASE(valuerange7, generated) {
     259                 :          6 :     const auto OP_VALUE_RANGE = Xapian::Query::OP_VALUE_RANGE;
     260 [ +  - ][ +  - ]:          6 :     Xapian::Database db = get_database("valprefixbounds", make_valprefixbounds_db);
                 [ +  - ]
     261                 :            : 
     262         [ +  - ]:         12 :     Xapian::Enquire enq(db);
     263                 :            : 
     264                 :         12 :     Xapian::Query query;
     265 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "ZAP", "ZOO");
         [ +  - ][ +  - ]
     266         [ +  - ]:          6 :     enq.set_query(query);
     267         [ +  - ]:         12 :     Xapian::MSet mset = enq.get_mset(0, 0);
     268 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_lower_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     269 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     270 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     271                 :            : 
     272 [ +  - ][ +  - ]:          6 :     query = Xapian::Query(OP_VALUE_RANGE, 0, "ZAP", "ZERO");
         [ +  - ][ +  - ]
     273         [ +  - ]:          6 :     enq.set_query(query);
     274 [ +  - ][ +  - ]:          6 :     mset = enq.get_mset(0, 0);
     275 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.get_matches_estimated(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     276 [ +  - ][ +  + ]:          6 :     if (startswith(get_dbtype(), "multi")) {
     277                 :            :         // The second shard will just have one document with "ZERO" in the slot
     278                 :            :         // so we can tell there's exactly one match there, and the first shard
     279                 :            :         // has one "ZERO\0" and one empty entry, so we can tell that can't
     280                 :            :         // match.
     281 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(mset.get_matches_lower_bound(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     282 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(mset.get_matches_upper_bound(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     283                 :            :     } else {
     284 [ +  - ][ -  + ]:          5 :         TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     285 [ +  - ][ -  + ]:          5 :         TEST_EQUAL(mset.get_matches_upper_bound(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     286                 :            :     }
     287                 :            : 
     288                 :          6 :     return true;
     289                 :            : }
     290                 :            : 
     291                 :            : // Feature test for Query::OP_VALUE_GE.
     292                 :          7 : DEFINE_TESTCASE(valuege1, backend) {
     293 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     294         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     295                 :            :     static const char * const vals[] = {
     296                 :            :         "", " ", "a", "aa", "abcd", "e", "g", "h", "hzz", "i", "l", "z"
     297                 :            :     };
     298         [ +  + ]:         91 :     for (auto start : vals) {
     299 [ +  - ][ +  - ]:         84 :         Xapian::Query query(Xapian::Query::OP_VALUE_GE, 1, start);
     300         [ +  - ]:         84 :         enq.set_query(query);
     301         [ +  - ]:        168 :         Xapian::MSet mset = enq.get_mset(0, 20);
     302                 :            :         // Check that documents in the MSet match the value range filter.
     303         [ +  - ]:        168 :         set<Xapian::docid> matched;
     304         [ +  - ]:        168 :         Xapian::MSetIterator i;
     305 [ +  - ][ +  - ]:        987 :         for (i = mset.begin(); i != mset.end(); ++i) {
         [ +  - ][ +  + ]
     306 [ +  - ][ +  - ]:        903 :             matched.insert(*i);
     307 [ +  - ][ +  - ]:        903 :             string value = db.get_document(*i).get_value(1);
                 [ +  - ]
     308 [ +  - ][ +  - ]:        903 :             tout << "'" << start << "' <= '" << value << "'" << endl;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     309 [ +  - ][ -  + ]:        903 :             TEST_REL(value,>=,start);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     310                 :        903 :         }
     311                 :            :         // Check that documents not in the MSet don't match the value range
     312                 :            :         // filter.
     313 [ +  - ][ +  + ]:       1512 :         for (Xapian::docid j = db.get_lastdocid(); j != 0; --j) {
     314 [ +  - ][ +  + ]:       1428 :             if (matched.find(j) == matched.end()) {
     315 [ +  - ][ +  - ]:        525 :                 string value = db.get_document(j).get_value(1);
     316 [ +  - ][ +  - ]:        525 :                 tout << value << " < '" << start << "'" << endl;
         [ +  - ][ +  - ]
                 [ +  - ]
     317 [ +  - ][ -  + ]:        525 :                 TEST_REL(value,<,start);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     318                 :            :             }
     319                 :            :         }
     320                 :         84 :     }
     321                 :          7 :     return true;
     322                 :            : }
     323                 :            : 
     324                 :            : // Regression test for Query::OP_VALUE_GE - used to segfault if check() got
     325                 :            : // called.
     326                 :          7 : DEFINE_TESTCASE(valuege2, backend) {
     327 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     328         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     329                 :            :     Xapian::Query query(Xapian::Query::OP_AND,
     330                 :            :                         Xapian::Query("what"),
     331 [ +  - ][ +  - ]:         14 :                         Xapian::Query(Xapian::Query::OP_VALUE_GE, 1, "aa"));
         [ +  - ][ +  - ]
                 [ +  - ]
     332         [ +  - ]:          7 :     enq.set_query(query);
     333         [ +  - ]:          7 :     Xapian::MSet mset = enq.get_mset(0, 20);
     334                 :          7 :     return true;
     335                 :            : }
     336                 :            : 
     337                 :            : // Feature test for Query::OP_VALUE_LE.
     338                 :          7 : DEFINE_TESTCASE(valuele1, backend) {
     339 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     340         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     341                 :            :     static const char * const vals[] = {
     342                 :            :         "", " ", "a", "aa", "abcd", "e", "g", "h", "hzz", "i", "l", "z"
     343                 :            :     };
     344         [ +  + ]:         91 :     for (auto end : vals) {
     345 [ +  - ][ +  - ]:         84 :         Xapian::Query query(Xapian::Query::OP_VALUE_LE, 1, end);
     346         [ +  - ]:         84 :         enq.set_query(query);
     347         [ +  - ]:        168 :         Xapian::MSet mset = enq.get_mset(0, 20);
     348                 :            :         // Check that documents in the MSet match the value range filter.
     349         [ +  - ]:        168 :         set<Xapian::docid> matched;
     350         [ +  - ]:        168 :         Xapian::MSetIterator i;
     351 [ +  - ][ +  - ]:        686 :         for (i = mset.begin(); i != mset.end(); ++i) {
         [ +  - ][ +  + ]
     352 [ +  - ][ +  - ]:        602 :             matched.insert(*i);
     353 [ +  - ][ +  - ]:        602 :             string value = db.get_document(*i).get_value(1);
                 [ +  - ]
     354 [ +  - ][ -  + ]:        602 :             TEST_REL(value,<=,end);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     355                 :        602 :         }
     356                 :            :         // Check that documents not in the MSet don't match the value range
     357                 :            :         // filter.
     358 [ +  - ][ +  + ]:       1512 :         for (Xapian::docid j = db.get_lastdocid(); j != 0; --j) {
     359 [ +  - ][ +  + ]:       1428 :             if (matched.find(j) == matched.end()) {
     360 [ +  - ][ +  - ]:        826 :                 string value = db.get_document(j).get_value(1);
     361 [ +  - ][ -  + ]:        826 :                 TEST_REL(value,>,end);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     362                 :            :             }
     363                 :            :         }
     364                 :         84 :     }
     365                 :          7 :     return true;
     366                 :            : }
     367                 :            : 
     368                 :            : // Check that Query(OP_VALUE_GE, 0, "") -> Query::MatchAll.
     369                 :          1 : DEFINE_TESTCASE(valuege3, !backend) {
     370 [ +  - ][ +  - ]:          1 :     Xapian::Query query(Xapian::Query::OP_VALUE_GE, 0, "");
     371 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(query.get_description(), Xapian::Query::MatchAll.get_description());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     372                 :          1 :     return true;
     373                 :            : }
     374                 :            : 
     375                 :            : // Test Query::OP_VALUE_GE in a query which causes its skip_to() to be used.
     376                 :          7 : DEFINE_TESTCASE(valuege4, backend) {
     377 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     378         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     379                 :            : 
     380                 :            :     // This query should put the ValueGePostList on the LHS of the AND because
     381                 :            :     // it has a lower estimated termfreq than the term "fridg".  As a result,
     382                 :            :     // the skip_to() method is used to advance the ValueGePostList.
     383                 :            :     Xapian::Query query(Xapian::Query::OP_AND,
     384                 :            :                         Xapian::Query("fridg"),
     385 [ +  - ][ +  - ]:         14 :                         Xapian::Query(Xapian::Query::OP_VALUE_GE, 1, "aa"));
         [ +  - ][ +  - ]
                 [ +  - ]
     386         [ +  - ]:          7 :     enq.set_query(query);
     387         [ +  - ]:          7 :     Xapian::MSet mset = enq.get_mset(0, 20);
     388                 :          7 :     return true;
     389                 :            : }
     390                 :            : 
     391                 :            : // Test Query::OP_VALUE_RANGE in a query which causes its check() to be used.
     392                 :          7 : DEFINE_TESTCASE(valuerange3, backend) {
     393 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     394         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     395                 :            :     Xapian::Query query(Xapian::Query::OP_AND,
     396                 :            :                         Xapian::Query("what"),
     397                 :            :                         Xapian::Query(Xapian::Query::OP_VALUE_RANGE, 1,
     398 [ +  - ][ +  - ]:         14 :                                       "aa", "z"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     399         [ +  - ]:          7 :     enq.set_query(query);
     400         [ +  - ]:          7 :     Xapian::MSet mset = enq.get_mset(0, 20);
     401                 :          7 :     return true;
     402                 :            : }
     403                 :            : 
     404                 :            : // Test Query::OP_VALUE_RANGE in a query which causes its skip_to() to be used.
     405                 :          7 : DEFINE_TESTCASE(valuerange4, backend) {
     406 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("apitest_phrase"));
     407         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     408                 :            :     Xapian::Query query(Xapian::Query::OP_AND,
     409                 :            :                         Xapian::Query("fridg"),
     410                 :            :                         Xapian::Query(Xapian::Query::OP_VALUE_RANGE, 1,
     411 [ +  - ][ +  - ]:         14 :                                       "aa", "z"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     412         [ +  - ]:          7 :     enq.set_query(query);
     413         [ +  - ]:          7 :     Xapian::MSet mset = enq.get_mset(0, 20);
     414                 :          7 :     return true;
     415                 :            : }
     416                 :            : 
     417                 :            : /// Test improved upper bound and estimate in 1.4.3.
     418                 :          7 : DEFINE_TESTCASE(valuerangematchesub1, backend) {
     419 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("etext"));
     420         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     421                 :            :     // Values present in slot 10 range from 'e' to 'w'.
     422                 :            :     Xapian::Query query(Xapian::Query(Xapian::Query::OP_VALUE_RANGE, 10,
     423 [ +  - ][ +  - ]:         14 :                                       "h", "i"));
                 [ +  - ]
     424         [ +  - ]:          7 :     enq.set_query(query);
     425         [ +  - ]:         14 :     Xapian::MSet mset = enq.get_mset(0, 0);
     426                 :            :     // The upper bound used to be db.size().
     427 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(mset.get_matches_upper_bound(), db.get_value_freq(10));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     428 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.get_matches_lower_bound(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     429                 :            :     // The estimate used to be db.size() / 2, now it's calculated
     430                 :            :     // proportional to the possible range.
     431 [ +  - ][ +  - ]:          7 :     TEST_REL(mset.get_matches_estimated(), <=, db.get_doccount() / 3);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     432                 :          7 :     return true;
     433                 :            : }

Generated by: LCOV version 1.11