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 : : }
|