Branch data Line data Source code
1 : : /* api_anydb.cc: tests which work with any backend
2 : : *
3 : : * Copyright 1999,2000,2001 BrightStation PLC
4 : : * Copyright 2002 Ananova Ltd
5 : : * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Olly Betts
6 : : * Copyright 2006,2008 Lemur Consulting Ltd
7 : : * Copyright 2011 Action Without Borders
8 : : *
9 : : * This program is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU General Public License as
11 : : * published by the Free Software Foundation; either version 2 of the
12 : : * License, or (at your option) any later version.
13 : : *
14 : : * This program is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : : * GNU General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU General Public License
20 : : * along with this program; if not, write to the Free Software
21 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 : : * USA
23 : : */
24 : :
25 : : #include <config.h>
26 : :
27 : : #include "api_anydb.h"
28 : :
29 : : #include <algorithm>
30 : : #include <string>
31 : :
32 : : #include <xapian.h>
33 : : #include "backendmanager_local.h"
34 : : #include "testsuite.h"
35 : : #include "testutils.h"
36 : : #include "utils.h"
37 : :
38 : : #include "apitest.h"
39 : :
40 : : #include <list>
41 : :
42 : : using namespace std;
43 : :
44 : : static void
45 : 0 : print_mset_weights(const Xapian::MSet &mset)
46 : : {
47 : 0 : Xapian::MSetIterator i = mset.begin();
48 [ # # ]: 0 : for ( ; i != mset.end(); ++i) {
49 : 0 : tout << " " << i.get_weight();
50 : 0 : }
51 : 0 : }
52 : :
53 : : static void
54 : 0 : print_mset_percentages(const Xapian::MSet &mset)
55 : : {
56 : 0 : Xapian::MSetIterator i = mset.begin();
57 [ # # ]: 0 : for ( ; i != mset.end(); ++i) {
58 : 0 : tout << " " << mset.convert_to_percent(i);
59 : 0 : }
60 : 0 : }
61 : :
62 : : static Xapian::Query
63 : 247 : query(Xapian::Query::op op,
64 : : const string & t1 = string(), const string & t2 = string(),
65 : : const string & t3 = string(), const string & t4 = string(),
66 : : const string & t5 = string(), const string & t6 = string(),
67 : : const string & t7 = string(), const string & t8 = string(),
68 : : const string & t9 = string(), const string & t10 = string())
69 : : {
70 : 247 : vector<string> v;
71 : 247 : Xapian::Stem stemmer("english");
72 [ + - ]: 247 : if (!t1.empty()) v.push_back(stemmer(t1));
73 [ + + ]: 247 : if (!t2.empty()) v.push_back(stemmer(t2));
74 [ + + ]: 247 : if (!t3.empty()) v.push_back(stemmer(t3));
75 [ + + ]: 247 : if (!t4.empty()) v.push_back(stemmer(t4));
76 [ - + ]: 247 : if (!t5.empty()) v.push_back(stemmer(t5));
77 [ - + ]: 247 : if (!t6.empty()) v.push_back(stemmer(t6));
78 [ - + ]: 247 : if (!t7.empty()) v.push_back(stemmer(t7));
79 [ - + ]: 247 : if (!t8.empty()) v.push_back(stemmer(t8));
80 [ - + ]: 247 : if (!t9.empty()) v.push_back(stemmer(t9));
81 [ - + ]: 247 : if (!t10.empty()) v.push_back(stemmer(t10));
82 : 247 : return Xapian::Query(op, v.begin(), v.end());
83 : : }
84 : :
85 : : static Xapian::Query
86 : 20 : query(Xapian::Query::op op, Xapian::termcount parameter,
87 : : const string & t1 = string(), const string & t2 = string(),
88 : : const string & t3 = string(), const string & t4 = string(),
89 : : const string & t5 = string(), const string & t6 = string(),
90 : : const string & t7 = string(), const string & t8 = string(),
91 : : const string & t9 = string(), const string & t10 = string())
92 : : {
93 : 20 : vector<string> v;
94 : 20 : Xapian::Stem stemmer("english");
95 [ + - ]: 20 : if (!t1.empty()) v.push_back(stemmer(t1));
96 [ + - ]: 20 : if (!t2.empty()) v.push_back(stemmer(t2));
97 [ + + ]: 20 : if (!t3.empty()) v.push_back(stemmer(t3));
98 [ - + ]: 20 : if (!t4.empty()) v.push_back(stemmer(t4));
99 [ - + ]: 20 : if (!t5.empty()) v.push_back(stemmer(t5));
100 [ - + ]: 20 : if (!t6.empty()) v.push_back(stemmer(t6));
101 [ - + ]: 20 : if (!t7.empty()) v.push_back(stemmer(t7));
102 [ - + ]: 20 : if (!t8.empty()) v.push_back(stemmer(t8));
103 [ - + ]: 20 : if (!t9.empty()) v.push_back(stemmer(t9));
104 [ - + ]: 20 : if (!t10.empty()) v.push_back(stemmer(t10));
105 : 20 : return Xapian::Query(op, v.begin(), v.end(), parameter);
106 : : }
107 : :
108 : : static Xapian::Query
109 : 152 : query(const string &t)
110 : : {
111 : 152 : return Xapian::Query(Xapian::Stem("english")(t));
112 : : }
113 : :
114 : : // #######################################################################
115 : : // # Tests start here
116 : :
117 : : // tests that the backend doesn't return zero docids
118 : 13 : DEFINE_TESTCASE(zerodocid1, backend) {
119 : : // open the database (in this case a simple text file
120 : : // we prepared earlier)
121 : :
122 : 13 : Xapian::Database mydb(get_database("apitest_onedoc"));
123 : :
124 : 13 : Xapian::Enquire enquire(mydb);
125 : :
126 : : // make a simple query, with one word in it - "word".
127 : 13 : enquire.set_query(Xapian::Query("word"));
128 : :
129 : : // retrieve the top ten results (we only expect one)
130 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
131 : :
132 : : // We've done the query, now check that the result is what
133 : : // we expect (1 document, with non-zero docid)
134 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
135 : :
136 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(*(mymset.begin()) != 0,
137 : : "A query on a database returned a zero docid");
138 : :
139 : 13 : return true;
140 : : }
141 : :
142 : : // tests that an empty query returns no matches
143 : 13 : DEFINE_TESTCASE(emptyquery1, backend) {
144 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
145 : :
146 : 13 : enquire.set_query(Xapian::Query());
147 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
148 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 0);
149 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
150 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
151 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 0);
152 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
153 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
154 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
155 : :
156 : 13 : vector<Xapian::Query> v;
157 : 13 : enquire.set_query(Xapian::Query(Xapian::Query::OP_AND, v.begin(), v.end()));
158 : 13 : mymset = enquire.get_mset(0, 10);
159 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 0);
160 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
161 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
162 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 0);
163 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
164 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
165 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
166 : :
167 : 13 : return true;
168 : : }
169 : :
170 : : // tests the document count for a simple query
171 : 13 : DEFINE_TESTCASE(simplequery1, backend) {
172 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
173 : 13 : enquire.set_query(Xapian::Query("word"));
174 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
175 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 2);
176 : 13 : return true;
177 : : }
178 : :
179 : : // tests for the right documents and weights returned with simple query
180 : 13 : DEFINE_TESTCASE(simplequery2, backend) {
181 : : // open the database (in this case a simple text file
182 : : // we prepared earlier)
183 : 13 : Xapian::Database db = get_database("apitest_simpledata");
184 : 13 : Xapian::Enquire enquire(db);
185 : 13 : enquire.set_query(Xapian::Query("word"));
186 : :
187 : : // retrieve the top results
188 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
189 : :
190 : : // We've done the query, now check that the result is what
191 : : // we expect (documents 2 and 4)
192 : 13 : mset_expect_order(mymset, 2, 4);
193 : :
194 : : // Check the weights
195 : 13 : Xapian::MSetIterator i = mymset.begin();
196 : : // These weights are for BM25Weight(1,0,1,0.5,0.5)
197 [ - + # # ]: 13 : TEST_EQUAL_DOUBLE(i.get_weight(), 1.04648168717725);
198 : 13 : i++;
199 [ - + # # ]: 13 : TEST_EQUAL_DOUBLE(i.get_weight(), 0.640987686595914);
200 : :
201 : 13 : return true;
202 : : }
203 : :
204 : : // tests for the right document count for another simple query
205 : 13 : DEFINE_TESTCASE(simplequery3, backend) {
206 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
207 : 13 : enquire.set_query(query("this"));
208 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
209 : :
210 : : // Check that 6 documents were returned.
211 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 6);
212 : :
213 : 13 : return true;
214 : : }
215 : :
216 : : // tests for the right document count for a wildcard query
217 : : // FIXME: move this to querytest (and just use an InMemory DB).
218 : 13 : DEFINE_TESTCASE(wildquery1, backend) {
219 : 13 : Xapian::QueryParser queryparser;
220 : : unsigned flags = Xapian::QueryParser::FLAG_WILDCARD |
221 : 13 : Xapian::QueryParser::FLAG_LOVEHATE;
222 : 13 : queryparser.set_stemmer(Xapian::Stem("english"));
223 : 13 : queryparser.set_stemming_strategy(Xapian::QueryParser::STEM_ALL);
224 : 13 : Xapian::Database db = get_database("apitest_simpledata");
225 : 13 : queryparser.set_database(db);
226 : 13 : Xapian::Enquire enquire(db);
227 : :
228 : 13 : Xapian::Query qobj = queryparser.parse_query("th*", flags);
229 : 13 : tout << qobj.get_description() << endl;
230 : 13 : enquire.set_query(qobj);
231 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
232 : : // Check that 6 documents were returned.
233 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 6);
234 : :
235 : 13 : qobj = queryparser.parse_query("notindb* \"this\"", flags);
236 : 13 : tout << qobj.get_description() << endl;
237 : 13 : enquire.set_query(qobj);
238 : 13 : mymset = enquire.get_mset(0, 10);
239 : : // Check that 6 documents were returned.
240 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 6);
241 : :
242 : 13 : qobj = queryparser.parse_query("+notindb* \"this\"", flags);
243 : 13 : tout << qobj.get_description() << endl;
244 : 13 : enquire.set_query(qobj);
245 : 13 : mymset = enquire.get_mset(0, 10);
246 : : // Check that 0 documents were returned.
247 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 0);
248 : :
249 : 13 : return true;
250 : : }
251 : :
252 : : // tests a query across multiple databases
253 : 13 : DEFINE_TESTCASE(multidb1, backend) {
254 : 13 : Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
255 : 13 : Xapian::Enquire enquire1(mydb1);
256 : :
257 : 13 : Xapian::Database mydb2(get_database("apitest_simpledata"));
258 : 13 : mydb2.add_database(get_database("apitest_simpledata2"));
259 : 13 : Xapian::Enquire enquire2(mydb2);
260 : :
261 : : // make a simple query, with one word in it - "word".
262 : 13 : Xapian::Query myquery("word");
263 : 13 : enquire1.set_query(myquery);
264 : 13 : enquire2.set_query(myquery);
265 : :
266 : : // retrieve the top ten results from each method of accessing
267 : : // multiple text files
268 : 13 : Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
269 : 13 : Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
270 : :
271 [ - + # # ]: 13 : TEST_EQUAL(mymset1.size(), mymset2.size());
272 [ - + ][ # # ]: 13 : TEST(mset_range_is_same_weights(mymset1, 0, mymset2, 0, mymset1.size()));
273 : 13 : return true;
274 : : }
275 : :
276 : : // tests a query across multiple databases with terms only
277 : : // in one of the two databases
278 : 10 : DEFINE_TESTCASE(multidb2, backend && !multi) {
279 : : Xapian::Database mydb1(get_database("apitest_simpledata",
280 : 10 : "apitest_simpledata2"));
281 : 10 : Xapian::Enquire enquire1(mydb1);
282 : :
283 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
284 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
285 : 10 : Xapian::Enquire enquire2(mydb2);
286 : :
287 : : // make a simple query
288 : 10 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
289 : 10 : enquire1.set_query(myquery);
290 : 10 : enquire2.set_query(myquery);
291 : :
292 : : // retrieve the top ten results from each method of accessing
293 : : // multiple text files
294 : 10 : Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
295 : 10 : Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
296 : :
297 [ - + # # ]: 10 : TEST_EQUAL(mymset1.size(), mymset2.size());
298 [ - + ][ # # ]: 10 : TEST(mset_range_is_same_weights(mymset1, 0, mymset2, 0, mymset1.size()));
299 : 10 : return true;
300 : : }
301 : :
302 : : // test that a multidb with 2 dbs query returns correct docids
303 : 10 : DEFINE_TESTCASE(multidb3, backend && !multi) {
304 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
305 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
306 : 10 : Xapian::Enquire enquire(mydb2);
307 : :
308 : : // make a query
309 : 10 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
310 : 10 : enquire.set_weighting_scheme(Xapian::BoolWeight());
311 : 10 : enquire.set_query(myquery);
312 : :
313 : : // retrieve the top ten results
314 : 10 : Xapian::MSet mymset = enquire.get_mset(0, 10);
315 : 10 : mset_expect_order(mymset, 2, 3, 7);
316 : :
317 : 10 : return true;
318 : : }
319 : :
320 : : // test that a multidb with 3 dbs query returns correct docids
321 : 10 : DEFINE_TESTCASE(multidb4, backend && !multi) {
322 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
323 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
324 : 10 : mydb2.add_database(get_database("apitest_termorder"));
325 : 10 : Xapian::Enquire enquire(mydb2);
326 : :
327 : : // make a query
328 : 10 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
329 : 10 : enquire.set_weighting_scheme(Xapian::BoolWeight());
330 : 10 : enquire.set_query(myquery);
331 : :
332 : : // retrieve the top ten results
333 : 10 : Xapian::MSet mymset = enquire.get_mset(0, 10);
334 : 10 : mset_expect_order(mymset, 2, 3, 4, 10);
335 : :
336 : 10 : return true;
337 : : }
338 : :
339 : : // tests MultiPostList::skip_to().
340 : 10 : DEFINE_TESTCASE(multidb5, backend && !multi) {
341 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
342 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
343 : 10 : Xapian::Enquire enquire(mydb2);
344 : :
345 : : // make a query
346 : 10 : Xapian::Query myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
347 : 10 : enquire.set_weighting_scheme(Xapian::BoolWeight());
348 : 10 : enquire.set_query(myquery);
349 : :
350 : : // retrieve the top ten results
351 : 10 : Xapian::MSet mymset = enquire.get_mset(0, 10);
352 : 10 : mset_expect_order(mymset, 2);
353 : :
354 : 10 : return true;
355 : : }
356 : :
357 : : // tests that when specifying maxitems to get_mset, no more than
358 : : // that are returned.
359 : 13 : DEFINE_TESTCASE(msetmaxitems1, backend) {
360 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
361 : 13 : enquire.set_query(query("this"));
362 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 1);
363 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
364 : :
365 : 13 : mymset = enquire.get_mset(0, 5);
366 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 5);
367 : :
368 : 13 : return true;
369 : : }
370 : :
371 : : // tests the returned weights are as expected (regression test for remote
372 : : // backend which was using the average weight rather than the actual document
373 : : // weight for computing weights - fixed in 1.0.0).
374 : 13 : DEFINE_TESTCASE(expandweights1, backend) {
375 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
376 : 13 : enquire.set_query(Xapian::Query("this"));
377 : :
378 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
379 : :
380 : 13 : Xapian::RSet myrset;
381 : 13 : Xapian::MSetIterator i = mymset.begin();
382 : 13 : myrset.add_document(*i);
383 : 13 : myrset.add_document(*(++i));
384 : :
385 : 13 : Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
386 [ - + # # ]: 13 : TEST_EQUAL(eset.size(), 3);
387 [ - + ][ # # ]: 13 : TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
388 [ - + ][ # # ]: 13 : TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
389 [ - + ][ # # ]: 13 : TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
390 : :
391 : 13 : return true;
392 : : }
393 : :
394 : : // Just like test_expandweights1 but without USE_EXACT_TERMFREQ.
395 : 13 : DEFINE_TESTCASE(expandweights2, backend) {
396 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
397 : 13 : enquire.set_query(Xapian::Query("this"));
398 : :
399 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
400 : :
401 : 13 : Xapian::RSet myrset;
402 : 13 : Xapian::MSetIterator i = mymset.begin();
403 : 13 : myrset.add_document(*i);
404 : 13 : myrset.add_document(*(++i));
405 : :
406 : 13 : Xapian::ESet eset = enquire.get_eset(3, myrset);
407 [ - + # # ]: 13 : TEST_EQUAL(eset.size(), 3);
408 [ + + ]: 13 : if (!startswith(get_dbtype(), "multi")) {
409 : : // For a single database, the weights should be the same with or
410 : : // without USE_EXACT_TERMFREQ.
411 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
412 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
413 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
414 : : } else {
415 : : // For multiple databases, we expect that using USE_EXACT_TERMFREQ
416 : : // will result in different weights in some cases.
417 [ - + ][ # # ]: 3 : TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
418 [ - + ][ # # ]: 3 : TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
419 [ - + ][ # # ]: 3 : TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
420 : : }
421 : :
422 : 13 : return true;
423 : : }
424 : :
425 : 13 : DEFINE_TESTCASE(expandweights3, backend) {
426 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
427 : 13 : enquire.set_query(Xapian::Query("this"));
428 : :
429 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
430 : :
431 : 13 : Xapian::RSet myrset;
432 : 13 : Xapian::MSetIterator i = mymset.begin();
433 : 13 : myrset.add_document(*i);
434 : 13 : myrset.add_document(*(++i));
435 : :
436 : : // Set min_wt to 0
437 : 13 : Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 1.0, 0, 0);
438 [ + + ]: 13 : if (!startswith(get_dbtype(), "multi")) {
439 : : // For a single database, the weights should be the same with or
440 : : // without USE_EXACT_TERMFREQ.
441 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
442 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
443 [ - + ][ # # ]: 10 : TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
444 : : } else {
445 : : // For multiple databases, we expect that using USE_EXACT_TERMFREQ
446 : : // will result in different weights in some cases.
447 [ - + ][ # # ]: 3 : TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
448 [ - + ][ # # ]: 3 : TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
449 [ - + ][ # # ]: 3 : TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
450 : : }
451 [ - + ][ # # ]: 13 : TEST_REL(eset.back().get_weight(),>=,0);
452 : :
453 : 13 : return true;
454 : : }
455 : :
456 : :
457 : : // tests that negative weights are returned
458 : 13 : DEFINE_TESTCASE(expandweights4, backend) {
459 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
460 : 13 : enquire.set_query(Xapian::Query("paragraph"));
461 : :
462 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
463 : :
464 : 13 : Xapian::RSet myrset;
465 : 13 : Xapian::MSetIterator i = mymset.begin();
466 : 13 : myrset.add_document(*i);
467 : 13 : myrset.add_document(*(++i));
468 : :
469 : 13 : Xapian::ESet eset = enquire.get_eset(37, myrset, 0, 1.0, 0, -100);
470 : : // Now include negative weights
471 [ - + # # ]: 13 : TEST_EQUAL(eset.size(), 37);
472 [ - + ][ # # ]: 13 : TEST_REL(eset[36].get_weight(),<,0);
473 [ - + ][ # # ]: 13 : TEST_REL(eset[36].get_weight(),>=,-100);
474 : :
475 : 13 : return true;
476 : : }
477 : :
478 : :
479 : : // tests that when specifying maxitems to get_eset, no more than
480 : : // that are returned.
481 : 13 : DEFINE_TESTCASE(expandmaxitems1, backend) {
482 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
483 : 13 : enquire.set_query(Xapian::Query("this"));
484 : :
485 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
486 : 13 : tout << "mymset.size() = " << mymset.size() << endl;
487 [ - + # # ]: 13 : TEST(mymset.size() >= 2);
488 : :
489 : 13 : Xapian::RSet myrset;
490 : 13 : Xapian::MSetIterator i = mymset.begin();
491 : 13 : myrset.add_document(*i);
492 : 13 : myrset.add_document(*(++i));
493 : :
494 : 13 : Xapian::ESet myeset = enquire.get_eset(1, myrset);
495 [ - + # # ]: 13 : TEST_EQUAL(myeset.size(), 1);
496 : :
497 : 13 : return true;
498 : : }
499 : :
500 : : // tests that a pure boolean query has all weights set to 0
501 : 13 : DEFINE_TESTCASE(boolquery1, backend) {
502 : 13 : Xapian::Query myboolquery(query("this"));
503 : :
504 : : // open the database (in this case a simple text file
505 : : // we prepared earlier)
506 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
507 : 13 : enquire.set_query(myboolquery);
508 : 13 : enquire.set_weighting_scheme(Xapian::BoolWeight());
509 : :
510 : : // retrieve the top results
511 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
512 : :
513 [ - + # # ]: 13 : TEST_NOT_EQUAL(mymset.size(), 0);
514 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_max_possible(), 0);
515 [ + + ]: 91 : for (Xapian::MSetIterator i = mymset.begin(); i != mymset.end(); ++i) {
516 [ - + ][ # # ]: 78 : TEST_EQUAL(i.get_weight(), 0);
517 : 13 : }
518 : 13 : return true;
519 : : }
520 : :
521 : : // tests that get_mset() specifying "this" works as expected
522 : 13 : DEFINE_TESTCASE(msetfirst1, backend) {
523 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
524 : 13 : enquire.set_query(query("this"));
525 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 6);
526 : 13 : Xapian::MSet mymset2 = enquire.get_mset(3, 3);
527 [ - + # # ]: 13 : TEST(mset_range_is_same(mymset1, 3, mymset2, 0, 3));
528 : :
529 : : // Regression test - we weren't adjusting the index into items[] by
530 : : // firstitem in api/omenquire.cc.
531 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1[5].get_document().get_data(),
532 : : mymset2[2].get_document().get_data());
533 : 13 : return true;
534 : : }
535 : :
536 : : // tests the converting-to-percent functions
537 : 13 : DEFINE_TESTCASE(topercent1, backend) {
538 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
539 : 13 : enquire.set_query(query("this"));
540 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 20);
541 : :
542 : 13 : int last_pct = 100;
543 : 13 : Xapian::MSetIterator i = mymset.begin();
544 [ + + ]: 91 : for ( ; i != mymset.end(); ++i) {
545 : 78 : int pct = mymset.convert_to_percent(i);
546 [ - + # # ]: 78 : TEST_AND_EXPLAIN(pct == i.get_percent(),
547 : : "convert_to_%(msetitor) != convert_to_%(wt)");
548 [ - + ][ # # ]: 78 : TEST_AND_EXPLAIN(pct == mymset.convert_to_percent(i.get_weight()),
549 : : "convert_to_%(msetitor) != convert_to_%(wt)");
550 [ + - ][ - + ]: 78 : TEST_AND_EXPLAIN(pct >= 0 && pct <= 100,
[ # # ]
551 : : "percentage out of range: " << pct);
552 [ - + ][ # # ]: 78 : TEST_AND_EXPLAIN(pct <= last_pct, "percentage increased down mset");
553 : 78 : last_pct = pct;
554 : : }
555 : 13 : return true;
556 : : }
557 : :
558 : : // tests the percentage values returned
559 : 14 : DEFINE_TESTCASE(topercent2, backend) {
560 : 14 : BackendManagerLocal local_manager;
561 : 14 : local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
562 : 14 : Xapian::Enquire localenq(local_manager.get_database("apitest_simpledata"));
563 : 14 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
564 : :
565 : : int pct;
566 : :
567 : : // First, test a search in which the top document scores 100%.
568 : 14 : enquire.set_query(query("this"));
569 : 14 : localenq.set_query(query("this"));
570 : 14 : Xapian::MSet mymset = enquire.get_mset(0, 20);
571 : 14 : Xapian::MSet localmset = localenq.get_mset(0, 20);
572 : :
573 : 14 : Xapian::MSetIterator i = mymset.begin();
574 [ - + ][ # # ]: 14 : TEST(i != mymset.end());
575 : 14 : pct = mymset.convert_to_percent(i);
576 [ - + # # ]: 14 : TEST_EQUAL(pct, 100);
577 : :
578 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
579 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
580 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
581 [ - + ][ # # ]: 14 : TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
582 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.size(), localmset.size());
583 [ - + ][ # # ]: 14 : TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
584 : :
585 : : // A search in which the top document doesn't have 100%
586 : : Xapian::Query q = query(Xapian::Query::OP_OR,
587 : 14 : "this", "line", "paragraph", "rubbish");
588 : 14 : enquire.set_query(q);
589 : 14 : localenq.set_query(q);
590 : 14 : mymset = enquire.get_mset(0, 20);
591 : 14 : localmset = localenq.get_mset(0, 20);
592 : :
593 : 14 : i = mymset.begin();
594 [ - + ][ # # ]: 14 : TEST(i != mymset.end());
595 : 14 : pct = mymset.convert_to_percent(i);
596 [ - + # # ]: 14 : TEST_REL(pct,>,60);
597 [ - + ][ # # ]: 14 : TEST_REL(pct,<,76);
598 : :
599 : 14 : ++i;
600 : :
601 [ - + ][ # # ]: 14 : TEST(i != mymset.end());
602 : 14 : pct = mymset.convert_to_percent(i);
603 [ - + # # ]: 14 : TEST_REL(pct,>,40);
604 [ - + ][ # # ]: 14 : TEST_REL(pct,<,50);
605 : :
606 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
607 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
608 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
609 [ - + ][ # # ]: 14 : TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
610 [ - + ][ # # ]: 14 : TEST_EQUAL(mymset.size(), localmset.size());
611 [ - + ][ # # ]: 14 : TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
612 : :
613 : 14 : return true;
614 : : }
615 : :
616 [ # # ][ - + ]: 26 : class myExpandFunctor : public Xapian::ExpandDecider {
617 : : public:
618 : 2429 : bool operator()(const string & tname) const {
619 : 2429 : unsigned long sum = 0;
620 [ + + ]: 12363 : for (string::const_iterator i=tname.begin(); i!=tname.end(); ++i) {
621 : 9934 : sum += *i;
622 : : }
623 : : // if (verbose) {
624 : : // tout << tname << "==> " << sum << "\n";
625 : : // }
626 : 2429 : return (sum % 2) == 0;
627 : : }
628 : : };
629 : :
630 : : // tests the expand decision functor
631 : 13 : DEFINE_TESTCASE(expandfunctor1, backend) {
632 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
633 : 13 : enquire.set_query(Xapian::Query("this"));
634 : :
635 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
636 [ - + # # ]: 13 : TEST(mymset.size() >= 2);
637 : :
638 : 13 : Xapian::RSet myrset;
639 : 13 : Xapian::MSetIterator i = mymset.begin();
640 : 13 : myrset.add_document(*i);
641 : 13 : myrset.add_document(*(++i));
642 : :
643 : 13 : myExpandFunctor myfunctor;
644 : :
645 : 13 : Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
646 : 13 : unsigned int neweset_size = 0;
647 : 13 : Xapian::ESetIterator j = myeset_orig.begin();
648 [ + + ]: 792 : for ( ; j != myeset_orig.end(); ++j) {
649 [ + + ]: 779 : if (myfunctor(*j)) neweset_size++;
650 : : }
651 : 13 : Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
652 : :
653 : : #if 0
654 : : // Compare myeset with the hand-filtered version of myeset_orig.
655 : : if (verbose) {
656 : : tout << "orig_eset: ";
657 : : copy(myeset_orig.begin(), myeset_orig.end(),
658 : : ostream_iterator<Xapian::ESetItem>(tout, " "));
659 : : tout << "\n";
660 : :
661 : : tout << "new_eset: ";
662 : : copy(myeset.begin(), myeset.end(),
663 : : ostream_iterator<Xapian::ESetItem>(tout, " "));
664 : : tout << "\n";
665 : : }
666 : : #endif
667 : 13 : Xapian::ESetIterator orig = myeset_orig.begin();
668 : 13 : Xapian::ESetIterator filt = myeset.begin();
669 [ + - ][ + + ]: 336 : for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
[ + - ][ # # ]
[ # # ][ + - ]
[ + + ]
670 : : // skip over items that shouldn't be in myeset
671 [ + - ][ + + ]: 753 : while (orig != myeset_orig.end() && !myfunctor(*orig)) {
[ + - ][ # # ]
[ + + ]
672 : 430 : ++orig;
673 : : }
674 : :
675 [ + - ][ - + ]: 323 : TEST_AND_EXPLAIN(*orig == *filt &&
[ - + ][ # # ]
676 : : orig.get_weight() == filt.get_weight(),
677 : : "Mismatch in items " << *orig << " vs. " << *filt
678 : : << " after filtering");
679 : : }
680 : :
681 [ + + ][ + - ]: 39 : while (orig != myeset_orig.end() && !myfunctor(*orig)) {
[ + - ][ # # ]
[ + + ]
682 : 26 : ++orig;
683 : : }
684 : :
685 [ - + ][ # # ]: 13 : TEST_EQUAL(orig, myeset_orig.end());
686 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(filt == myeset.end(),
687 : : "Extra items in the filtered eset.");
688 : 13 : return true;
689 : : }
690 : :
691 : : // tests the percent cutoff option
692 : 13 : DEFINE_TESTCASE(pctcutoff1, backend) {
693 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
694 : : enquire.set_query(query(Xapian::Query::OP_OR,
695 : 13 : "this", "line", "paragraph", "rubbish"));
696 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
697 : :
698 [ - + ]: 13 : if (verbose) {
699 : 0 : tout << "Original mset pcts:";
700 : 0 : print_mset_percentages(mymset1);
701 : 0 : tout << "\n";
702 : : }
703 : :
704 : 13 : unsigned int num_items = 0;
705 : 13 : int my_pct = 100;
706 : 13 : int changes = 0;
707 : 13 : Xapian::MSetIterator i = mymset1.begin();
708 : 13 : int c = 0;
709 [ + - ]: 52 : for ( ; i != mymset1.end(); ++i, ++c) {
710 : 52 : int new_pct = mymset1.convert_to_percent(i);
711 [ + - ]: 52 : if (new_pct != my_pct) {
712 : 52 : changes++;
713 [ + + ]: 52 : if (changes > 3) break;
714 : 39 : num_items = c;
715 : 39 : my_pct = new_pct;
716 : : }
717 : : }
718 : :
719 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
720 [ - + ]: 13 : if (verbose) {
721 : 0 : tout << "Cutoff percent: " << my_pct << "\n";
722 : : }
723 : :
724 : 13 : enquire.set_cutoff(my_pct);
725 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 100);
726 : :
727 [ - + ]: 13 : if (verbose) {
728 : 0 : tout << "Percentages after cutoff:";
729 : 0 : print_mset_percentages(mymset2);
730 : 0 : tout << "\n";
731 : : }
732 : :
733 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(mymset2.size() >= num_items,
734 : : "Match with % cutoff lost too many items");
735 : :
736 [ + - ][ + - ]: 13 : TEST_AND_EXPLAIN(mymset2.size() == num_items ||
[ - + ][ + - ]
[ # # ][ # # ]
[ + - ][ - + ]
[ # # ]
737 : : (mymset2.convert_to_percent(mymset2[num_items]) == my_pct &&
738 : : mymset2.convert_to_percent(mymset2.back()) == my_pct),
739 : : "Match with % cutoff returned too many items");
740 : :
741 : 13 : return true;
742 : : }
743 : :
744 : : // Tests the percent cutoff option combined with collapsing
745 : 13 : DEFINE_TESTCASE(pctcutoff2, backend) {
746 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
747 : 13 : enquire.set_query(Xapian::Query("this"));
748 : 13 : enquire.set_query(Xapian::Query(Xapian::Query::OP_AND_NOT, Xapian::Query("this"), Xapian::Query("banana")));
749 : 13 : Xapian::MSet mset = enquire.get_mset(0, 100);
750 : :
751 [ - + ]: 13 : if (verbose) {
752 : 0 : tout << "Original mset pcts:";
753 : 0 : print_mset_percentages(mset);
754 : 0 : tout << "\n";
755 : : }
756 : :
757 [ - + ][ # # ]: 13 : TEST(mset.size() >= 2);
758 [ - + ][ # # ]: 13 : TEST(mset[0].get_percent() - mset[1].get_percent() >= 2);
759 : :
760 : 13 : Xapian::percent cutoff = mset[0].get_percent() + mset[1].get_percent();
761 : 13 : cutoff /= 2;
762 : :
763 : 13 : enquire.set_cutoff(cutoff);
764 : 13 : enquire.set_collapse_key(1234); // Value which is always empty.
765 : :
766 : 13 : Xapian::MSet mset2 = enquire.get_mset(0, 1);
767 [ - + # # ]: 13 : TEST_EQUAL(mset2.size(), 1);
768 [ - + ][ # # ]: 13 : TEST_EQUAL(mset2.get_matches_lower_bound(), 1);
769 [ - + ][ # # ]: 13 : TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),>=,1);
770 [ - + ][ # # ]: 13 : TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset.size());
771 [ - + ][ # # ]: 13 : TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset.size());
772 [ - + ][ # # ]: 13 : TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
773 [ - + ][ # # ]: 13 : TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset2.get_uncollapsed_matches_estimated());
774 : :
775 : 13 : return true;
776 : : }
777 : :
778 : : // Test that the percent cutoff option returns all the answers it should.
779 : 13 : DEFINE_TESTCASE(pctcutoff3, backend) {
780 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
781 : 13 : enquire.set_query(Xapian::Query("this"));
782 : 13 : Xapian::MSet mset1 = enquire.get_mset(0, 10);
783 : :
784 [ - + ]: 13 : if (verbose) {
785 : 0 : tout << "Original mset pcts:";
786 : 0 : print_mset_percentages(mset1);
787 : 0 : tout << "\n";
788 : : }
789 : :
790 : 13 : int percent = 100;
791 [ + + ]: 91 : for (Xapian::MSetIterator i = mset1.begin(); i != mset1.end(); ++i) {
792 : 78 : int new_percent = mset1.convert_to_percent(i);
793 [ + + ]: 78 : if (new_percent != percent) {
794 : 39 : enquire.set_cutoff(percent);
795 : 39 : Xapian::MSet mset2 = enquire.get_mset(0, 10);
796 [ - + # # ]: 39 : TEST_EQUAL(mset2.size(), i.get_rank());
797 : 39 : percent = new_percent;
798 : : }
799 : 13 : }
800 : :
801 : 13 : return true;
802 : : }
803 : :
804 : : // tests the cutoff option
805 : 13 : DEFINE_TESTCASE(cutoff1, backend) {
806 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
807 : : enquire.set_query(query(Xapian::Query::OP_OR,
808 : 13 : "this", "line", "paragraph", "rubbish"));
809 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
810 : :
811 [ - + ]: 13 : if (verbose) {
812 : 0 : tout << "Original mset weights:";
813 : 0 : print_mset_weights(mymset1);
814 : 0 : tout << "\n";
815 : : }
816 : :
817 : 13 : unsigned int num_items = 0;
818 : 13 : Xapian::weight my_wt = -100;
819 : 13 : int changes = 0;
820 : 13 : Xapian::MSetIterator i = mymset1.begin();
821 : 13 : int c = 0;
822 [ + - ]: 52 : for ( ; i != mymset1.end(); ++i, ++c) {
823 : 52 : Xapian::weight new_wt = i.get_weight();
824 [ + - ]: 52 : if (new_wt != my_wt) {
825 : 52 : changes++;
826 [ + + ]: 52 : if (changes > 3) break;
827 : 39 : num_items = c;
828 : 39 : my_wt = new_wt;
829 : : }
830 : : }
831 : :
832 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
833 [ - + ]: 13 : if (verbose) {
834 : 0 : tout << "Cutoff weight: " << my_wt << "\n";
835 : : }
836 : :
837 : 13 : enquire.set_cutoff(0, my_wt);
838 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 100);
839 : :
840 [ - + ]: 13 : if (verbose) {
841 : 0 : tout << "Weights after cutoff:";
842 : 0 : print_mset_weights(mymset2);
843 : 0 : tout << "\n";
844 : : }
845 : :
846 [ - + ][ # # ]: 13 : TEST_AND_EXPLAIN(mymset2.size() >= num_items,
847 : : "Match with cutoff lost too many items");
848 : :
849 [ + - ][ + - ]: 13 : TEST_AND_EXPLAIN(mymset2.size() == num_items ||
[ - + ][ + - ]
[ # # ][ # # ]
[ + - ][ - + ]
[ # # ]
850 : : (mymset2[num_items].get_weight() == my_wt &&
851 : : mymset2.back().get_weight() == my_wt),
852 : : "Match with cutoff returned too many items");
853 : :
854 : 13 : return true;
855 : : }
856 : :
857 : : // tests the allow query terms expand option
858 : 13 : DEFINE_TESTCASE(allowqterms1, backend) {
859 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
860 : 13 : string term = "paragraph";
861 : 13 : enquire.set_query(Xapian::Query(term));
862 : :
863 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
864 [ - + # # ]: 13 : TEST(mymset.size() >= 2);
865 : :
866 : 13 : Xapian::RSet myrset;
867 : 13 : Xapian::MSetIterator i = mymset.begin();
868 : 13 : myrset.add_document(*i);
869 : 13 : myrset.add_document(*(++i));
870 : :
871 : 13 : Xapian::ESet myeset = enquire.get_eset(1000, myrset);
872 : 13 : Xapian::ESetIterator j = myeset.begin();
873 [ + + ]: 398 : for ( ; j != myeset.end(); ++j) {
874 [ - + ][ # # ]: 385 : TEST_NOT_EQUAL(*j, term);
875 : : }
876 : :
877 : 13 : Xapian::ESet myeset2 = enquire.get_eset(1000, myrset, Xapian::Enquire::INCLUDE_QUERY_TERMS);
878 : 13 : j = myeset2.begin();
879 [ + - ]: 261 : for ( ; j != myeset2.end(); ++j) {
880 [ + + ]: 261 : if (*j == term) break;
881 : : }
882 [ - + ][ # # ]: 13 : TEST(j != myeset2.end());
883 : 13 : return true;
884 : : }
885 : :
886 : : // tests that the MSet max_attained works
887 : 13 : DEFINE_TESTCASE(maxattain1, backend) {
888 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
889 : 13 : enquire.set_query(query("this"));
890 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 100);
891 : :
892 : 13 : Xapian::weight mymax = 0;
893 : 13 : Xapian::MSetIterator i = mymset.begin();
894 [ + + ]: 91 : for ( ; i != mymset.end(); ++i) {
895 [ + + ]: 78 : if (i.get_weight() > mymax) mymax = i.get_weight();
896 : : }
897 [ - + ][ # # ]: 13 : TEST_EQUAL(mymax, mymset.get_max_attained());
898 : :
899 : 13 : return true;
900 : : }
901 : :
902 : : // tests a reversed boolean query
903 : 13 : DEFINE_TESTCASE(reversebool1, backend) {
904 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
905 : 13 : enquire.set_query(Xapian::Query("this"));
906 : 13 : enquire.set_weighting_scheme(Xapian::BoolWeight());
907 : :
908 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
909 [ - + # # ]: 13 : TEST_AND_EXPLAIN(mymset1.size() > 1,
910 : : "Mset was too small to test properly");
911 : :
912 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
913 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 100);
914 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
915 : 13 : Xapian::MSet mymset3 = enquire.get_mset(0, 100);
916 : :
917 : : // mymset1 and mymset2 should be identical
918 [ - + # # ]: 13 : TEST_EQUAL(mymset1.size(), mymset2.size());
919 : :
920 : : {
921 : 13 : Xapian::MSetIterator i = mymset1.begin();
922 : 13 : Xapian::MSetIterator j = mymset2.begin();
923 [ + + ]: 91 : for ( ; i != mymset1.end(), j != mymset2.end(); ++i, j++) {
924 : : // if this fails, then setting match_sort_forward=true was not
925 : : // the same as the default.
926 [ - + ][ # # ]: 78 : TEST_EQUAL(*i, *j);
927 : 13 : }
928 : : }
929 : :
930 : : // mymset1 and mymset3 should be same but reversed
931 [ - + # # ]: 13 : TEST_EQUAL(mymset1.size(), mymset3.size());
932 : :
933 : : {
934 : 13 : Xapian::MSetIterator i = mymset1.begin();
935 : 13 : vector<Xapian::docid> rev(mymset3.begin(), mymset3.end());
936 : : // Next iterator not const because of compiler brokenness (egcs 1.1.2)
937 : 13 : vector<Xapian::docid>::reverse_iterator j = rev.rbegin();
938 [ + + ]: 91 : for ( ; i != mymset1.end(); ++i, j++) {
939 : : // if this fails, then setting match_sort_forward=false didn't
940 : : // reverse the results.
941 [ - + ][ # # ]: 78 : TEST_EQUAL(*i, *j);
942 : 13 : }
943 : : }
944 : :
945 : 13 : return true;
946 : : }
947 : :
948 : : // tests a reversed boolean query, where the full mset isn't returned
949 : 13 : DEFINE_TESTCASE(reversebool2, backend) {
950 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
951 : 13 : enquire.set_query(Xapian::Query("this"));
952 : 13 : enquire.set_weighting_scheme(Xapian::BoolWeight());
953 : :
954 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
955 : :
956 [ - + # # ]: 13 : TEST_AND_EXPLAIN(mymset1.size() > 1,
957 : : "Mset was too small to test properly");
958 : :
959 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
960 : 13 : Xapian::doccount msize = mymset1.size() / 2;
961 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, msize);
962 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
963 : 13 : Xapian::MSet mymset3 = enquire.get_mset(0, msize);
964 : :
965 : : // mymset2 should be first msize items of mymset1
966 [ - + # # ]: 13 : TEST_EQUAL(msize, mymset2.size());
967 : : {
968 : 13 : Xapian::MSetIterator i = mymset1.begin();
969 : 13 : Xapian::MSetIterator j = mymset2.begin();
970 [ + + ]: 52 : for ( ; i != mymset1.end(), j != mymset2.end(); ++i, j++) {
971 : : // if this fails, then setting match_sort_forward=true was not
972 : : // the same as the default.
973 [ - + ][ # # ]: 39 : TEST_EQUAL(*i, *j);
974 : 13 : }
975 : : }
976 : :
977 : : // mymset3 should be last msize items of mymset1, in reverse order
978 [ - + # # ]: 13 : TEST_EQUAL(msize, mymset3.size());
979 : : {
980 : 13 : vector<Xapian::docid> rev(mymset1.begin(), mymset1.end());
981 : : // Next iterator not const because of compiler brokenness (egcs 1.1.2)
982 : 13 : vector<Xapian::docid>::reverse_iterator i = rev.rbegin();
983 : 13 : Xapian::MSetIterator j = mymset3.begin();
984 [ + + ]: 52 : for ( ; j != mymset3.end(); ++i, j++) {
985 : : // if this fails, then setting match_sort_forward=false didn't
986 : : // reverse the results.
987 [ - + ][ # # ]: 39 : TEST_EQUAL(*i, *j);
988 : 13 : }
989 : : }
990 : :
991 : 13 : return true;
992 : : }
993 : :
994 : : // tests that get_matching_terms() returns the terms in the right order
995 : 13 : DEFINE_TESTCASE(getmterms1, backend) {
996 : 13 : list<string> answers_list;
997 : 13 : answers_list.push_back("one");
998 : 13 : answers_list.push_back("two");
999 : 13 : answers_list.push_back("three");
1000 : 13 : answers_list.push_back("four");
1001 : :
1002 : 13 : Xapian::Database mydb(get_database("apitest_termorder"));
1003 : 13 : Xapian::Enquire enquire(mydb);
1004 : :
1005 : : Xapian::Query myquery(Xapian::Query::OP_OR,
1006 : : Xapian::Query(Xapian::Query::OP_AND,
1007 : : Xapian::Query("one", 1, 1),
1008 : : Xapian::Query("three", 1, 3)),
1009 : : Xapian::Query(Xapian::Query::OP_OR,
1010 : : Xapian::Query("four", 1, 4),
1011 : 13 : Xapian::Query("two", 1, 2)));
1012 : :
1013 : 13 : enquire.set_query(myquery);
1014 : :
1015 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1016 : :
1017 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1018 : : list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1019 : 13 : enquire.get_matching_terms_end(mymset.begin()));
1020 [ - + # # ]: 13 : TEST(list == answers_list);
1021 : :
1022 : 13 : return true;
1023 : : }
1024 : :
1025 : : // tests that get_matching_terms() returns the terms only once
1026 : 13 : DEFINE_TESTCASE(getmterms2, backend) {
1027 : 13 : list<string> answers_list;
1028 : 13 : answers_list.push_back("one");
1029 : 13 : answers_list.push_back("two");
1030 : 13 : answers_list.push_back("three");
1031 : :
1032 : 13 : Xapian::Database mydb(get_database("apitest_termorder"));
1033 : 13 : Xapian::Enquire enquire(mydb);
1034 : :
1035 : : Xapian::Query myquery(Xapian::Query::OP_OR,
1036 : : Xapian::Query(Xapian::Query::OP_AND,
1037 : : Xapian::Query("one", 1, 1),
1038 : : Xapian::Query("three", 1, 3)),
1039 : : Xapian::Query(Xapian::Query::OP_OR,
1040 : : Xapian::Query("one", 1, 4),
1041 : 13 : Xapian::Query("two", 1, 2)));
1042 : :
1043 : 13 : enquire.set_query(myquery);
1044 : :
1045 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1046 : :
1047 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1048 : : list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1049 : 13 : enquire.get_matching_terms_end(mymset.begin()));
1050 [ - + # # ]: 13 : TEST(list == answers_list);
1051 : :
1052 : 13 : return true;
1053 : : }
1054 : :
1055 : : // tests that the collapsing on termpos optimisation works
1056 : 13 : DEFINE_TESTCASE(poscollapse1, backend) {
1057 : : Xapian::Query myquery1(Xapian::Query::OP_OR,
1058 : : Xapian::Query("this", 1, 1),
1059 : 13 : Xapian::Query("this", 1, 1));
1060 : 13 : Xapian::Query myquery2("this", 2, 1);
1061 : :
1062 [ - + ]: 13 : if (verbose) {
1063 : 0 : tout << myquery1.get_description() << "\n";
1064 : 0 : tout << myquery2.get_description() << "\n";
1065 : : }
1066 : :
1067 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1068 : 13 : enquire.set_query(myquery1);
1069 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1070 : :
1071 : 13 : enquire.set_query(myquery2);
1072 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1073 : :
1074 [ - + # # ]: 13 : TEST_EQUAL(mymset1, mymset2);
1075 : :
1076 : 13 : return true;
1077 : : }
1078 : :
1079 : : // test that running a query twice returns the same results
1080 : 13 : DEFINE_TESTCASE(repeatquery1, backend) {
1081 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1082 : 13 : enquire.set_query(Xapian::Query("this"));
1083 : :
1084 : 13 : enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1085 : :
1086 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1087 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1088 [ - + # # ]: 13 : TEST_EQUAL(mymset1, mymset2);
1089 : :
1090 : 13 : return true;
1091 : : }
1092 : :
1093 : : // test that prefetching documents works (at least, gives same results)
1094 : 13 : DEFINE_TESTCASE(fetchdocs1, backend) {
1095 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1096 : 13 : enquire.set_query(Xapian::Query("this"));
1097 : :
1098 : 13 : enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1099 : :
1100 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1101 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1102 [ - + # # ]: 13 : TEST_EQUAL(mymset1, mymset2);
1103 : 13 : mymset2.fetch(mymset2[0], mymset2[mymset2.size() - 1]);
1104 : 13 : mymset2.fetch(mymset2.begin(), mymset2.end());
1105 : 13 : mymset2.fetch(mymset2.begin());
1106 : 13 : mymset2.fetch();
1107 : :
1108 : 13 : Xapian::MSetIterator it1 = mymset1.begin();
1109 : 13 : Xapian::MSetIterator it2 = mymset2.begin();
1110 : :
1111 [ + + ][ + - ]: 91 : while (it1 != mymset1.end() && it2 != mymset2.end()) {
[ + + ][ # # ]
[ # # ][ + - ]
[ + + ]
1112 [ - + ][ # # ]: 78 : TEST_EQUAL(it1.get_document().get_data(),
1113 : : it2.get_document().get_data());
1114 [ - + ][ # # ]: 78 : TEST_NOT_EQUAL(it1.get_document().get_data(), "");
1115 [ - + ][ # # ]: 78 : TEST_NOT_EQUAL(it2.get_document().get_data(), "");
1116 : 78 : it1++;
1117 : 78 : it2++;
1118 : : }
1119 [ - + ][ # # ]: 13 : TEST_EQUAL(it1, mymset1.end());
1120 [ - + ][ # # ]: 13 : TEST_EQUAL(it1, mymset2.end());
1121 : :
1122 : 13 : return true;
1123 : : }
1124 : :
1125 : : // test that searching for a term not in the database fails nicely
1126 : 13 : DEFINE_TESTCASE(absentterm1, backend) {
1127 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1128 : 13 : enquire.set_weighting_scheme(Xapian::BoolWeight());
1129 : 13 : enquire.set_query(Xapian::Query("frink"));
1130 : :
1131 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1132 : 13 : mset_expect_order(mymset);
1133 : :
1134 : 13 : return true;
1135 : : }
1136 : :
1137 : : // as absentterm1, but setting query from a vector of terms
1138 : 13 : DEFINE_TESTCASE(absentterm2, backend) {
1139 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1140 : 13 : vector<string> terms;
1141 : 13 : terms.push_back("frink");
1142 : :
1143 : 13 : Xapian::Query query(Xapian::Query::OP_OR, terms.begin(), terms.end());
1144 : 13 : enquire.set_query(query);
1145 : :
1146 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1147 : 13 : mset_expect_order(mymset);
1148 : :
1149 : 13 : return true;
1150 : : }
1151 : :
1152 : : // test that rsets do sensible things
1153 : 13 : DEFINE_TESTCASE(rset1, backend) {
1154 : 13 : Xapian::Database mydb(get_database("apitest_rset"));
1155 : 13 : Xapian::Enquire enquire(mydb);
1156 : 13 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "giraffe", "tiger");
1157 : 13 : enquire.set_query(myquery);
1158 : :
1159 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1160 : :
1161 : 13 : Xapian::RSet myrset;
1162 : 13 : myrset.add_document(1);
1163 : :
1164 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1165 : :
1166 : : // We should have the same documents turn up, but 1 and 3 should
1167 : : // have higher weights with the RSet.
1168 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset1, 3);
1169 [ - + ][ # # ]: 13 : TEST_MSET_SIZE(mymset2, 3);
1170 : :
1171 : 13 : return true;
1172 : : }
1173 : :
1174 : : // test that rsets do more sensible things
1175 : 13 : DEFINE_TESTCASE(rset2, backend) {
1176 : 13 : Xapian::Database mydb(get_database("apitest_rset"));
1177 : 13 : Xapian::Enquire enquire(mydb);
1178 : 13 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
1179 : 13 : enquire.set_query(myquery);
1180 : :
1181 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1182 : :
1183 : 13 : Xapian::RSet myrset;
1184 : 13 : myrset.add_document(2);
1185 : :
1186 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1187 : :
1188 : 13 : mset_expect_order(mymset1, 1, 2);
1189 : 13 : mset_expect_order(mymset2, 2, 1);
1190 : :
1191 : 13 : return true;
1192 : : }
1193 : :
1194 : : // test that rsets behave correctly with multiDBs
1195 : 10 : DEFINE_TESTCASE(rsetmultidb1, backend && !multi) {
1196 : 10 : Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1197 : 10 : Xapian::Database mydb2(get_database("apitest_rset"));
1198 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
1199 : :
1200 : 10 : Xapian::Enquire enquire1(mydb1);
1201 : 10 : Xapian::Enquire enquire2(mydb2);
1202 : :
1203 : 10 : Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "multiple");
1204 : :
1205 : 10 : enquire1.set_query(myquery);
1206 : 10 : enquire2.set_query(myquery);
1207 : :
1208 : 10 : Xapian::RSet myrset1;
1209 : 10 : Xapian::RSet myrset2;
1210 : 10 : myrset1.add_document(4);
1211 : 10 : myrset2.add_document(2);
1212 : :
1213 : 10 : Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
1214 : 10 : Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
1215 : 10 : Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
1216 : 10 : Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
1217 : :
1218 : 10 : mset_expect_order(mymset1a, 1, 4);
1219 : 10 : mset_expect_order(mymset1b, 4, 1);
1220 : 10 : mset_expect_order(mymset2a, 1, 2);
1221 : 10 : mset_expect_order(mymset2b, 2, 1);
1222 : :
1223 [ - + # # ]: 10 : TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
1224 [ - + ][ # # ]: 10 : TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
1225 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(mymset1a, mymset1b);
1226 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(mymset2a, mymset2b);
1227 : :
1228 : 10 : return true;
1229 : : }
1230 : :
1231 : : // regression tests - used to cause assertion in stats.h to fail
1232 : : // Doesn't actually fail for multi but it doesn't make sense to run there.
1233 : 10 : DEFINE_TESTCASE(rsetmultidb3, backend && !multi) {
1234 : 10 : Xapian::Enquire enquire(get_database("apitest_simpledata2"));
1235 : 10 : enquire.set_query(query(Xapian::Query::OP_OR, "cuddly", "people"));
1236 : 10 : Xapian::MSet mset = enquire.get_mset(0, 10); // used to fail assertion
1237 : 10 : return true;
1238 : : }
1239 : :
1240 : : /// Simple test of the elite set operator.
1241 : 13 : DEFINE_TESTCASE(eliteset1, backend) {
1242 : : // FIXME: OP_ELITE_SET erroneously picks the best N terms separately in
1243 : : // each sub-database!
1244 : 19 : SKIP_TEST_FOR_BACKEND("multi");
1245 : :
1246 : 10 : Xapian::Database mydb(get_database("apitest_simpledata"));
1247 : 10 : Xapian::Enquire enquire(mydb);
1248 : :
1249 : 10 : Xapian::Query myquery1 = query(Xapian::Query::OP_OR, "word");
1250 : :
1251 : : Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1252 : 10 : "simple", "word");
1253 : :
1254 : 10 : enquire.set_query(myquery1, 2); // So the query lengths are the same.
1255 : 10 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1256 : :
1257 : 10 : enquire.set_query(myquery2);
1258 : 10 : Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1259 : :
1260 [ - + # # ]: 10 : TEST_EQUAL(mymset1, mymset2);
1261 : 10 : return true;
1262 : : }
1263 : :
1264 : : /// Test that the elite set operator works if the set contains
1265 : : /// sub-expressions (regression test)
1266 : 13 : DEFINE_TESTCASE(eliteset2, backend) {
1267 : : // FIXME: OP_ELITE_SET erroneously picks the best N terms separately in
1268 : : // each sub-database!
1269 : 19 : SKIP_TEST_FOR_BACKEND("multi");
1270 : :
1271 : 10 : Xapian::Database mydb(get_database("apitest_simpledata"));
1272 : 10 : Xapian::Enquire enquire(mydb);
1273 : :
1274 : 10 : Xapian::Query myquery1 = query(Xapian::Query::OP_AND, "word", "search");
1275 : :
1276 : 10 : vector<Xapian::Query> qs;
1277 : 10 : qs.push_back(query("this"));
1278 : 10 : qs.push_back(query(Xapian::Query::OP_AND, "word", "search"));
1279 : : Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET,
1280 : 10 : qs.begin(), qs.end(), 1);
1281 : :
1282 : 10 : enquire.set_query(myquery1);
1283 : 10 : Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1284 : :
1285 : 10 : enquire.set_query(myquery2);
1286 : 10 : Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1287 : :
1288 [ - + # # ]: 10 : TEST_EQUAL(mymset1, mymset2);
1289 : : // query lengths differ so mset weights not the same (with some weighting
1290 : : // parameters)
1291 : : //test_mset_order_equal(mymset1, mymset2);
1292 : :
1293 : 10 : return true;
1294 : : }
1295 : :
1296 : : /// Test that elite set doesn't affect query results if we have fewer
1297 : : /// terms than the threshold
1298 : 13 : DEFINE_TESTCASE(eliteset3, backend) {
1299 : 13 : Xapian::Database mydb1(get_database("apitest_simpledata"));
1300 : 13 : Xapian::Enquire enquire1(mydb1);
1301 : :
1302 : 13 : Xapian::Database mydb2(get_database("apitest_simpledata"));
1303 : 13 : Xapian::Enquire enquire2(mydb2);
1304 : :
1305 : : // make a query
1306 : 13 : Xapian::Stem stemmer("english");
1307 : :
1308 : 13 : string term1 = stemmer("word");
1309 : 13 : string term2 = stemmer("rubbish");
1310 : 13 : string term3 = stemmer("banana");
1311 : :
1312 : 13 : vector<string> terms;
1313 : 13 : terms.push_back(term1);
1314 : 13 : terms.push_back(term2);
1315 : 13 : terms.push_back(term3);
1316 : :
1317 : 13 : Xapian::Query myquery1(Xapian::Query::OP_OR, terms.begin(), terms.end());
1318 : 13 : enquire1.set_query(myquery1);
1319 : :
1320 : 13 : Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET, terms.begin(), terms.end(), 3);
1321 : 13 : enquire2.set_query(myquery2);
1322 : :
1323 : : // retrieve the results
1324 : 13 : Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1325 : 13 : Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1326 : :
1327 [ - + # # ]: 13 : TEST_EQUAL(mymset1.get_termfreq(term1),
1328 : : mymset2.get_termfreq(term1));
1329 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1.get_termweight(term1),
1330 : : mymset2.get_termweight(term1));
1331 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1.get_termfreq(term2),
1332 : : mymset2.get_termfreq(term2));
1333 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1.get_termweight(term2),
1334 : : mymset2.get_termweight(term2));
1335 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1.get_termfreq(term3),
1336 : : mymset2.get_termfreq(term3));
1337 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1.get_termweight(term3),
1338 : : mymset2.get_termweight(term3));
1339 : : // TEST_EQUAL(mymset1, mymset2);
1340 : :
1341 : 13 : return true;
1342 : : }
1343 : :
1344 : : /// Test that elite set doesn't pick terms with 0 frequency
1345 : 13 : DEFINE_TESTCASE(eliteset4, backend) {
1346 : : // FIXME: OP_ELITE_SET erroneously picks the best N terms separately in
1347 : : // each sub-database!
1348 : 19 : SKIP_TEST_FOR_BACKEND("multi");
1349 : :
1350 : 10 : Xapian::Database mydb1(get_database("apitest_simpledata"));
1351 : 10 : Xapian::Enquire enquire1(mydb1);
1352 : :
1353 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
1354 : 10 : Xapian::Enquire enquire2(mydb2);
1355 : :
1356 : 10 : Xapian::Query myquery1 = query("rubbish");
1357 : : Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1358 : 10 : "word", "rubbish", "fibble");
1359 : 10 : enquire1.set_query(myquery1);
1360 : 10 : enquire2.set_query(myquery2);
1361 : :
1362 : : // retrieve the results
1363 : 10 : Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1364 : 10 : Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1365 : :
1366 [ - + # # ]: 10 : TEST_NOT_EQUAL(mymset2.size(), 0);
1367 [ - + ][ # # ]: 10 : TEST_EQUAL(mymset1, mymset2);
1368 : : // TEST_EQUAL(mymset1, mymset2);
1369 : :
1370 : 10 : return true;
1371 : : }
1372 : :
1373 : : /// Regression test for problem with excess precision.
1374 : 13 : DEFINE_TESTCASE(eliteset5, backend) {
1375 : 19 : SKIP_TEST_FOR_BACKEND("multi");
1376 : :
1377 : 10 : Xapian::Database mydb1(get_database("apitest_simpledata"));
1378 : 10 : Xapian::Enquire enquire1(mydb1);
1379 : :
1380 : 10 : vector<string> v;
1381 [ + + ]: 40 : for (int i = 0; i != 3; ++i) {
1382 : 30 : v.push_back("simpl");
1383 : 30 : v.push_back("queri");
1384 : :
1385 : 30 : v.push_back("rubbish");
1386 : 30 : v.push_back("rubbish");
1387 : 30 : v.push_back("rubbish");
1388 : 30 : v.push_back("word");
1389 : 30 : v.push_back("word");
1390 : 30 : v.push_back("word");
1391 : : }
1392 : :
1393 : : Xapian::Query myquery1 = Xapian::Query(Xapian::Query::OP_ELITE_SET,
1394 : 10 : v.begin(), v.end(), 1);
1395 : : myquery1 = Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
1396 : : myquery1,
1397 : 10 : 0.004);
1398 : :
1399 : 10 : enquire1.set_query(myquery1);
1400 : : // On architectures with excess precision (or, at least, on x86), the
1401 : : // following call used to result in a segfault.
1402 : 10 : enquire1.get_mset(0, 10);
1403 : :
1404 : 10 : return true;
1405 : : }
1406 : :
1407 : : /// Test that the termfreq returned by termlists is correct.
1408 : 13 : DEFINE_TESTCASE(termlisttermfreq1, backend) {
1409 : 13 : Xapian::Database mydb(get_database("apitest_simpledata"));
1410 : 13 : Xapian::Enquire enquire(mydb);
1411 : 13 : Xapian::Stem stemmer("english");
1412 : 13 : Xapian::RSet rset1;
1413 : 13 : Xapian::RSet rset2;
1414 : 13 : rset1.add_document(5);
1415 : 13 : rset2.add_document(6);
1416 : :
1417 : 13 : Xapian::ESet eset1 = enquire.get_eset(1000, rset1);
1418 : 13 : Xapian::ESet eset2 = enquire.get_eset(1000, rset2);
1419 : :
1420 : : // search for weight of term 'another'
1421 : 13 : string theterm = stemmer("another");
1422 : :
1423 : 13 : Xapian::weight wt1 = 0;
1424 : 13 : Xapian::weight wt2 = 0;
1425 : : {
1426 : 13 : Xapian::ESetIterator i = eset1.begin();
1427 [ + - ]: 97 : for ( ; i != eset1.end(); i++) {
1428 [ + + ]: 97 : if (*i == theterm) {
1429 : 13 : wt1 = i.get_weight();
1430 : 13 : break;
1431 : : }
1432 : 13 : }
1433 : : }
1434 : : {
1435 : 13 : Xapian::ESetIterator i = eset2.begin();
1436 [ + - ]: 147 : for ( ; i != eset2.end(); i++) {
1437 [ + + ]: 147 : if (*i == theterm) {
1438 : 13 : wt2 = i.get_weight();
1439 : 13 : break;
1440 : : }
1441 : 13 : }
1442 : : }
1443 : :
1444 [ - + # # ]: 13 : TEST_NOT_EQUAL(wt1, 0);
1445 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(wt2, 0);
1446 [ - + ][ # # ]: 13 : TEST_EQUAL(wt1, wt2);
1447 : :
1448 : 13 : return true;
1449 : : }
1450 : :
1451 : : /// Test the termfrequency and termweight info returned for query terms
1452 : 13 : DEFINE_TESTCASE(qterminfo1, backend) {
1453 : 13 : Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1454 : 13 : Xapian::Enquire enquire1(mydb1);
1455 : :
1456 : 13 : Xapian::Database mydb2(get_database("apitest_simpledata"));
1457 : 13 : mydb2.add_database(get_database("apitest_simpledata2"));
1458 : 13 : Xapian::Enquire enquire2(mydb2);
1459 : :
1460 : : // make a query
1461 : 13 : Xapian::Stem stemmer("english");
1462 : :
1463 : 13 : string term1 = stemmer("word");
1464 : 13 : string term2 = stemmer("inmemory");
1465 : 13 : string term3 = stemmer("flibble");
1466 : :
1467 : : Xapian::Query myquery(Xapian::Query::OP_OR,
1468 : : Xapian::Query(term1),
1469 : : Xapian::Query(Xapian::Query::OP_OR,
1470 : : Xapian::Query(term2),
1471 : 13 : Xapian::Query(term3)));
1472 : 13 : enquire1.set_query(myquery);
1473 : 13 : enquire2.set_query(myquery);
1474 : :
1475 : : // retrieve the results
1476 : 13 : Xapian::MSet mymset1a = enquire1.get_mset(0, 0);
1477 : 13 : Xapian::MSet mymset2a = enquire2.get_mset(0, 0);
1478 : :
1479 [ - + # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term1),
1480 : : mymset2a.get_termfreq(term1));
1481 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term2),
1482 : : mymset2a.get_termfreq(term2));
1483 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term3),
1484 : : mymset2a.get_termfreq(term3));
1485 : :
1486 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term1), 3);
1487 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term2), 1);
1488 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(term3), 0);
1489 : :
1490 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(mymset1a.get_termweight(term1), 0);
1491 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(mymset1a.get_termweight(term2), 0);
1492 : : // non-existent terms should have 0 weight.
1493 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termweight(term3), 0);
1494 : :
1495 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq(stemmer("banana")), 1);
1496 [ + - ][ - + ]: 65 : TEST_EXCEPTION(Xapian::InvalidArgumentError,
[ # # ][ - + ]
1497 : : mymset1a.get_termweight(stemmer("banana")));
1498 : :
1499 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset1a.get_termfreq("sponge"), 0);
1500 [ + - ][ - + ]: 52 : TEST_EXCEPTION(Xapian::InvalidArgumentError,
[ # # ][ - + ]
1501 : : mymset1a.get_termweight("sponge"));
1502 : :
1503 : 13 : return true;
1504 : : }
1505 : :
1506 : : /// Regression test for bug #37.
1507 : 13 : DEFINE_TESTCASE(qterminfo2, backend) {
1508 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1509 : 13 : Xapian::Enquire enquire(db);
1510 : :
1511 : : // make a query
1512 : 13 : Xapian::Stem stemmer("english");
1513 : :
1514 : 13 : string term1 = stemmer("paragraph");
1515 : 13 : string term2 = stemmer("another");
1516 : :
1517 : : Xapian::Query query(Xapian::Query::OP_AND_NOT, term1,
1518 : 13 : Xapian::Query(Xapian::Query::OP_AND, term1, term2));
1519 : 13 : enquire.set_query(query);
1520 : :
1521 : : // retrieve the results
1522 : : // Note: get_mset() used to throw "AssertionError" in debug builds
1523 : 13 : Xapian::MSet mset = enquire.get_mset(0, 10);
1524 : :
1525 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(mset.get_termweight("paragraph"), 0);
1526 : :
1527 : 13 : return true;
1528 : : }
1529 : :
1530 : : // tests that when specifying that no items are to be returned, those
1531 : : // statistics which should be the same are.
1532 : 13 : DEFINE_TESTCASE(msetzeroitems1, backend) {
1533 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1534 : 13 : enquire.set_query(query("this"));
1535 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 0);
1536 : :
1537 : 13 : Xapian::MSet mymset2 = enquire.get_mset(0, 1);
1538 : :
1539 [ - + # # ]: 13 : TEST_EQUAL(mymset1.get_max_possible(), mymset2.get_max_possible());
1540 : :
1541 : 13 : return true;
1542 : : }
1543 : :
1544 : : // test that the matches_* of a simple query are as expected
1545 : 13 : DEFINE_TESTCASE(matches1, backend) {
1546 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1547 : 13 : Xapian::Query myquery;
1548 : 13 : Xapian::MSet mymset;
1549 : :
1550 : 13 : myquery = query("word");
1551 : 13 : enquire.set_query(myquery);
1552 : 13 : mymset = enquire.get_mset(0, 10);
1553 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1554 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1555 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1556 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1557 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1558 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1559 : :
1560 : 13 : myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
1561 : 13 : enquire.set_query(myquery);
1562 : 13 : mymset = enquire.get_mset(0, 10);
1563 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1564 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1565 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1566 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1567 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1568 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1569 : :
1570 : 13 : myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
1571 : 13 : enquire.set_query(myquery);
1572 : 13 : mymset = enquire.get_mset(0, 10);
1573 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1574 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 0);
1575 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
1576 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
1577 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
1578 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
1579 : :
1580 : 13 : myquery = query(Xapian::Query::OP_AND, "simple", "word");
1581 : 13 : enquire.set_query(myquery);
1582 : 13 : mymset = enquire.get_mset(0, 10);
1583 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1584 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1585 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1586 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1587 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1588 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1589 : :
1590 : 13 : myquery = query(Xapian::Query::OP_AND, "simple", "word");
1591 : 13 : enquire.set_query(myquery);
1592 : 13 : mymset = enquire.get_mset(0, 0);
1593 : : // For a single database, this is true, but not for "multi" (since there
1594 : : // one sub-database has 3 documents and simple and word both have termfreq
1595 : : // of 2, so the matcher can tell at least one document must match!)
1596 : : // TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1597 [ - + # # ]: 13 : TEST_REL(mymset.get_matches_lower_bound(),<=,mymset.get_matches_estimated());
1598 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 1);
1599 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1600 [ - + ][ # # ]: 13 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,mymset.get_uncollapsed_matches_estimated());
1601 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1602 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1603 : :
1604 : 13 : mymset = enquire.get_mset(0, 1);
1605 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1606 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1607 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1608 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1609 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1610 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1611 : :
1612 : 13 : mymset = enquire.get_mset(0, 2);
1613 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1614 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1615 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1616 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1617 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1618 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1619 : :
1620 : 13 : myquery = query(Xapian::Query::OP_AND, "paragraph", "another");
1621 : 13 : enquire.set_query(myquery);
1622 : 13 : mymset = enquire.get_mset(0, 0);
1623 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1624 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1625 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1626 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1627 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1628 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1629 : :
1630 : 13 : mymset = enquire.get_mset(0, 1);
1631 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1632 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 2);
1633 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1634 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1635 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1636 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1637 : :
1638 : 13 : mymset = enquire.get_mset(0, 2);
1639 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1640 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 1);
1641 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1642 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1643 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1644 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1645 : :
1646 : 13 : mymset = enquire.get_mset(1, 20);
1647 [ - + # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1648 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_estimated(), 1);
1649 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1650 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1651 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1652 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1653 : :
1654 : 13 : return true;
1655 : : }
1656 : :
1657 : : // tests that wqf affects the document weights
1658 : 13 : DEFINE_TESTCASE(wqf1, backend) {
1659 : : // Both queries have length 2; in q1 word has wqf=2, in q2 word has wqf=1
1660 : 13 : Xapian::Query q1("word", 2);
1661 : 13 : Xapian::Query q2("word");
1662 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1663 : 13 : enquire.set_query(q1);
1664 : 13 : Xapian::MSet mset1 = enquire.get_mset(0, 10);
1665 : 13 : enquire.set_query(q2);
1666 : 13 : Xapian::MSet mset2 = enquire.get_mset(0, 2);
1667 : : // Check the weights
1668 [ - + ][ # # ]: 13 : TEST(mset1.begin().get_weight() > mset2.begin().get_weight());
1669 : 13 : return true;
1670 : : }
1671 : :
1672 : : // tests that query length affects the document weights
1673 : 13 : DEFINE_TESTCASE(qlen1, backend) {
1674 : 13 : Xapian::Query q1("word");
1675 : 13 : Xapian::Query q2("word");
1676 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1677 : 13 : enquire.set_query(q1);
1678 : 13 : Xapian::MSet mset1 = enquire.get_mset(0, 10);
1679 : 13 : enquire.set_query(q2);
1680 : 13 : Xapian::MSet mset2 = enquire.get_mset(0, 2);
1681 : : // Check the weights
1682 : : //TEST(mset1.begin().get_weight() < mset2.begin().get_weight());
1683 [ - + ][ # # ]: 13 : TEST(mset1.begin().get_weight() == mset2.begin().get_weight());
1684 : 13 : return true;
1685 : : }
1686 : :
1687 : : // tests that opening a non-existent termlist throws the correct exception
1688 : 13 : DEFINE_TESTCASE(termlist1, backend) {
1689 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1690 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::InvalidArgumentError,
[ # # ][ - + ]
1691 : : Xapian::TermIterator t = db.termlist_begin(0));
1692 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError,
[ # # ][ - + ]
1693 : : Xapian::TermIterator t = db.termlist_begin(2));
1694 : : /* Cause the database to be used properly, showing up problems
1695 : : * with the link being in a bad state. CME */
1696 : 13 : Xapian::TermIterator temp = db.termlist_begin(1);
1697 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError,
[ # # ][ - + ]
1698 : : Xapian::TermIterator t = db.termlist_begin(999999999));
1699 : 13 : return true;
1700 : : }
1701 : :
1702 : : // tests that a Xapian::TermIterator works as an STL iterator
1703 : 13 : DEFINE_TESTCASE(termlist2, backend) {
1704 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1705 : 13 : Xapian::TermIterator t = db.termlist_begin(1);
1706 : 13 : Xapian::TermIterator tend = db.termlist_end(1);
1707 : :
1708 : : // test operator= creates a copy which compares equal
1709 : 13 : Xapian::TermIterator t_copy = t;
1710 [ - + # # ]: 13 : TEST_EQUAL(t, t_copy);
1711 : :
1712 : : // test copy constructor creates a copy which compares equal
1713 : 13 : Xapian::TermIterator t_clone(t);
1714 [ - + # # ]: 13 : TEST_EQUAL(t, t_clone);
1715 : :
1716 : 13 : vector<string> v(t, tend);
1717 : :
1718 : 13 : t = db.termlist_begin(1);
1719 : 13 : tend = db.termlist_end(1);
1720 : 13 : vector<string>::const_iterator i;
1721 [ + + ]: 130 : for (i = v.begin(); i != v.end(); i++) {
1722 [ - + ][ # # ]: 117 : TEST_NOT_EQUAL(t, tend);
1723 [ - + ][ # # ]: 117 : TEST_EQUAL(*i, *t);
1724 : 117 : t++;
1725 : : }
1726 [ - + ][ # # ]: 13 : TEST_EQUAL(t, tend);
1727 : 13 : return true;
1728 : : }
1729 : :
1730 : : static Xapian::TermIterator
1731 : 13 : test_termlist3_helper()
1732 : : {
1733 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1734 : 13 : return db.termlist_begin(1);
1735 : : }
1736 : :
1737 : : // tests that a Xapian::TermIterator still works when the DB is deleted
1738 : 13 : DEFINE_TESTCASE(termlist3, backend) {
1739 : 13 : Xapian::TermIterator u = test_termlist3_helper();
1740 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1741 : 13 : Xapian::TermIterator t = db.termlist_begin(1);
1742 : 13 : Xapian::TermIterator tend = db.termlist_end(1);
1743 : :
1744 [ + + ]: 130 : while (t != tend) {
1745 [ - + ][ # # ]: 117 : TEST_EQUAL(*t, *u);
1746 : 117 : t++;
1747 : 117 : u++;
1748 : : }
1749 : 13 : return true;
1750 : : }
1751 : :
1752 : : // tests skip_to
1753 : 13 : DEFINE_TESTCASE(termlist4, backend) {
1754 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1755 : 13 : Xapian::TermIterator i = db.termlist_begin(1);
1756 : 13 : i.skip_to("");
1757 : 13 : i.skip_to("\xff");
1758 : 13 : return true;
1759 : : }
1760 : :
1761 : : // tests punctuation is OK in terms (particularly in remote queries)
1762 : 13 : DEFINE_TESTCASE(puncterms1, backend) {
1763 : 13 : Xapian::Database db(get_database("apitest_punc"));
1764 : 13 : Xapian::Enquire enquire(db);
1765 : :
1766 : 13 : Xapian::Query q1("semi;colon");
1767 : 13 : enquire.set_query(q1);
1768 : 13 : Xapian::MSet m1 = enquire.get_mset(0, 10);
1769 : :
1770 : 13 : Xapian::Query q2("col:on");
1771 : 13 : enquire.set_query(q2);
1772 : 13 : Xapian::MSet m2 = enquire.get_mset(0, 10);
1773 : :
1774 : 13 : Xapian::Query q3("com,ma");
1775 : 13 : enquire.set_query(q3);
1776 : 13 : Xapian::MSet m3 = enquire.get_mset(0, 10);
1777 : :
1778 : 13 : return true;
1779 : : }
1780 : :
1781 : : // test that searching for a term with a space or backslash in it works
1782 : 13 : DEFINE_TESTCASE(spaceterms1, backend) {
1783 : 13 : Xapian::Enquire enquire(get_database("apitest_space"));
1784 : 13 : Xapian::MSet mymset;
1785 : : Xapian::doccount count;
1786 : 13 : Xapian::MSetIterator m;
1787 : 13 : Xapian::Stem stemmer("english");
1788 : :
1789 : 13 : enquire.set_query(stemmer("space man"));
1790 : 13 : mymset = enquire.get_mset(0, 10);
1791 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1792 : 13 : count = 0;
1793 [ + + ]: 26 : for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1794 [ - + ][ # # ]: 13 : TEST_EQUAL(count, 1);
1795 : :
1796 [ + + ]: 91 : for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
1797 [ - + ][ # # ]: 78 : TEST_NOT_EQUAL(mymset.begin().get_document().get_data(), "");
1798 [ - + ][ # # ]: 78 : TEST_NOT_EQUAL(mymset.begin().get_document().get_value(value_no), "");
1799 : : }
1800 : :
1801 : 13 : enquire.set_query(stemmer("tab\tby"));
1802 : 13 : mymset = enquire.get_mset(0, 10);
1803 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1804 : 13 : count = 0;
1805 [ + + ]: 26 : for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1806 [ - + ][ # # ]: 13 : TEST_EQUAL(count, 1);
1807 : :
1808 [ + + ]: 104 : for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
1809 : 91 : string value = mymset.begin().get_document().get_value(value_no);
1810 [ - + # # ]: 91 : TEST_NOT_EQUAL(value, "");
1811 [ + + ]: 91 : if (value_no == 0) {
1812 [ - + ][ # # ]: 13 : TEST(value.size() > 262);
1813 [ - + ][ # # ]: 13 : TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
1814 : : }
1815 : : }
1816 : :
1817 : 13 : enquire.set_query(stemmer("back\\slash"));
1818 : 13 : mymset = enquire.get_mset(0, 10);
1819 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1820 : 13 : count = 0;
1821 [ + + ]: 26 : for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1822 [ - + ][ # # ]: 13 : TEST_EQUAL(count, 1);
1823 : :
1824 : 13 : return true;
1825 : : }
1826 : :
1827 : : // test that XOR queries work
1828 : 13 : DEFINE_TESTCASE(xor1, backend) {
1829 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1830 : 13 : Xapian::Stem stemmer("english");
1831 : :
1832 : 13 : vector<string> terms;
1833 : 13 : terms.push_back(stemmer("this"));
1834 : 13 : terms.push_back(stemmer("word"));
1835 : 13 : terms.push_back(stemmer("of"));
1836 : :
1837 : 13 : Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1838 : 13 : enquire.set_weighting_scheme(Xapian::BoolWeight());
1839 : 13 : enquire.set_query(query);
1840 : :
1841 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1842 : : // Docid this word of Match?
1843 : : // 1 * *
1844 : : // 2 * * * *
1845 : : // 3 * *
1846 : : // 4 * *
1847 : : // 5 * *
1848 : : // 6 * *
1849 : 13 : mset_expect_order(mymset, 1, 2, 5, 6);
1850 : :
1851 : 13 : return true;
1852 : : }
1853 : :
1854 : : /// Test that weighted XOR queries work (bug fixed in 1.2.1 and 1.0.21).
1855 : 13 : DEFINE_TESTCASE(xor2, backend) {
1856 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1857 : 13 : Xapian::Stem stemmer("english");
1858 : :
1859 : 13 : vector<string> terms;
1860 : 13 : terms.push_back(stemmer("this"));
1861 : 13 : terms.push_back(stemmer("word"));
1862 : 13 : terms.push_back(stemmer("of"));
1863 : :
1864 : 13 : Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1865 : 13 : enquire.set_query(query);
1866 : :
1867 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1868 : : // Docid LEN this word of Match?
1869 : : // 1 28 2 *
1870 : : // 2 81 5 8 1 *
1871 : : // 3 15 1 2
1872 : : // 4 31 1 1
1873 : : // 5 15 1 *
1874 : : // 6 15 1 *
1875 : 13 : mset_expect_order(mymset, 2, 1, 5, 6);
1876 : :
1877 : 13 : return true;
1878 : : }
1879 : :
1880 : : // test Xapian::Database::get_document()
1881 : 13 : DEFINE_TESTCASE(getdoc1, backend) {
1882 : 13 : Xapian::Database db(get_database("apitest_onedoc"));
1883 : 13 : Xapian::Document doc(db.get_document(1));
1884 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_document(0));
[ # # ][ - + ]
1885 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(999999999));
[ # # ][ - + ]
1886 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(123456789));
[ # # ][ - + ]
1887 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
[ # # ][ - + ]
1888 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
1889 : : // Check that Document works as a handle on modification
1890 : : // (this was broken for the first try at Xapian::Document prior to 0.7).
1891 : 13 : Xapian::Document doc2 = doc;
1892 : 13 : doc.set_data("modified!");
1893 [ - + ][ # # ]: 13 : TEST_EQUAL(doc.get_data(), "modified!");
1894 [ - + ][ # # ]: 13 : TEST_EQUAL(doc.get_data(), doc2.get_data());
1895 : 13 : return true;
1896 : : }
1897 : :
1898 : : // test whether operators with no elements work as a null query
1899 : 13 : DEFINE_TESTCASE(emptyop1, backend) {
1900 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1901 : 13 : vector<Xapian::Query> nullvec;
1902 : :
1903 : 13 : Xapian::Query query1(Xapian::Query::OP_XOR, nullvec.begin(), nullvec.end());
1904 : :
1905 : 13 : enquire.set_query(query1);
1906 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
1907 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 0);
1908 [ + - ][ - + ]: 26 : TEST_EXCEPTION(Xapian::InvalidArgumentError, enquire.get_matching_terms_begin(1));
[ # # ][ - + ]
1909 : :
1910 : 13 : return true;
1911 : : }
1912 : :
1913 : : // Regression test for check_at_least SEGV when there are no matches.
1914 : 13 : DEFINE_TESTCASE(checkatleast1, backend) {
1915 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1916 : 13 : enquire.set_query(Xapian::Query("thom"));
1917 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10, 11);
1918 [ - + # # ]: 13 : TEST_EQUAL(0, mymset.size());
1919 : :
1920 : 13 : return true;
1921 : : }
1922 : :
1923 : : // Regression test - if check_at_least was set we returned (check_at_least - 1)
1924 : : // results, rather than the requested msize. Fixed in 1.0.2.
1925 : 13 : DEFINE_TESTCASE(checkatleast2, backend) {
1926 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1927 : 13 : enquire.set_query(Xapian::Query("paragraph"));
1928 : :
1929 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 3, 10);
1930 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 3);
1931 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_lower_bound(), 5);
1932 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 5);
1933 : :
1934 : 13 : mymset = enquire.get_mset(0, 2, 4);
1935 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 2);
1936 [ - + ][ # # ]: 13 : TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1937 [ - + ][ # # ]: 13 : TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1938 [ - + ][ # # ]: 13 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1939 [ - + ][ # # ]: 13 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1940 : :
1941 : 13 : return true;
1942 : : }
1943 : :
1944 : : // Feature tests - check_at_least with various sorting options.
1945 : 13 : DEFINE_TESTCASE(checkatleast3, backend) {
1946 : 13 : Xapian::Enquire enquire(get_database("etext"));
1947 : 13 : enquire.set_query(Xapian::Query("prussian")); // 60 matches.
1948 : :
1949 [ + + ]: 52 : for (int order = 0; order < 3; ++order) {
1950 [ + + + - ]: 39 : switch (order) {
1951 : : case 0:
1952 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1953 : 13 : break;
1954 : : case 1:
1955 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1956 : 13 : break;
1957 : : case 2:
1958 : 13 : enquire.set_docid_order(Xapian::Enquire::DONT_CARE);
1959 : : break;
1960 : : }
1961 : :
1962 [ + + ]: 312 : for (int sort = 0; sort < 7; ++sort) {
1963 : 273 : bool reverse = (sort & 1);
1964 [ + + + + : 273 : switch (sort) {
- ]
1965 : : case 0:
1966 : 39 : enquire.set_sort_by_relevance();
1967 : 39 : break;
1968 : : case 1: case 2:
1969 : 78 : enquire.set_sort_by_value(0, reverse);
1970 : 78 : break;
1971 : : case 3: case 4:
1972 : 78 : enquire.set_sort_by_value_then_relevance(0, reverse);
1973 : 78 : break;
1974 : : case 5: case 6:
1975 : 78 : enquire.set_sort_by_relevance_then_value(0, reverse);
1976 : : break;
1977 : : }
1978 : :
1979 : 273 : Xapian::MSet mset = enquire.get_mset(0, 100, 500);
1980 [ - + # # ]: 273 : TEST_MSET_SIZE(mset, 60);
1981 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_lower_bound(), 60);
1982 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_estimated(), 60);
1983 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_upper_bound(), 60);
1984 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
1985 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
1986 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
1987 : :
1988 : 273 : mset = enquire.get_mset(0, 50, 100);
1989 [ - + # # ]: 273 : TEST_MSET_SIZE(mset, 50);
1990 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_lower_bound(), 60);
1991 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_estimated(), 60);
1992 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_matches_upper_bound(), 60);
1993 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
1994 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
1995 [ - + ][ # # ]: 273 : TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
1996 : :
1997 : 273 : mset = enquire.get_mset(0, 10, 50);
1998 [ - + # # ]: 273 : TEST_MSET_SIZE(mset, 10);
1999 [ - + ][ # # ]: 273 : TEST_REL(mset.get_matches_lower_bound(),>=,50);
2000 [ - + ][ # # ]: 273 : TEST_REL(mset.get_uncollapsed_matches_lower_bound(),>=,50);
2001 : 273 : }
2002 : : }
2003 : :
2004 : 13 : return true;
2005 : : }
2006 : :
2007 : : // tests all document postlists
2008 : 13 : DEFINE_TESTCASE(allpostlist1, backend) {
2009 : 13 : Xapian::Database db(get_database("apitest_manydocs"));
2010 : 13 : Xapian::PostingIterator i = db.postlist_begin("");
2011 : 13 : unsigned int j = 1;
2012 [ + + ]: 6669 : while (i != db.postlist_end("")) {
2013 [ - + ][ # # ]: 6656 : TEST_EQUAL(*i, j);
2014 : 6656 : i++;
2015 : 6656 : j++;
2016 : : }
2017 [ - + ][ # # ]: 13 : TEST_EQUAL(j, 513);
2018 : :
2019 : 13 : i = db.postlist_begin("");
2020 : 13 : j = 1;
2021 [ + + ]: 6539 : while (i != db.postlist_end("")) {
2022 [ - + ][ # # ]: 6526 : TEST_EQUAL(*i, j);
2023 : 6526 : i++;
2024 : 6526 : j++;
2025 [ + + ]: 6526 : if (j == 50) {
2026 : 13 : j += 10;
2027 : 13 : i.skip_to(j);
2028 : : }
2029 : : }
2030 [ - + ][ # # ]: 13 : TEST_EQUAL(j, 513);
2031 : :
2032 : 13 : return true;
2033 : : }
2034 : :
2035 : 39 : static void test_emptyterm1_helper(Xapian::Database & db)
2036 : : {
2037 : : // Don't bother with postlist_begin() because allpostlist tests cover that.
2038 [ + - ][ - + ]: 156 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
[ # # ][ - + ]
2039 [ - + ][ # # ]: 39 : TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
2040 [ - + ][ # # ]: 39 : TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
2041 [ - + ][ # # ]: 39 : TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
2042 : 39 : }
2043 : :
2044 : : // tests results of passing an empty term to various methods
2045 : 13 : DEFINE_TESTCASE(emptyterm1, backend) {
2046 : 13 : Xapian::Database db(get_database("apitest_manydocs"));
2047 [ - + # # ]: 13 : TEST_EQUAL(db.get_doccount(), 512);
2048 : 13 : test_emptyterm1_helper(db);
2049 : :
2050 : 13 : db = get_database("apitest_onedoc");
2051 [ - + # # ]: 13 : TEST_EQUAL(db.get_doccount(), 1);
2052 : 13 : test_emptyterm1_helper(db);
2053 : :
2054 : 13 : db = get_database("");
2055 [ - + # # ]: 13 : TEST_EQUAL(db.get_doccount(), 0);
2056 : 13 : test_emptyterm1_helper(db);
2057 : :
2058 : 13 : return true;
2059 : : }
2060 : :
2061 : : // Test for alldocs postlist with a sparse database.
2062 : 10 : DEFINE_TESTCASE(alldocspl1, writable) {
2063 : 10 : Xapian::WritableDatabase db = get_writable_database();
2064 : 10 : Xapian::Document doc;
2065 : 10 : doc.set_data("5");
2066 : 10 : doc.add_value(0, "5");
2067 : 10 : db.replace_document(5, doc);
2068 : :
2069 : 10 : Xapian::PostingIterator i = db.postlist_begin("");
2070 [ - + ][ # # ]: 10 : TEST(i != db.postlist_end(""));
2071 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 5);
2072 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2073 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2074 : 10 : ++i;
2075 [ - + ][ # # ]: 10 : TEST(i == db.postlist_end(""));
2076 : :
2077 : 10 : return true;
2078 : : }
2079 : :
2080 : : // Test reading and writing a modified alldocspostlist.
2081 : 10 : DEFINE_TESTCASE(alldocspl2, writable) {
2082 : 10 : Xapian::PostingIterator i, end;
2083 : : {
2084 : 10 : Xapian::WritableDatabase db = get_writable_database();
2085 : 10 : Xapian::Document doc;
2086 : 10 : doc.set_data("5");
2087 : 10 : doc.add_value(0, "5");
2088 : 10 : db.replace_document(5, doc);
2089 : :
2090 : : // Test iterating before committing the changes.
2091 : 10 : i = db.postlist_begin("");
2092 : 10 : end = db.postlist_end("");
2093 [ - + # # ]: 10 : TEST(i != end);
2094 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 5);
2095 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2096 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2097 : 10 : ++i;
2098 [ - + # # ]: 10 : TEST(i == end);
2099 : :
2100 : 10 : db.commit();
2101 : :
2102 : : // Test iterating after committing the changes.
2103 : 10 : i = db.postlist_begin("");
2104 : 10 : end = db.postlist_end("");
2105 [ - + # # ]: 10 : TEST(i != end);
2106 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 5);
2107 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2108 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2109 : 10 : ++i;
2110 [ - + # # ]: 10 : TEST(i == end);
2111 : :
2112 : : // Add another document.
2113 : 10 : doc = Xapian::Document();
2114 : 10 : doc.set_data("5");
2115 : 10 : doc.add_value(0, "7");
2116 : 10 : db.replace_document(7, doc);
2117 : :
2118 : : // Test iterating through before committing the changes.
2119 : 10 : i = db.postlist_begin("");
2120 : 10 : end = db.postlist_end("");
2121 [ - + # # ]: 10 : TEST(i != end);
2122 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 5);
2123 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2124 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2125 : 10 : ++i;
2126 [ - + # # ]: 10 : TEST(i != end);
2127 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 7);
2128 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2129 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2130 : 10 : ++i;
2131 [ - + # # ]: 10 : TEST(i == end);
2132 : :
2133 : : // Delete the first document.
2134 : 10 : db.delete_document(5);
2135 : :
2136 : : // Test iterating through before committing the changes.
2137 : 10 : i = db.postlist_begin("");
2138 : 10 : end = db.postlist_end("");
2139 [ - + # # ]: 10 : TEST(i != end);
2140 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 7);
2141 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2142 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2143 : 10 : ++i;
2144 [ - + # # ]: 10 : TEST(i == end);
2145 : :
2146 : : // Test iterating through after committing the changes, and dropping the
2147 : : // reference to the main DB.
2148 : 10 : db.commit();
2149 : 10 : i = db.postlist_begin("");
2150 : 10 : end = db.postlist_end("");
2151 : : }
2152 : :
2153 [ - + # # ]: 10 : TEST(i != end);
2154 [ - + ][ # # ]: 10 : TEST_EQUAL(*i, 7);
2155 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_doclength(), 0);
2156 [ - + ][ # # ]: 10 : TEST_EQUAL(i.get_wdf(), 1);
2157 : 10 : ++i;
2158 [ - + # # ]: 10 : TEST(i == end);
2159 : :
2160 : 10 : return true;
2161 : : }
2162 : :
2163 : : // Feature test for Query::OP_SCALE_WEIGHT.
2164 : 13 : DEFINE_TESTCASE(scaleweight1, backend) {
2165 : 13 : Xapian::Database db(get_database("apitest_phrase"));
2166 : 13 : Xapian::Enquire enq(db);
2167 : 13 : Xapian::QueryParser qp;
2168 : :
2169 : : static const char * queries[] = {
2170 : : "pad",
2171 : : "milk fridge",
2172 : : "leave milk on fridge",
2173 : : "ordered milk operator",
2174 : : "ordered phrase operator",
2175 : : "leave \"milk on fridge\"",
2176 : : "notpresent",
2177 : : "leave \"milk notpresent\"",
2178 : : NULL
2179 : : };
2180 : : static const double multipliers[] = {
2181 : : -1000000, -2.5, -1, -0.5, 0, 0.5, 1, 2.5, 1000000,
2182 : : 0, 0
2183 : : };
2184 : :
2185 [ + + ]: 117 : for (const char **qstr = queries; *qstr; ++qstr) {
2186 : 104 : tout.str(string());
2187 : 104 : Xapian::Query query1 = qp.parse_query(*qstr);
2188 : 104 : tout << "query1: " << query1.get_description() << endl;
2189 [ + + ]: 1040 : for (const double *multp = multipliers; multp[0] != multp[1]; ++multp) {
2190 : 936 : double mult = *multp;
2191 [ + + ]: 936 : if (mult < 0) {
2192 [ + - ][ - + ]: 1248 : TEST_EXCEPTION(Xapian::InvalidArgumentError,
[ # # ][ - + ]
2193 : : Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
2194 : : query1, mult));
2195 : 416 : continue;
2196 : : }
2197 : 520 : Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, mult);
2198 : 520 : tout << "query2: " << query2.get_description() << endl;
2199 : :
2200 : 520 : enq.set_query(query1);
2201 : 520 : Xapian::MSet mset1 = enq.get_mset(0, 20);
2202 : 520 : enq.set_query(query2);
2203 : 520 : Xapian::MSet mset2 = enq.get_mset(0, 20);
2204 : :
2205 [ - + # # ]: 520 : TEST_EQUAL(mset1.size(), mset2.size());
2206 : :
2207 : 520 : Xapian::MSetIterator i1, i2;
2208 [ + + ]: 520 : if (mult > 0) {
2209 [ + + ][ + - ]: 2652 : for (i1 = mset1.begin(), i2 = mset2.begin();
[ + + ][ # # ]
[ # # ][ + - ]
[ + + ]
2210 : : i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2211 [ - + ][ # # ]: 2236 : TEST_EQUAL_DOUBLE(i1.get_weight() * mult, i2.get_weight());
2212 [ - + ][ # # ]: 2236 : TEST_EQUAL(*i1, *i2);
2213 : : }
2214 : : } else {
2215 : : // Weights in mset2 are 0; so it should be sorted by docid.
2216 : 104 : vector<Xapian::docid> ids1;
2217 : 104 : vector<Xapian::docid> ids2;
2218 [ + + ][ + - ]: 663 : for (i1 = mset1.begin(), i2 = mset2.begin();
[ + + ][ # # ]
[ # # ][ + - ]
[ + + ]
2219 : : i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2220 [ - + ][ # # ]: 559 : TEST_NOT_EQUAL_DOUBLE(i1.get_weight(), 0);
2221 [ - + ][ # # ]: 559 : TEST_EQUAL_DOUBLE(i2.get_weight(), 0);
2222 : 559 : ids1.push_back(*i1);
2223 : 559 : ids2.push_back(*i2);
2224 : : }
2225 : 104 : sort(ids1.begin(), ids1.end());
2226 [ - + # # ]: 104 : TEST_EQUAL(ids1, ids2);
2227 : : }
2228 : : }
2229 : : }
2230 : 13 : return true;
2231 : : }
2232 : :
2233 : : // Test Query::OP_SCALE_WEIGHT being used to multiply some of the weights of a
2234 : : // search by zero.
2235 : 13 : DEFINE_TESTCASE(scaleweight2, backend) {
2236 : 13 : Xapian::Database db(get_database("apitest_phrase"));
2237 : 13 : Xapian::Enquire enq(db);
2238 : 13 : Xapian::MSetIterator i;
2239 : :
2240 : 13 : Xapian::Query query1("fridg");
2241 : 13 : Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, 2.5);
2242 : 13 : Xapian::Query query3("milk");
2243 : 13 : Xapian::Query query4(Xapian::Query::OP_SCALE_WEIGHT, query3, 0);
2244 : 13 : Xapian::Query query5(Xapian::Query::OP_OR, query2, query4);
2245 : :
2246 : : // query5 should first return the same results as query1, in the same
2247 : : // order, and then return the results of query3 which aren't also results
2248 : : // of query1, in ascending docid order. We test that this happens.
2249 : :
2250 : : // First, build a vector of docids matching the first part of the query,
2251 : : // and append the non-duplicate docids matching the second part of the
2252 : : // query.
2253 : 13 : vector<Xapian::docid> ids1;
2254 : 13 : set<Xapian::docid> idsin1;
2255 : 13 : vector<Xapian::docid> ids3;
2256 : :
2257 : 13 : enq.set_query(query1);
2258 : 13 : Xapian::MSet mset1 = enq.get_mset(0, 20);
2259 : 13 : enq.set_query(query3);
2260 : 13 : Xapian::MSet mset3 = enq.get_mset(0, 20);
2261 [ - + # # ]: 13 : TEST_NOT_EQUAL(mset1.size(), 0);
2262 [ + + ]: 156 : for (i = mset1.begin(); i != mset1.end(); ++i) {
2263 : 143 : ids1.push_back(*i);
2264 : 143 : idsin1.insert(*i);
2265 : : }
2266 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(mset3.size(), 0);
2267 [ + + ]: 104 : for (i = mset3.begin(); i != mset3.end(); ++i) {
2268 [ + + ]: 91 : if (idsin1.find(*i) != idsin1.end())
2269 : 65 : continue;
2270 : 26 : ids3.push_back(*i);
2271 : : }
2272 : 13 : sort(ids3.begin(), ids3.end());
2273 : 13 : ids1.insert(ids1.end(), ids3.begin(), ids3.end());
2274 : :
2275 : : // Now, run the combined query and build a vector of the matching docids.
2276 : 13 : vector<Xapian::docid> ids5;
2277 : 13 : enq.set_query(query5);
2278 : 13 : Xapian::MSet mset5 = enq.get_mset(0, 20);
2279 [ + + ]: 182 : for (i = mset5.begin(); i != mset5.end(); ++i) {
2280 : 169 : ids5.push_back(*i);
2281 : : }
2282 : :
2283 [ - + ][ # # ]: 13 : TEST_EQUAL(ids1, ids5);
2284 : 13 : return true;
2285 : : }
2286 : :
2287 : : // Regression test for bug fixed in 1.0.5 - this test would failed under
2288 : : // valgrind because it used an uninitialised value.
2289 : 13 : DEFINE_TESTCASE(bm25weight1, backend) {
2290 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
2291 : 13 : enquire.set_weighting_scheme(Xapian::BM25Weight(1, 25, 1, 0.01, 0.5));
2292 : 13 : enquire.set_query(Xapian::Query("word") );
2293 : :
2294 : 13 : Xapian::MSet mset = enquire.get_mset(0, 25);
2295 : :
2296 : 13 : return true;
2297 : : }
2298 : :
2299 : : // Feature test for TradWeight.
2300 : 13 : DEFINE_TESTCASE(tradweight1, backend) {
2301 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
2302 : 13 : enquire.set_weighting_scheme(Xapian::TradWeight());
2303 : 13 : enquire.set_query(Xapian::Query("word") );
2304 : :
2305 : 13 : Xapian::MSet mset = enquire.get_mset(0, 25);
2306 : :
2307 : 13 : enquire.set_weighting_scheme(Xapian::TradWeight(0));
2308 : 13 : enquire.set_query(Xapian::Query("word") );
2309 : :
2310 : 13 : mset = enquire.get_mset(0, 25);
2311 : : // FIXME: should check that TradWeight(0) means wdf and doc length really
2312 : : // don't affect the weights as stated in the documentation.
2313 : :
2314 : 13 : return true;
2315 : : }
2316 : :
2317 : : // Feature test for Database::get_uuid().
2318 : 10 : DEFINE_TESTCASE(uuid1, backend && !multi) {
2319 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
2320 : 9 : Xapian::Database db = get_database("apitest_simpledata");
2321 : 9 : string uuid1 = db.get_uuid();
2322 [ - + # # ]: 9 : TEST_EQUAL(uuid1.size(), 36);
2323 : :
2324 : : // A database with no sub-databases has an empty UUID.
2325 : 9 : Xapian::Database db2;
2326 [ - + ][ # # ]: 9 : TEST(db2.get_uuid().empty());
2327 : :
2328 : 9 : db2.add_database(db);
2329 [ - + ][ # # ]: 9 : TEST_EQUAL(uuid1, db2.get_uuid());
2330 : :
2331 : : // Multi-database has multiple UUIDs (we don't define the format exactly
2332 : : // so this assumes something about the implementation).
2333 : 9 : db2.add_database(db);
2334 [ - + ][ # # ]: 9 : TEST_EQUAL(uuid1 + ":" + uuid1, db2.get_uuid());
2335 : :
2336 : : #ifdef XAPIAN_HAS_INMEMORY_BACKEND
2337 : : // This relies on InMemory databases not supporting uuids.
2338 : : // A multi-database containing a database with no uuid has no uuid.
2339 : 9 : db2.add_database(Xapian::InMemory::open());
2340 [ - + ][ # # ]: 9 : TEST(db2.get_uuid().empty());
2341 : : #endif
2342 : :
2343 : 9 : return true;
2344 : : }
|