LCOV - code coverage report
Current view: top level - tests - api_query.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 7028d852e609 Lines: 502 504 99.6 %
Date: 2019-02-17 14:59:59 Functions: 27 27 100.0 %
Branches: 1094 4862 22.5 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_query.cc
       2                 :            :  * @brief Query-related tests.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2008,2009,2012,2013,2015,2016,2017,2018,2019 Olly Betts
       5                 :            :  *
       6                 :            :  * This program is free software; you can redistribute it and/or
       7                 :            :  * modify it under the terms of the GNU General Public License as
       8                 :            :  * published by the Free Software Foundation; either version 2 of the
       9                 :            :  * License, or (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This program is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :  * GNU General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU General Public License
      17                 :            :  * along with this program; if not, write to the Free Software
      18                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
      19                 :            :  * USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "api_query.h"
      25                 :            : 
      26                 :            : #include <xapian.h>
      27                 :            : 
      28                 :            : #include "testsuite.h"
      29                 :            : #include "testutils.h"
      30                 :            : 
      31                 :            : #include "apitest.h"
      32                 :            : 
      33                 :            : using namespace std;
      34                 :            : 
      35                 :            : /// Regression test - in 1.0.10 and earlier "" was included in the list.
      36                 :          1 : DEFINE_TESTCASE(queryterms1, !backend) {
      37         [ +  - ]:          1 :     Xapian::Query query = Xapian::Query::MatchAll;
      38 [ +  - ][ -  + ]:          1 :     TEST(query.get_terms_begin() == query.get_terms_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      39 [ +  - ][ +  - ]:          1 :     query = Xapian::Query(query.OP_AND_NOT, query, Xapian::Query("fair"));
         [ +  - ][ +  - ]
      40 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(*query.get_terms_begin(), "fair");
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      41                 :          1 :     return true;
      42                 :            : }
      43                 :            : 
      44                 :          1 : DEFINE_TESTCASE(matchall2, !backend) {
      45 [ +  - ][ -  + ]:          1 :     TEST_STRINGS_EQUAL(Xapian::Query::MatchAll.get_description(),
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      46                 :            :                        "Query(<alldocuments>)");
      47                 :          1 :     return true;
      48                 :            : }
      49                 :            : 
      50                 :          1 : DEFINE_TESTCASE(matchnothing1, !backend) {
      51 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(Xapian::Query::MatchNothing.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      52                 :            :                        "Query()");
      53                 :          1 :     vector<Xapian::Query> subqs;
      54 [ +  - ][ +  - ]:          1 :     subqs.push_back(Xapian::Query("foo"));
                 [ +  - ]
      55         [ +  - ]:          1 :     subqs.push_back(Xapian::Query::MatchNothing);
      56         [ +  - ]:          2 :     Xapian::Query q(Xapian::Query::OP_AND, subqs.begin(), subqs.end());
      57 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      58                 :            : 
      59                 :            :     Xapian::Query q2(Xapian::Query::OP_AND,
      60 [ +  - ][ +  - ]:          2 :                      Xapian::Query("foo"), Xapian::Query::MatchNothing);
                 [ +  - ]
      61 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q2.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      62                 :          1 :     return true;
      63                 :            : }
      64                 :            : 
      65                 :          1 : DEFINE_TESTCASE(overload1, !backend) {
      66                 :          1 :     Xapian::Query q;
      67 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      68 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo AND bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      69                 :            : 
      70                 :            :     // Test &= appends a same-type subquery (since Xapian 1.4.10).
      71 [ +  - ][ +  - ]:          1 :     q &= Xapian::Query("baz");
                 [ +  - ]
      72 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo AND bar AND baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      73                 :            :     // But not if the RHS is the same query:
      74 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      75         [ +  - ]:          1 :     q &= q;
      76 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(((foo AND bar) AND (foo AND bar)))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      77                 :            :     {
      78                 :            :         // Also not if the query has a refcount > 1.
      79 [ +  - ][ +  - ]:          1 :         q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      80         [ +  - ]:          1 :         Xapian::Query qcopy = q;
      81 [ +  - ][ +  - ]:          1 :         qcopy &= Xapian::Query("baz");
                 [ +  - ]
      82 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(qcopy.get_description(), "Query(((foo AND bar) AND baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      83                 :            :         // And q shouldn't change.
      84 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(q.get_description(), "Query((foo AND bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      85                 :            :     }
      86                 :            :     // Check that MatchNothing still results in MatchNothing:
      87 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      88         [ +  - ]:          1 :     q &= Xapian::Query::MatchNothing;
      89 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      90                 :            :     // Check we don't combine for other operators:
      91 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      92 [ +  - ][ +  - ]:          1 :     q &= Xapian::Query("baz");
                 [ +  - ]
      93 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(((foo OR bar) AND baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      94                 :            : 
      95                 :            :     // Test |= appends a same-type subquery (since Xapian 1.4.10).
      96 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
      97 [ +  - ][ +  - ]:          1 :     q |= Xapian::Query("baz");
                 [ +  - ]
      98 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo OR bar OR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      99                 :            :     // But not if the RHS is the same query:
     100 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     101         [ +  - ]:          1 :     q |= q;
     102 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(((foo OR bar) OR (foo OR bar)))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     103                 :            :     {
     104                 :            :         // Also not if the query has a refcount > 1.
     105 [ +  - ][ +  - ]:          1 :         q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     106         [ +  - ]:          1 :         Xapian::Query qcopy = q;
     107 [ +  - ][ +  - ]:          1 :         qcopy |= Xapian::Query("baz");
                 [ +  - ]
     108 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(qcopy.get_description(), "Query(((foo OR bar) OR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     109                 :            :         // And q shouldn't change.
     110 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(q.get_description(), "Query((foo OR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     111                 :            :     }
     112                 :            :     // Check that MatchNothing still results in no change:
     113 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     114         [ +  - ]:          1 :     q |= Xapian::Query::MatchNothing;
     115 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo OR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     116                 :            :     // Check we don't combine for other operators:
     117 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     118 [ +  - ][ +  - ]:          1 :     q |= Xapian::Query("baz");
                 [ +  - ]
     119 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(((foo AND bar) OR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     120                 :            : 
     121                 :            :     // Test ^= appends a same-type subquery (since Xapian 1.4.10).
     122 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     123 [ +  - ][ +  - ]:          1 :     q ^= Xapian::Query("baz");
                 [ +  - ]
     124 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo XOR bar XOR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     125                 :            :     // But a query ^= itself gives an empty query.
     126 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     127         [ +  - ]:          1 :     q ^= q;
     128 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     129                 :            :     {
     130                 :            :         // Even if the reference count > 1.
     131 [ +  - ][ +  - ]:          1 :         q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     132         [ +  - ]:          1 :         Xapian::Query qcopy = q;
     133         [ +  - ]:          1 :         q ^= qcopy;
     134 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(q.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     135                 :            :     }
     136                 :            :     {
     137                 :            :         // Also not if the query has a refcount > 1.
     138 [ +  - ][ +  - ]:          1 :         q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     139         [ +  - ]:          1 :         Xapian::Query qcopy = q;
     140 [ +  - ][ +  - ]:          1 :         qcopy ^= Xapian::Query("baz");
                 [ +  - ]
     141 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(qcopy.get_description(), "Query(((foo XOR bar) XOR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     142                 :            :         // And q shouldn't change.
     143 [ +  - ][ +  - ]:          1 :         TEST_STRINGS_EQUAL(q.get_description(), "Query((foo XOR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     144                 :            :     }
     145                 :            :     // Check that MatchNothing still results in no change:
     146 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     147         [ +  - ]:          1 :     q ^= Xapian::Query::MatchNothing;
     148 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo XOR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     149                 :            :     // Check we don't combine for other operators:
     150 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     151 [ +  - ][ +  - ]:          1 :     q ^= Xapian::Query("baz");
                 [ +  - ]
     152 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(((foo AND bar) XOR baz))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     153                 :            : 
     154 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") &~ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     155 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo AND_NOT bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     156                 :            :     // In 1.4.9 and earlier this gave (foo AND (<alldocuments> AND_NOT bar)).
     157 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo");
                 [ +  - ]
     158 [ +  - ][ +  - ]:          1 :     q &= ~Xapian::Query("bar");
                 [ +  - ]
     159 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo AND_NOT bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     160 [ +  - ][ +  - ]:          1 :     q = ~Xapian::Query("bar");
         [ +  - ][ +  - ]
     161 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((<alldocuments> AND_NOT bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     162 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query::MatchNothing;
         [ +  - ][ +  - ]
     163 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query()");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     164 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     165 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo OR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     166 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query::MatchNothing;
         [ +  - ][ +  - ]
     167 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(foo)");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     168 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     169 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query((foo XOR bar))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     170 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query::MatchNothing;
         [ +  - ][ +  - ]
     171 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(foo)");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     172 [ +  - ][ +  - ]:          1 :     q = 1.25 * (Xapian::Query("one") | Xapian::Query("two"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     173 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(1.25 * (one OR two))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     174 [ +  - ][ +  - ]:          1 :     q = (Xapian::Query("one") & Xapian::Query("two")) * 42;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     175 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(42 * (one AND two))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     176 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("one") / 2.0;
         [ +  - ][ +  - ]
     177 [ +  - ][ +  - ]:          1 :     TEST_STRINGS_EQUAL(q.get_description(), "Query(0.5 * one)");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     178                 :          1 :     return true;
     179                 :            : }
     180                 :            : 
     181                 :            : /** Regression test and feature test.
     182                 :            :  *
     183                 :            :  *  This threw AssertionError in 1.0.9 and earlier (bug#201) and gave valgrind
     184                 :            :  *  errors in 1.0.11 and earlier (bug#349).
     185                 :            :  *
     186                 :            :  *  Currently the OR-subquery case is supported, other operators aren't.
     187                 :            :  */
     188                 :          5 : DEFINE_TESTCASE(possubqueries1, writable) {
     189 [ +  - ][ +  - ]:          5 :     Xapian::WritableDatabase db = get_writable_database();
     190         [ +  - ]:         10 :     Xapian::Document doc;
     191 [ +  - ][ +  - ]:          5 :     doc.add_posting("a", 1);
     192 [ +  - ][ +  - ]:          5 :     doc.add_posting("b", 2);
     193 [ +  - ][ +  - ]:          5 :     doc.add_posting("c", 3);
     194         [ +  - ]:          5 :     db.add_document(doc);
     195                 :            : 
     196                 :            :     Xapian::Query a_or_b(Xapian::Query::OP_OR,
     197                 :            :                          Xapian::Query("a"),
     198 [ +  - ][ +  - ]:         10 :                          Xapian::Query("b"));
         [ +  - ][ +  - ]
                 [ +  - ]
     199         [ +  - ]:         10 :     Xapian::Query near(Xapian::Query::OP_NEAR, a_or_b, a_or_b);
     200                 :            :     // As of 1.3.0, we no longer rearrange queries at this point, so check
     201                 :            :     // that we don't.
     202 [ +  - ][ +  - ]:          5 :     TEST_STRINGS_EQUAL(near.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     203                 :            :                        "Query(((a OR b) NEAR 2 (a OR b)))");
     204         [ +  - ]:         10 :     Xapian::Query phrase(Xapian::Query::OP_PHRASE, a_or_b, a_or_b);
     205 [ +  - ][ +  - ]:          5 :     TEST_STRINGS_EQUAL(phrase.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     206                 :            :                        "Query(((a OR b) PHRASE 2 (a OR b)))");
     207                 :            : 
     208                 :            :     Xapian::Query a_and_b(Xapian::Query::OP_AND,
     209                 :            :                           Xapian::Query("a"),
     210 [ +  - ][ +  - ]:         10 :                           Xapian::Query("b"));
         [ +  - ][ +  - ]
                 [ +  - ]
     211                 :            :     Xapian::Query a_near_b(Xapian::Query::OP_NEAR,
     212                 :            :                            Xapian::Query("a"),
     213 [ +  - ][ +  - ]:         10 :                            Xapian::Query("b"));
         [ +  - ][ +  - ]
                 [ +  - ]
     214                 :            :     Xapian::Query a_phrs_b(Xapian::Query::OP_PHRASE,
     215                 :            :                            Xapian::Query("a"),
     216 [ +  - ][ +  - ]:         10 :                            Xapian::Query("b"));
         [ +  - ][ +  - ]
                 [ +  - ]
     217 [ +  - ][ +  - ]:         10 :     Xapian::Query c("c");
     218                 :            : 
     219                 :            :     // FIXME: The plan is to actually try to support the cases below, but
     220                 :            :     // for now at least ensure they are cleanly rejected.
     221         [ +  - ]:         10 :     Xapian::Enquire enq(db);
     222                 :            : 
     223 [ +  - ][ -  + ]:          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
     224                 :            :         Xapian::Query q(Xapian::Query::OP_NEAR, a_and_b, c);
     225                 :            :         enq.set_query(q);
     226                 :            :         (void)enq.get_mset(0, 10));
     227                 :            : 
     228 [ +  - ][ -  +  :          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     229                 :            :         Xapian::Query q(Xapian::Query::OP_NEAR, a_near_b, c);
     230                 :            :         enq.set_query(q);
     231                 :            :         (void)enq.get_mset(0, 10));
     232                 :            : 
     233 [ +  - ][ -  +  :          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     234                 :            :         Xapian::Query q(Xapian::Query::OP_NEAR, a_phrs_b, c);
     235                 :            :         enq.set_query(q);
     236                 :            :         (void)enq.get_mset(0, 10));
     237                 :            : 
     238 [ +  - ][ -  +  :          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     239                 :            :         Xapian::Query q(Xapian::Query::OP_PHRASE, a_and_b, c);
     240                 :            :         enq.set_query(q);
     241                 :            :         (void)enq.get_mset(0, 10));
     242                 :            : 
     243 [ +  - ][ -  +  :          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     244                 :            :         Xapian::Query q(Xapian::Query::OP_PHRASE, a_near_b, c);
     245                 :            :         enq.set_query(q);
     246                 :            :         (void)enq.get_mset(0, 10));
     247                 :            : 
     248 [ +  - ][ -  +  :          5 :     TEST_EXCEPTION(Xapian::UnimplementedError,
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     249                 :            :         Xapian::Query q(Xapian::Query::OP_PHRASE, a_phrs_b, c);
     250                 :            :         enq.set_query(q);
     251                 :            :         (void)enq.get_mset(0, 10));
     252                 :            : 
     253                 :          5 :     return true;
     254                 :            : }
     255                 :            : 
     256                 :            : /// Test that XOR handles all remaining subqueries running out at the same
     257                 :            : //  time.
     258                 :          7 : DEFINE_TESTCASE(xor3, backend) {
     259 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     260                 :            : 
     261                 :            :     static const char * const subqs[] = {
     262                 :            :         "hack", "which", "paragraph", "is", "return"
     263                 :            :     };
     264                 :            :     // Document where the subqueries run out *does* match XOR:
     265         [ +  - ]:         14 :     Xapian::Query q(Xapian::Query::OP_XOR, subqs, subqs + 5);
     266         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     267         [ +  - ]:          7 :     enq.set_query(q);
     268         [ +  - ]:         14 :     Xapian::MSet mset = enq.get_mset(0, 10);
     269                 :            : 
     270 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     271 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[0], 4);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     272 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[1], 2);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     273 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[2], 3);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     274                 :            : 
     275                 :            :     // Document where the subqueries run out *does not* match XOR:
     276 [ +  - ][ +  - ]:          7 :     q = Xapian::Query(Xapian::Query::OP_XOR, subqs, subqs + 4);
     277         [ +  - ]:          7 :     enq.set_query(q);
     278 [ +  - ][ +  - ]:          7 :     mset = enq.get_mset(0, 10);
     279                 :            : 
     280 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), 4);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     281 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[0], 5);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     282 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[1], 4);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     283 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[2], 2);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     284 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(*mset[3], 3);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     285                 :            : 
     286                 :          7 :     return true;
     287                 :            : }
     288                 :            : 
     289                 :            : /// Check encoding of non-UTF8 terms in query descriptions.
     290                 :          1 : DEFINE_TESTCASE(nonutf8termdesc1, !backend) {
     291 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query("\xc0\x80\xf5\x80\x80\x80\xfe\xff").get_description(),
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     292                 :            :                "Query(\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff)");
     293 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(string("\x00\x1f", 2)).get_description(),
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     294                 :            :                "Query(\\x00\\x1f)");
     295                 :            :     // Check that backslashes are encoded so output isn't ambiguous.
     296 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query("back\\slash").get_description(),
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     297                 :            :                "Query(back\\x5cslash)");
     298                 :            :     // Check that \x7f is escaped.
     299 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query("D\x7f_\x7f~").get_description(),
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     300                 :            :                "Query(D\\x7f_\\x7f~)");
     301                 :          1 :     return true;
     302                 :            : }
     303                 :            : 
     304                 :            : /// Test introspection on Query objects.
     305                 :          1 : DEFINE_TESTCASE(queryintro1, !backend) {
     306 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(Xapian::Query::MatchAll.get_type(), Xapian::Query::LEAF_MATCH_ALL);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     307 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(Xapian::Query::MatchAll.get_num_subqueries(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     308 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(Xapian::Query::MatchNothing.get_type(), Xapian::Query::LEAF_MATCH_NOTHING);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     309 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(Xapian::Query::MatchNothing.get_num_subqueries(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     310                 :            : 
     311                 :          1 :     Xapian::Query q;
     312 [ +  - ][ +  - ]:          1 :     q = Xapian::Query(q.OP_AND_NOT, Xapian::Query::MatchAll, Xapian::Query("fair"));
         [ +  - ][ +  - ]
     313 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_AND_NOT);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     314 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_num_subqueries(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     315 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(0).get_type(), q.LEAF_MATCH_ALL);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     316 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(1).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     317                 :            : 
     318 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo", 2, 1);
                 [ +  - ]
     319 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_leaf_wqf(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     320 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_leaf_pos(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     321                 :            : 
     322 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("bar");
                 [ +  - ]
     323 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_leaf_wqf(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     324 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_leaf_pos(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     325                 :            : 
     326 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") & Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     327 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_AND);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     328                 :            : 
     329 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") &~ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     330 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_AND_NOT);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     331                 :            : 
     332 [ +  - ][ +  - ]:          1 :     q = ~Xapian::Query("bar");
         [ +  - ][ +  - ]
     333 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_AND_NOT);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     334                 :            : 
     335 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") | Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     336 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_OR);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     337                 :            : 
     338 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("foo") ^ Xapian::Query("bar");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     339 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_XOR);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     340                 :            : 
     341 [ +  - ][ +  - ]:          1 :     q = 1.25 * (Xapian::Query("one") | Xapian::Query("two"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     342 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_SCALE_WEIGHT);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     343 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_num_subqueries(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     344 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(0).get_type(), q.OP_OR);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     345                 :            : 
     346 [ +  - ][ +  - ]:          1 :     q = Xapian::Query("one") / 2.0;
         [ +  - ][ +  - ]
     347 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_SCALE_WEIGHT);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     348 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_num_subqueries(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     349 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(0).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     350                 :            : 
     351 [ +  - ][ +  - ]:          1 :     q = Xapian::Query(q.OP_NEAR, Xapian::Query("a"), Xapian::Query("b"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     352 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_NEAR);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     353 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_num_subqueries(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     354 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(0).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     355 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(1).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     356                 :            : 
     357 [ +  - ][ +  - ]:          1 :     q = Xapian::Query(q.OP_PHRASE, Xapian::Query("c"), Xapian::Query("d"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     358 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_type(), q.OP_PHRASE);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     359 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_num_subqueries(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     360 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(0).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     361 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(q.get_subquery(1).get_type(), q.LEAF_TERM);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     362                 :            : 
     363                 :          1 :     return true;
     364                 :            : }
     365                 :            : 
     366                 :            : /// Regression test for bug introduced in 1.3.1 and fixed in 1.3.3.
     367                 :            : //  We were incorrectly converting a term which indexed all docs and was used
     368                 :            : //  in an unweighted phrase into an all docs postlist, so check that this
     369                 :            : //  case actually works.
     370                 :          7 : DEFINE_TESTCASE(phrasealldocs1, backend) {
     371 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_declen");
     372                 :         14 :     Xapian::Query q;
     373                 :            :     static const char * const phrase[] = { "this", "is", "the" };
     374 [ +  - ][ +  - ]:         14 :     q = Xapian::Query(q.OP_AND_NOT,
         [ +  - ][ +  - ]
     375                 :            :             Xapian::Query("paragraph"),
     376         [ +  - ]:          7 :             Xapian::Query(q.OP_PHRASE, phrase, phrase + 3));
     377         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     378         [ +  - ]:          7 :     enq.set_query(q);
     379         [ +  - ]:         14 :     Xapian::MSet mset = enq.get_mset(0, 10);
     380 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     381                 :            : 
     382                 :          7 :     return true;
     383                 :            : }
     384                 :            : 
     385                 :            : struct wildcard_testcase {
     386                 :            :     const char * pattern;
     387                 :            :     Xapian::termcount max_expansion;
     388                 :            :     char max_type;
     389                 :            :     const char * terms[4];
     390                 :            : };
     391                 :            : 
     392                 :            : #define WILDCARD_EXCEPTION { 0, 0, 0, "" }
     393                 :            : static const
     394                 :            : wildcard_testcase wildcard1_testcases[] = {
     395                 :            :     // Tries to expand to 7 terms.
     396                 :            :     { "th",   6, 'E', WILDCARD_EXCEPTION },
     397                 :            :     { "thou", 1, 'E', { "though", 0, 0, 0 } },
     398                 :            :     { "s",    2, 'F', { "say", "search", 0, 0 } },
     399                 :            :     { "s",    2, 'M', { "simpl", "so", 0, 0 } },
     400                 :            :     { 0,        0, 0, { 0, 0, 0, 0 } }
     401                 :            : };
     402                 :            : 
     403                 :          7 : DEFINE_TESTCASE(wildcard1, backend) {
     404                 :            :     // FIXME: The counting of terms the wildcard expands to is per subdatabase,
     405                 :            :     // so the wildcard may expand to more terms than the limit if some aren't
     406                 :            :     // in all subdatabases.  Also WILDCARD_LIMIT_MOST_FREQUENT uses the
     407                 :            :     // frequency from the subdatabase, and so may select different terms in
     408                 :            :     // each subdatabase.
     409 [ +  - ][ +  + ]:          7 :     SKIP_TEST_FOR_BACKEND("multi");
     410 [ +  - ][ +  - ]:          6 :     Xapian::Database db = get_database("apitest_simpledata");
     411         [ +  - ]:         12 :     Xapian::Enquire enq(db);
     412                 :          6 :     const Xapian::Query::op o = Xapian::Query::OP_WILDCARD;
     413                 :            : 
     414                 :          6 :     const wildcard_testcase * p = wildcard1_testcases;
     415         [ +  + ]:         30 :     while (p->pattern) {
     416 [ +  - ][ +  - ]:         24 :         tout << p->pattern << endl;
     417                 :         24 :         const char * const * tend = p->terms + 4;
     418         [ +  + ]:         66 :         while (tend[-1] == NULL) --tend;
     419 [ +  + ][ +  - ]:         24 :         bool expect_exception = (tend - p->terms == 4 && tend[-1][0] == '\0');
     420                 :         24 :         Xapian::Query q;
     421         [ +  - ]:         24 :         if (p->max_type) {
     422                 :            :             int max_type;
     423   [ +  +  +  - ]:         24 :             switch (p->max_type) {
     424                 :            :                 case 'E':
     425                 :         12 :                     max_type = Xapian::Query::WILDCARD_LIMIT_ERROR;
     426                 :         12 :                     break;
     427                 :            :                 case 'F':
     428                 :          6 :                     max_type = Xapian::Query::WILDCARD_LIMIT_FIRST;
     429                 :          6 :                     break;
     430                 :            :                 case 'M':
     431                 :          6 :                     max_type = Xapian::Query::WILDCARD_LIMIT_MOST_FREQUENT;
     432                 :          6 :                     break;
     433                 :            :                 default:
     434                 :          0 :                     return false;
     435                 :            :             }
     436 [ +  - ][ +  - ]:         24 :             q = Xapian::Query(o, p->pattern, p->max_expansion, max_type);
                 [ +  - ]
     437                 :            :         } else {
     438 [ #  # ][ #  # ]:          0 :             q = Xapian::Query(o, p->pattern, p->max_expansion);
                 [ #  # ]
     439                 :            :         }
     440         [ +  - ]:         24 :         enq.set_query(q);
     441                 :            :         try {
     442         [ +  + ]:         24 :             Xapian::MSet mset = enq.get_mset(0, 10);
     443 [ -  + ][ #  # ]:         18 :             TEST(!expect_exception);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     444 [ +  - ][ +  - ]:         18 :             q = Xapian::Query(q.OP_SYNONYM, p->terms, tend);
     445         [ +  - ]:         18 :             enq.set_query(q);
     446         [ +  - ]:         36 :             Xapian::MSet mset2 = enq.get_mset(0, 10);
     447 [ +  - ][ +  - ]:         18 :             TEST_EQUAL(mset.size(), mset2.size());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     448 [ +  - ][ +  - ]:         42 :             TEST(mset_range_is_same(mset, 0, mset2, 0, mset.size()));
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     449 [ -  + ][ +  - ]:         12 :         } catch (const Xapian::WildcardError &) {
     450   [ -  +  #  #  :          6 :             TEST(expect_exception);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     451                 :            :         }
     452         [ +  - ]:         24 :         ++p;
     453                 :         24 :     }
     454                 :            : 
     455                 :         12 :     return true;
     456                 :            : }
     457                 :            : 
     458                 :            : /// Regression test for #696, fixed in 1.3.4.
     459                 :          7 : DEFINE_TESTCASE(wildcard2, backend) {
     460                 :            :     // FIXME: The counting of terms the wildcard expands to is per subdatabase,
     461                 :            :     // so the wildcard may expand to more terms than the limit if some aren't
     462                 :            :     // in all subdatabases.  Also WILDCARD_LIMIT_MOST_FREQUENT uses the
     463                 :            :     // frequency from the subdatabase, and so may select different terms in
     464                 :            :     // each subdatabase.
     465 [ +  - ][ +  + ]:          7 :     SKIP_TEST_FOR_BACKEND("multi");
     466 [ +  - ][ +  - ]:          6 :     Xapian::Database db = get_database("apitest_simpledata");
     467         [ +  - ]:         12 :     Xapian::Enquire enq(db);
     468                 :          6 :     const Xapian::Query::op o = Xapian::Query::OP_WILDCARD;
     469                 :            : 
     470                 :          6 :     const int max_type = Xapian::Query::WILDCARD_LIMIT_MOST_FREQUENT;
     471 [ +  - ][ +  - ]:         12 :     Xapian::Query q0(o, "w", 2, max_type);
     472 [ +  - ][ +  - ]:         12 :     Xapian::Query q(o, "s", 2, max_type);
     473 [ +  - ][ +  - ]:         12 :     Xapian::Query q2(o, "t", 2, max_type);
     474 [ +  - ][ +  - ]:          6 :     q = Xapian::Query(q.OP_OR, q0, q);
     475 [ +  - ][ +  - ]:          6 :     q = Xapian::Query(q.OP_OR, q, q2);
     476         [ +  - ]:          6 :     enq.set_query(q);
     477         [ +  - ]:         12 :     Xapian::MSet mset = enq.get_mset(0, 10);
     478 [ +  - ][ -  + ]:          6 :     TEST_EQUAL(mset.size(), 6);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     479                 :            : 
     480                 :          6 :     return true;
     481                 :            : }
     482                 :            : 
     483                 :          7 : DEFINE_TESTCASE(dualprefixwildcard1, backend) {
     484 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     485                 :            :     Xapian::Query q(Xapian::Query::OP_SYNONYM,
     486                 :            :                     Xapian::Query(Xapian::Query::OP_WILDCARD, "fo"),
     487 [ +  - ][ +  - ]:         14 :                     Xapian::Query(Xapian::Query::OP_WILDCARD, "Sfo"));
         [ +  - ][ +  - ]
                 [ +  - ]
     488 [ +  - ][ +  - ]:          7 :     tout << q.get_description() << endl;
                 [ +  - ]
     489         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     490         [ +  - ]:          7 :     enq.set_query(q);
     491 [ +  - ][ +  - ]:          7 :     TEST_EQUAL(enq.get_mset(0, 5).size(), 2);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     492                 :          7 :     return true;
     493                 :            : }
     494                 :            : 
     495                 :            : /// Test special case wildcards.
     496                 :          1 : DEFINE_TESTCASE(specialwildcard1, !backend) {
     497                 :          1 :     const Xapian::Query::op o = Xapian::Query::OP_WILDCARD;
     498                 :          1 :     const auto f = Xapian::Query::WILDCARD_PATTERN_GLOB;
     499                 :            : 
     500                 :            :     // Empty wildcard -> MatchNothing.
     501 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "", 0, f).get_description(), "Query()");
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     502                 :            : 
     503                 :            :     // "*", "?*", etc -> MatchAll.
     504                 :            : #define QUERY_ALLDOCS "Query(<alldocuments>)"
     505 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "*", 0, f).get_description(), QUERY_ALLDOCS);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     506 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "**", 0, f).get_description(), QUERY_ALLDOCS);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     507 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "?*", 0, f).get_description(), QUERY_ALLDOCS);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     508 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "*?", 0, f).get_description(), QUERY_ALLDOCS);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     509 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(Xapian::Query(o, "*?*", 0, f).get_description(), QUERY_ALLDOCS);
         [ +  - ][ +  - ]
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     510                 :            : 
     511                 :          1 :     return true;
     512                 :            : }
     513                 :            : 
     514                 :            : /// Test `?` extended wildcard.
     515                 :          5 : DEFINE_TESTCASE(singlecharwildcard1, writable) {
     516 [ +  - ][ +  - ]:          5 :     Xapian::WritableDatabase db = get_writable_database();
     517                 :            :     {
     518         [ +  - ]:          5 :         Xapian::Document doc;
     519 [ +  - ][ +  - ]:          5 :         doc.add_term("test");
     520         [ +  - ]:          5 :         db.add_document(doc);
     521                 :            :     }
     522                 :            :     {
     523         [ +  - ]:          5 :         Xapian::Document doc;
     524 [ +  - ][ +  - ]:          5 :         doc.add_term("t\xc3\xaast");
     525         [ +  - ]:          5 :         db.add_document(doc);
     526                 :            :     }
     527                 :            :     {
     528         [ +  - ]:          5 :         Xapian::Document doc;
     529 [ +  - ][ +  - ]:          5 :         doc.add_term("t\xe1\x80\x80st");
     530         [ +  - ]:          5 :         db.add_document(doc);
     531                 :            :     }
     532                 :            :     {
     533         [ +  - ]:          5 :         Xapian::Document doc;
     534 [ +  - ][ +  - ]:          5 :         doc.add_term("t\xf3\x80\x80\x80st");
     535         [ +  - ]:          5 :         db.add_document(doc);
     536                 :            :     }
     537                 :            :     {
     538         [ +  - ]:          5 :         Xapian::Document doc;
     539 [ +  - ][ +  - ]:          5 :         doc.add_term("toast");
     540         [ +  - ]:          5 :         db.add_document(doc);
     541                 :            :     }
     542                 :            :     {
     543         [ +  - ]:          5 :         Xapian::Document doc;
     544 [ +  - ][ +  - ]:          5 :         doc.add_term("t*t");
     545         [ +  - ]:          5 :         db.add_document(doc);
     546                 :            :     }
     547         [ +  - ]:          5 :     db.commit();
     548                 :            : 
     549         [ +  - ]:         10 :     Xapian::Enquire enq(db);
     550         [ +  - ]:          5 :     enq.set_weighting_scheme(Xapian::BoolWeight());
     551                 :            : 
     552                 :          5 :     const Xapian::Query::op o = Xapian::Query::OP_WILDCARD;
     553                 :          5 :     const auto f = Xapian::Query::WILDCARD_PATTERN_SINGLE;
     554                 :            : 
     555                 :            :     {
     556                 :            :         // Check that `?` matches one Unicode character.
     557 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "t?st", 0, f));
                 [ +  - ]
     558         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     559         [ +  - ]:          5 :         mset_expect_order(mset, 1, 2, 3, 4);
     560                 :            :     }
     561                 :            : 
     562                 :            :     {
     563                 :            :         // Check that `??` doesn't match a single two-byte UTF-8 character.
     564 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "t??st", 0, f));
                 [ +  - ]
     565         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     566         [ +  - ]:          5 :         mset_expect_order(mset, 5);
     567                 :            :     }
     568                 :            : 
     569                 :            :     {
     570                 :            :         // Check that `*` is handled as a literal character not a wildcard.
     571 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "t*t", 0, f));
                 [ +  - ]
     572         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     573         [ +  - ]:          5 :         mset_expect_order(mset, 6);
     574                 :            :     }
     575                 :            : 
     576                 :          5 :     return true;
     577                 :            : }
     578                 :            : 
     579                 :            : /// Test `*` extended wildcard.
     580                 :          5 : DEFINE_TESTCASE(multicharwildcard1, writable) {
     581 [ +  - ][ +  - ]:          5 :     Xapian::WritableDatabase db = get_writable_database();
     582                 :            :     {
     583         [ +  - ]:          5 :         Xapian::Document doc;
     584 [ +  - ][ +  - ]:          5 :         doc.add_term("ananas");
     585         [ +  - ]:          5 :         db.add_document(doc);
     586                 :            :     }
     587                 :            :     {
     588         [ +  - ]:          5 :         Xapian::Document doc;
     589 [ +  - ][ +  - ]:          5 :         doc.add_term("annas");
     590         [ +  - ]:          5 :         db.add_document(doc);
     591                 :            :     }
     592                 :            :     {
     593         [ +  - ]:          5 :         Xapian::Document doc;
     594 [ +  - ][ +  - ]:          5 :         doc.add_term("bananas");
     595         [ +  - ]:          5 :         db.add_document(doc);
     596                 :            :     }
     597                 :            :     {
     598         [ +  - ]:          5 :         Xapian::Document doc;
     599 [ +  - ][ +  - ]:          5 :         doc.add_term("banannas");
     600         [ +  - ]:          5 :         db.add_document(doc);
     601                 :            :     }
     602                 :            :     {
     603         [ +  - ]:          5 :         Xapian::Document doc;
     604 [ +  - ][ +  - ]:          5 :         doc.add_term("b?nanas");
     605         [ +  - ]:          5 :         db.add_document(doc);
     606                 :            :     }
     607         [ +  - ]:          5 :     db.commit();
     608                 :            : 
     609         [ +  - ]:         10 :     Xapian::Enquire enq(db);
     610         [ +  - ]:          5 :     enq.set_weighting_scheme(Xapian::BoolWeight());
     611                 :            : 
     612                 :          5 :     const Xapian::Query::op o = Xapian::Query::OP_WILDCARD;
     613                 :          5 :     const auto f = Xapian::Query::WILDCARD_PATTERN_MULTI;
     614                 :            : 
     615                 :            :     {
     616                 :            :         // Check `*` can handle partial matches before and after.
     617 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "b*anas", 0, f));
                 [ +  - ]
     618         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     619         [ +  - ]:          5 :         mset_expect_order(mset, 3, 5);
     620                 :            :     }
     621                 :            : 
     622                 :            :     {
     623                 :            :         // Check leading `*` works.
     624 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "*anas", 0, f));
                 [ +  - ]
     625         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     626         [ +  - ]:          5 :         mset_expect_order(mset, 1, 3, 5);
     627                 :            :     }
     628                 :            : 
     629                 :            :     {
     630                 :            :         // Check more than one `*` works.
     631 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "*ann*", 0, f));
                 [ +  - ]
     632         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     633         [ +  - ]:          5 :         mset_expect_order(mset, 2, 4);
     634                 :            :     }
     635                 :            : 
     636                 :            :     {
     637                 :            :         // Check that `?` is handled as a literal character not a wildcard.
     638 [ +  - ][ +  - ]:          5 :         enq.set_query(Xapian::Query(o, "b?n*", 0, f));
                 [ +  - ]
     639         [ +  - ]:          5 :         Xapian::MSet mset = enq.get_mset(0, 100);
     640         [ +  - ]:          5 :         mset_expect_order(mset, 5);
     641                 :            :     }
     642                 :            : 
     643                 :          5 :     return true;
     644                 :            : }
     645                 :            : 
     646                 :            : struct positional_testcase {
     647                 :            :     int window;
     648                 :            :     const char * terms[4];
     649                 :            :     Xapian::docid result;
     650                 :            : };
     651                 :            : 
     652                 :            : static const
     653                 :            : positional_testcase loosephrase1_testcases[] = {
     654                 :            :     { 5, { "expect", "to", "mset", 0 }, 0 },
     655                 :            :     { 5, { "word", "well", "the", 0 }, 2 },
     656                 :            :     { 5, { "if", "word", "doesnt", 0 }, 0 },
     657                 :            :     { 5, { "at", "line", "three", 0 }, 0 },
     658                 :            :     { 5, { "paragraph", "other", "the", 0 }, 0 },
     659                 :            :     { 5, { "other", "the", "with", 0 }, 0 },
     660                 :            :     { 0, { 0, 0, 0, 0 }, 0 }
     661                 :            : };
     662                 :            : 
     663                 :            : /// Regression test for bug fixed in 1.3.3 and 1.2.21.
     664                 :          7 : DEFINE_TESTCASE(loosephrase1, backend) {
     665 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     666         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     667                 :            : 
     668                 :          7 :     const positional_testcase * p = loosephrase1_testcases;
     669         [ +  + ]:         49 :     while (p->window) {
     670                 :         42 :         const char * const * tend = p->terms + 4;
     671         [ +  + ]:         84 :         while (tend[-1] == NULL) --tend;
     672         [ +  - ]:         42 :         Xapian::Query q(Xapian::Query::OP_PHRASE, p->terms, tend, p->window);
     673         [ +  - ]:         42 :         enq.set_query(q);
     674         [ +  - ]:         84 :         Xapian::MSet mset = enq.get_mset(0, 10);
     675         [ +  + ]:         42 :         if (p->result == 0) {
     676 [ +  - ][ -  + ]:         35 :             TEST(mset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     677                 :            :         } else {
     678 [ +  - ][ -  + ]:          7 :             TEST_EQUAL(mset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     679 [ +  - ][ +  - ]:          7 :             TEST_EQUAL(*mset[0], p->result);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     680                 :            :         }
     681                 :         42 :         ++p;
     682                 :         42 :     }
     683                 :            : 
     684                 :          7 :     return true;
     685                 :            : }
     686                 :            : 
     687                 :            : static const
     688                 :            : positional_testcase loosenear1_testcases[] = {
     689                 :            :     { 4, { "test", "the", "with", 0 }, 1 },
     690                 :            :     { 4, { "expect", "word", "the", 0 }, 2 },
     691                 :            :     { 4, { "line", "be", "blank", 0 }, 1 },
     692                 :            :     { 2, { "banana", "banana", 0, 0 }, 0 },
     693                 :            :     { 3, { "banana", "banana", 0, 0 }, 0 },
     694                 :            :     { 2, { "word", "word", 0, 0 }, 2 },
     695                 :            :     { 4, { "work", "meant", "work", 0 }, 0 },
     696                 :            :     { 4, { "this", "one", "yet", "one" }, 0 },
     697                 :            :     { 0, { 0, 0, 0, 0 }, 0 }
     698                 :            : };
     699                 :            : 
     700                 :            : /// Regression tests for bugs fixed in 1.3.3 and 1.2.21.
     701                 :          7 : DEFINE_TESTCASE(loosenear1, backend) {
     702 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     703         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     704                 :            : 
     705                 :          7 :     const positional_testcase * p = loosenear1_testcases;
     706         [ +  + ]:         63 :     while (p->window) {
     707                 :         56 :         const char * const * tend = p->terms + 4;
     708         [ +  + ]:        126 :         while (tend[-1] == NULL) --tend;
     709         [ +  - ]:         56 :         Xapian::Query q(Xapian::Query::OP_NEAR, p->terms, tend, p->window);
     710         [ +  - ]:         56 :         enq.set_query(q);
     711         [ +  - ]:        112 :         Xapian::MSet mset = enq.get_mset(0, 10);
     712         [ +  + ]:         56 :         if (p->result == 0) {
     713 [ +  - ][ -  + ]:         28 :             TEST(mset.empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     714                 :            :         } else {
     715 [ +  - ][ -  + ]:         28 :             TEST_EQUAL(mset.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     716 [ +  - ][ +  - ]:         28 :             TEST_EQUAL(*mset[0], p->result);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     717                 :            :         }
     718                 :         56 :         ++p;
     719                 :         56 :     }
     720                 :            : 
     721                 :          7 :     return true;
     722                 :            : }
     723                 :            : 
     724                 :            : /// Regression test for bug fixed in 1.3.6 - the first case segfaulted in 1.3.x.
     725                 :          7 : DEFINE_TESTCASE(complexphrase1, backend) {
     726 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     727         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     728                 :            :     Xapian::Query query(Xapian::Query::OP_PHRASE,
     729 [ +  - ][ +  - ]:         14 :             Xapian::Query("a") | Xapian::Query("b"),
         [ +  - ][ +  - ]
                 [ +  - ]
     730 [ +  - ][ +  - ]:         28 :             Xapian::Query("i"));
                 [ +  - ]
     731         [ +  - ]:          7 :     enq.set_query(query);
     732 [ +  - ][ +  - ]:          7 :     TEST(enq.get_mset(0, 10).empty());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     733                 :            :     Xapian::Query query2(Xapian::Query::OP_PHRASE,
     734 [ +  - ][ +  - ]:         14 :             Xapian::Query("a") | Xapian::Query("b"),
         [ +  - ][ +  - ]
                 [ +  - ]
     735 [ +  - ][ +  - ]:         28 :             Xapian::Query("c"));
                 [ +  - ]
     736         [ +  - ]:          7 :     enq.set_query(query2);
     737 [ +  - ][ +  - ]:          7 :     TEST(enq.get_mset(0, 10).empty());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     738                 :          7 :     return true;
     739                 :            : }
     740                 :            : 
     741                 :            : /// Regression test for bug fixed in 1.3.6 - the first case segfaulted in 1.3.x.
     742                 :          7 : DEFINE_TESTCASE(complexnear1, backend) {
     743 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     744         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     745                 :            :     Xapian::Query query(Xapian::Query::OP_NEAR,
     746 [ +  - ][ +  - ]:         14 :             Xapian::Query("a") | Xapian::Query("b"),
         [ +  - ][ +  - ]
                 [ +  - ]
     747 [ +  - ][ +  - ]:         28 :             Xapian::Query("i"));
                 [ +  - ]
     748         [ +  - ]:          7 :     enq.set_query(query);
     749 [ +  - ][ +  - ]:          7 :     TEST(enq.get_mset(0, 10).empty());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     750                 :            :     Xapian::Query query2(Xapian::Query::OP_NEAR,
     751 [ +  - ][ +  - ]:         14 :             Xapian::Query("a") | Xapian::Query("b"),
         [ +  - ][ +  - ]
                 [ +  - ]
     752 [ +  - ][ +  - ]:         28 :             Xapian::Query("c"));
                 [ +  - ]
     753         [ +  - ]:          7 :     enq.set_query(query2);
     754 [ +  - ][ +  - ]:          7 :     TEST(enq.get_mset(0, 10).empty());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     755                 :          7 :     return true;
     756                 :            : }
     757                 :            : 
     758                 :            : /// Check subqueries of MatchAll, MatchNothing and PostingSource are supported.
     759                 :          7 : DEFINE_TESTCASE(complexphrase2, backend) {
     760 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     761         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     762         [ +  - ]:         14 :     Xapian::ValueWeightPostingSource ps(0);
     763                 :            :     Xapian::Query subqs[3] = {
     764                 :            :         Xapian::Query(Xapian::Query::OP_PHRASE,
     765                 :            :             Xapian::Query("a"),
     766                 :            :             Xapian::Query(&ps)),
     767                 :            :         Xapian::Query(Xapian::Query::OP_PHRASE,
     768                 :            :             Xapian::Query("and"),
     769                 :            :             Xapian::Query::MatchAll),
     770                 :            :         Xapian::Query(Xapian::Query::OP_PHRASE,
     771                 :            :             Xapian::Query("at"),
     772                 :            :             Xapian::Query::MatchNothing)
     773 [ +  - ][ +  - ]:         35 :     };
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ #  #  
             #  #  #  # ]
     774         [ +  - ]:         14 :     Xapian::Query query(Xapian::Query::OP_OR, subqs, subqs + 3);
     775         [ +  - ]:          7 :     enq.set_query(query);
     776         [ +  - ]:          7 :     (void)enq.get_mset(0, 10);
     777                 :          7 :     return true;
     778                 :            : }
     779                 :            : 
     780                 :            : /// Check subqueries of MatchAll, MatchNothing and PostingSource are supported.
     781                 :          7 : DEFINE_TESTCASE(complexnear2, backend) {
     782 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     783         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     784         [ +  - ]:         14 :     Xapian::ValueWeightPostingSource ps(0);
     785                 :            :     Xapian::Query subqs[3] = {
     786                 :            :         Xapian::Query(Xapian::Query::OP_NEAR,
     787                 :            :             Xapian::Query("a"),
     788                 :            :             Xapian::Query(&ps)),
     789                 :            :         Xapian::Query(Xapian::Query::OP_NEAR,
     790                 :            :             Xapian::Query("and"),
     791                 :            :             Xapian::Query::MatchAll),
     792                 :            :         Xapian::Query(Xapian::Query::OP_NEAR,
     793                 :            :             Xapian::Query("at"),
     794                 :            :             Xapian::Query::MatchNothing)
     795 [ +  - ][ +  - ]:         35 :     };
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ #  #  
             #  #  #  # ]
     796         [ +  - ]:         14 :     Xapian::Query query(Xapian::Query::OP_OR, subqs, subqs + 3);
     797         [ +  - ]:          7 :     enq.set_query(query);
     798         [ +  - ]:          7 :     (void)enq.get_mset(0, 10);
     799                 :          7 :     return true;
     800                 :            : }
     801                 :            : 
     802                 :            : /// A zero estimated number of matches broke the code to round the estimate.
     803                 :          7 : DEFINE_TESTCASE(zeroestimate1, backend) {
     804 [ +  - ][ +  - ]:          7 :     Xapian::Enquire enquire(get_database("apitest_simpledata"));
                 [ +  - ]
     805                 :            :     Xapian::Query phrase(Xapian::Query::OP_PHRASE,
     806                 :            :                          Xapian::Query("absolute"),
     807 [ +  - ][ +  - ]:         14 :                          Xapian::Query("rubbish"));
         [ +  - ][ +  - ]
                 [ +  - ]
     808 [ +  - ][ +  - ]:          7 :     enquire.set_query(phrase &~ Xapian::Query("queri"));
         [ +  - ][ +  - ]
     809         [ +  - ]:         14 :     Xapian::MSet mset = enquire.get_mset(0, 0);
     810 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.get_matches_estimated(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     811                 :          7 :     return true;
     812                 :            : }
     813                 :            : 
     814                 :            : /// Feature test for OR under OP_PHRASE support added in 1.4.3.
     815                 :          7 : DEFINE_TESTCASE(complexphrase3, backend) {
     816 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     817         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     818                 :            :     Xapian::Query query(Xapian::Query::OP_PHRASE,
     819 [ +  - ][ +  - ]:         14 :             Xapian::Query("is") | Xapian::Query("as") | Xapian::Query("be"),
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     820 [ +  - ][ +  - ]:         28 :             Xapian::Query("a"));
                 [ +  - ]
     821         [ +  - ]:          7 :     enq.set_query(query);
     822 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1);
     823                 :            :     Xapian::Query query2(Xapian::Query::OP_PHRASE,
     824                 :            :             Xapian::Query("a"),
     825 [ +  - ][ +  - ]:         14 :             Xapian::Query("is") | Xapian::Query("as") | Xapian::Query("be"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     826         [ +  - ]:          7 :     enq.set_query(query2);
     827 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10));
     828                 :            :     Xapian::Query query3(Xapian::Query::OP_PHRASE,
     829 [ +  - ][ +  - ]:         14 :             Xapian::Query("one") | Xapian::Query("with"),
         [ +  - ][ +  - ]
                 [ +  - ]
     830 [ +  - ][ +  - ]:         28 :             Xapian::Query("the") | Xapian::Query("of") | Xapian::Query("line"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     831         [ +  - ]:          7 :     enq.set_query(query3);
     832 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1, 4, 5);
     833                 :            :     Xapian::Query query4(Xapian::Query::OP_PHRASE,
     834 [ +  - ][ +  - ]:         14 :             Xapian::Query("the") | Xapian::Query("of") | Xapian::Query("line"),
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     835 [ +  - ][ +  - ]:         28 :             Xapian::Query("one") | Xapian::Query("with"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     836         [ +  - ]:          7 :     enq.set_query(query4);
     837 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10));
     838                 :          7 :     return true;
     839                 :            : }
     840                 :            : 
     841                 :            : /// Feature test for OR under OP_NEAR support added in 1.4.3.
     842                 :          7 : DEFINE_TESTCASE(complexnear3, backend) {
     843 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     844         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     845                 :            :     Xapian::Query query(Xapian::Query::OP_NEAR,
     846 [ +  - ][ +  - ]:         14 :             Xapian::Query("is") | Xapian::Query("as") | Xapian::Query("be"),
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     847 [ +  - ][ +  - ]:         28 :             Xapian::Query("a"));
                 [ +  - ]
     848         [ +  - ]:          7 :     enq.set_query(query);
     849 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1);
     850                 :            :     Xapian::Query query2(Xapian::Query::OP_NEAR,
     851                 :            :             Xapian::Query("a"),
     852 [ +  - ][ +  - ]:         14 :             Xapian::Query("is") | Xapian::Query("as") | Xapian::Query("be"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     853         [ +  - ]:          7 :     enq.set_query(query2);
     854 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1);
     855                 :            :     Xapian::Query query3(Xapian::Query::OP_NEAR,
     856 [ +  - ][ +  - ]:         14 :             Xapian::Query("one") | Xapian::Query("with"),
         [ +  - ][ +  - ]
                 [ +  - ]
     857 [ +  - ][ +  - ]:         28 :             Xapian::Query("the") | Xapian::Query("of") | Xapian::Query("line"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     858         [ +  - ]:          7 :     enq.set_query(query3);
     859 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1, 4, 5);
     860                 :            :     Xapian::Query query4(Xapian::Query::OP_NEAR,
     861 [ +  - ][ +  - ]:         14 :             Xapian::Query("the") | Xapian::Query("of") | Xapian::Query("line"),
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     862 [ +  - ][ +  - ]:         28 :             Xapian::Query("one") | Xapian::Query("with"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     863         [ +  - ]:          7 :     enq.set_query(query4);
     864 [ +  - ][ +  - ]:          7 :     mset_expect_order(enq.get_mset(0, 10), 1, 4, 5);
     865                 :          7 :     return true;
     866                 :            : }
     867                 :            : 
     868                 :            : static void
     869                 :          3 : gen_subdbwithoutpos1_db(Xapian::WritableDatabase& db, const string&)
     870                 :            : {
     871         [ +  - ]:          3 :     Xapian::Document doc;
     872 [ +  - ][ +  - ]:          3 :     doc.add_term("this");
     873 [ +  - ][ +  - ]:          3 :     doc.add_term("paragraph");
     874 [ +  - ][ +  - ]:          3 :     doc.add_term("wibble", 5);
     875         [ +  - ]:          3 :     db.add_document(doc);
     876                 :          3 : }
     877                 :            : 
     878                 :          3 : DEFINE_TESTCASE(subdbwithoutpos1, generated) {
     879 [ +  - ][ +  - ]:          3 :     Xapian::Database db(get_database("apitest_simpledata"));
     880                 :            : 
     881                 :            :     Xapian::Query q(Xapian::Query::OP_PHRASE,
     882                 :            :                     Xapian::Query("this"),
     883 [ +  - ][ +  - ]:          6 :                     Xapian::Query("paragraph"));
         [ +  - ][ +  - ]
                 [ +  - ]
     884                 :            : 
     885         [ +  - ]:          6 :     Xapian::Enquire enq1(db);
     886         [ +  - ]:          3 :     enq1.set_query(q);
     887         [ +  - ]:          6 :     Xapian::MSet mset1 = enq1.get_mset(0, 10);
     888 [ +  - ][ -  + ]:          3 :     TEST_EQUAL(mset1.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     889                 :            : 
     890                 :            :     Xapian::Database db2 =
     891 [ +  - ][ +  - ]:          6 :         get_database("subdbwithoutpos1", gen_subdbwithoutpos1_db);
                 [ +  - ]
     892                 :            : 
     893                 :            :     // If a database has no positional info, OP_PHRASE -> OP_AND.
     894         [ +  - ]:          6 :     Xapian::Enquire enq2(db2);
     895         [ +  - ]:          3 :     enq2.set_query(q);
     896         [ +  - ]:          6 :     Xapian::MSet mset2 = enq2.get_mset(0, 10);
     897 [ +  - ][ -  + ]:          3 :     TEST_EQUAL(mset2.size(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     898                 :            : 
     899                 :            :     // If one sub-database in a combined database has no positional info but
     900                 :            :     // other sub-databases do, then we shouldn't convert OP_PHRASE to OP_AND
     901                 :            :     // (but prior to 1.4.3 we did).
     902         [ +  - ]:          3 :     db.add_database(db2);
     903         [ +  - ]:          6 :     Xapian::Enquire enq3(db);
     904         [ +  - ]:          3 :     enq3.set_query(q);
     905         [ +  - ]:          6 :     Xapian::MSet mset3 = enq3.get_mset(0, 10);
     906 [ +  - ][ -  + ]:          3 :     TEST_EQUAL(mset3.size(), 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     907                 :            :     // Regression test for bug introduced in 1.4.3 which led to a division by
     908                 :            :     // zero and then (at least on Linux) we got 1% here.
     909 [ +  - ][ +  - ]:          3 :     TEST_EQUAL(mset3[0].get_percent(), 100);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     910                 :            : 
     911                 :            :     // Regression test for https://trac.xapian.org/ticket/752
     912 [ +  - ][ +  - ]:          3 :     enq3.set_query((Xapian::Query("this") & q) | Xapian::Query("wibble"));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     913 [ +  - ][ +  - ]:          3 :     mset3 = enq3.get_mset(0, 10);
     914 [ +  - ][ -  + ]:          3 :     TEST_EQUAL(mset3.size(), 4);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     915                 :            : 
     916                 :          3 :     return true;
     917                 :            : }
     918                 :            : 
     919                 :            : // Regression test for bug fixed in 1.4.4 and 1.2.25.
     920                 :          7 : DEFINE_TESTCASE(notandor1, backend) {
     921 [ +  - ][ +  - ]:          7 :     Xapian::Database db(get_database("etext"));
     922                 :            :     Xapian::Query q =
     923 [ +  - ][ +  - ]:         14 :         Xapian::Query("the") &~ (Xapian::Query("friedrich") &
                 [ +  - ]
     924 [ +  - ][ +  - ]:         28 :                 (Xapian::Query("day") | Xapian::Query("night")));
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     925         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     926         [ +  - ]:          7 :     enq.set_query(q);
     927                 :            : 
     928 [ +  - ][ +  - ]:         14 :     Xapian::MSet mset = enq.get_mset(0, 10, db.get_doccount());
     929 [ +  - ][ -  + ]:          7 :     TEST_EQUAL(mset.get_matches_estimated(), 344);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     930                 :            : 
     931                 :          7 :     return true;
     932                 :            : }

Generated by: LCOV version 1.11