Eliminate broken PostListCursor for non-const HoneyTable
[xapian.git] / xapian-core / tests / api_anydb.cc
blob568ad2255c7e90d4e11837eacf229d1629f494ef
1 /* api_anydb.cc: tests which work with any backend
3 * Copyright 1999,2000,2001 BrightStation PLC
4 * Copyright 2002 Ananova Ltd
5 * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2015,2016,2017 Olly Betts
6 * Copyright 2006,2008 Lemur Consulting Ltd
7 * Copyright 2011 Action Without Borders
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.
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.
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
25 #include <config.h>
27 #include "api_anydb.h"
29 #include <algorithm>
30 #include <string>
32 #define XAPIAN_DEPRECATED(X) X
33 #include <xapian.h>
34 #include "backendmanager_local.h"
35 #include "testsuite.h"
36 #include "testutils.h"
38 #include "apitest.h"
40 #include <list>
42 using namespace std;
44 static void
45 print_mset_weights(const Xapian::MSet &mset)
47 Xapian::MSetIterator i = mset.begin();
48 for ( ; i != mset.end(); ++i) {
49 tout << " " << i.get_weight();
53 static void
54 print_mset_percentages(const Xapian::MSet &mset)
56 Xapian::MSetIterator i = mset.begin();
57 for ( ; i != mset.end(); ++i) {
58 tout << " " << mset.convert_to_percent(i);
62 static Xapian::Query
63 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())
70 vector<string> v;
71 Xapian::Stem stemmer("english");
72 if (!t1.empty()) v.push_back(stemmer(t1));
73 if (!t2.empty()) v.push_back(stemmer(t2));
74 if (!t3.empty()) v.push_back(stemmer(t3));
75 if (!t4.empty()) v.push_back(stemmer(t4));
76 if (!t5.empty()) v.push_back(stemmer(t5));
77 if (!t6.empty()) v.push_back(stemmer(t6));
78 if (!t7.empty()) v.push_back(stemmer(t7));
79 if (!t8.empty()) v.push_back(stemmer(t8));
80 if (!t9.empty()) v.push_back(stemmer(t9));
81 if (!t10.empty()) v.push_back(stemmer(t10));
82 return Xapian::Query(op, v.begin(), v.end());
85 static Xapian::Query
86 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())
93 vector<string> v;
94 Xapian::Stem stemmer("english");
95 if (!t1.empty()) v.push_back(stemmer(t1));
96 if (!t2.empty()) v.push_back(stemmer(t2));
97 if (!t3.empty()) v.push_back(stemmer(t3));
98 if (!t4.empty()) v.push_back(stemmer(t4));
99 if (!t5.empty()) v.push_back(stemmer(t5));
100 if (!t6.empty()) v.push_back(stemmer(t6));
101 if (!t7.empty()) v.push_back(stemmer(t7));
102 if (!t8.empty()) v.push_back(stemmer(t8));
103 if (!t9.empty()) v.push_back(stemmer(t9));
104 if (!t10.empty()) v.push_back(stemmer(t10));
105 return Xapian::Query(op, v.begin(), v.end(), parameter);
108 static Xapian::Query
109 query(const string &t)
111 return Xapian::Query(Xapian::Stem("english")(t));
114 // #######################################################################
115 // # Tests start here
117 // tests that the backend doesn't return zero docids
118 DEFINE_TESTCASE(zerodocid1, backend) {
119 // open the database (in this case a simple text file
120 // we prepared earlier)
122 Xapian::Database mydb(get_database("apitest_onedoc"));
124 Xapian::Enquire enquire(mydb);
126 // make a simple query, with one word in it - "word".
127 enquire.set_query(Xapian::Query("word"));
129 // retrieve the top ten results (we only expect one)
130 Xapian::MSet mymset = enquire.get_mset(0, 10);
132 // We've done the query, now check that the result is what
133 // we expect (1 document, with non-zero docid)
134 TEST_MSET_SIZE(mymset, 1);
136 TEST_AND_EXPLAIN(*(mymset.begin()) != 0,
137 "A query on a database returned a zero docid");
139 return true;
142 // tests that an empty query returns no matches
143 DEFINE_TESTCASE(emptyquery1, backend) {
144 Xapian::Enquire enquire(get_database("apitest_simpledata"));
146 enquire.set_query(Xapian::Query());
147 Xapian::MSet mymset = enquire.get_mset(0, 10);
148 TEST_MSET_SIZE(mymset, 0);
149 TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
150 TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
151 TEST_EQUAL(mymset.get_matches_estimated(), 0);
152 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
153 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
154 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
156 vector<Xapian::Query> v;
157 enquire.set_query(Xapian::Query(Xapian::Query::OP_AND, v.begin(), v.end()));
158 mymset = enquire.get_mset(0, 10);
159 TEST_MSET_SIZE(mymset, 0);
160 TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
161 TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
162 TEST_EQUAL(mymset.get_matches_estimated(), 0);
163 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
164 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
165 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
167 return true;
170 // tests the document count for a simple query
171 DEFINE_TESTCASE(simplequery1, backend) {
172 Xapian::Enquire enquire(get_database("apitest_simpledata"));
173 enquire.set_query(Xapian::Query("word"));
174 Xapian::MSet mymset = enquire.get_mset(0, 10);
175 TEST_MSET_SIZE(mymset, 2);
176 return true;
179 // tests for the right documents and weights returned with simple query
180 DEFINE_TESTCASE(simplequery2, backend) {
181 // open the database (in this case a simple text file
182 // we prepared earlier)
183 Xapian::Database db = get_database("apitest_simpledata");
184 Xapian::Enquire enquire(db);
185 enquire.set_query(Xapian::Query("word"));
187 // retrieve the top results
188 Xapian::MSet mymset = enquire.get_mset(0, 10);
190 // We've done the query, now check that the result is what
191 // we expect (documents 2 and 4)
192 mset_expect_order(mymset, 2, 4);
194 // Check the weights
195 Xapian::MSetIterator i = mymset.begin();
196 // These weights are for BM25Weight(1,0,1,0.5,0.5)
197 TEST_EQUAL_DOUBLE(i.get_weight(), 1.04648168717725);
198 i++;
199 TEST_EQUAL_DOUBLE(i.get_weight(), 0.640987686595914);
201 return true;
204 // tests for the right document count for another simple query
205 DEFINE_TESTCASE(simplequery3, backend) {
206 Xapian::Enquire enquire(get_database("apitest_simpledata"));
207 enquire.set_query(query("this"));
208 Xapian::MSet mymset = enquire.get_mset(0, 10);
210 // Check that 6 documents were returned.
211 TEST_MSET_SIZE(mymset, 6);
213 return true;
216 // multidb1 and multidb2 no longer exist.
218 // test that a multidb with 2 dbs query returns correct docids
219 DEFINE_TESTCASE(multidb3, backend && !multi) {
220 Xapian::Database mydb2(get_database("apitest_simpledata"));
221 mydb2.add_database(get_database("apitest_simpledata2"));
222 Xapian::Enquire enquire(mydb2);
224 // make a query
225 Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
226 enquire.set_weighting_scheme(Xapian::BoolWeight());
227 enquire.set_query(myquery);
229 // retrieve the top ten results
230 Xapian::MSet mymset = enquire.get_mset(0, 10);
231 mset_expect_order(mymset, 2, 3, 7);
233 return true;
236 // test that a multidb with 3 dbs query returns correct docids
237 DEFINE_TESTCASE(multidb4, backend && !multi) {
238 Xapian::Database mydb2(get_database("apitest_simpledata"));
239 mydb2.add_database(get_database("apitest_simpledata2"));
240 mydb2.add_database(get_database("apitest_termorder"));
241 Xapian::Enquire enquire(mydb2);
243 // make a query
244 Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
245 enquire.set_weighting_scheme(Xapian::BoolWeight());
246 enquire.set_query(myquery);
248 // retrieve the top ten results
249 Xapian::MSet mymset = enquire.get_mset(0, 10);
250 mset_expect_order(mymset, 2, 3, 4, 10);
252 return true;
255 // tests MultiPostList::skip_to().
256 DEFINE_TESTCASE(multidb5, backend && !multi) {
257 Xapian::Database mydb2(get_database("apitest_simpledata"));
258 mydb2.add_database(get_database("apitest_simpledata2"));
259 Xapian::Enquire enquire(mydb2);
261 // make a query
262 Xapian::Query myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
263 enquire.set_weighting_scheme(Xapian::BoolWeight());
264 enquire.set_query(myquery);
266 // retrieve the top ten results
267 Xapian::MSet mymset = enquire.get_mset(0, 10);
268 mset_expect_order(mymset, 2);
270 return true;
273 // tests that when specifying maxitems to get_mset, no more than
274 // that are returned.
275 DEFINE_TESTCASE(msetmaxitems1, backend) {
276 Xapian::Enquire enquire(get_database("apitest_simpledata"));
277 enquire.set_query(query("this"));
278 Xapian::MSet mymset = enquire.get_mset(0, 1);
279 TEST_MSET_SIZE(mymset, 1);
281 mymset = enquire.get_mset(0, 5);
282 TEST_MSET_SIZE(mymset, 5);
284 return true;
287 // tests the returned weights are as expected (regression test for remote
288 // backend which was using the average weight rather than the actual document
289 // weight for computing weights - fixed in 1.0.0).
290 DEFINE_TESTCASE(expandweights1, backend) {
291 Xapian::Enquire enquire(get_database("apitest_simpledata"));
292 enquire.set_query(Xapian::Query("this"));
294 Xapian::MSet mymset = enquire.get_mset(0, 10);
296 Xapian::RSet myrset;
297 Xapian::MSetIterator i = mymset.begin();
298 myrset.add_document(*i);
299 myrset.add_document(*(++i));
301 Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
302 TEST_EQUAL(eset.size(), 3);
303 TEST_REL(eset.get_ebound(), >=, eset.size());
304 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
305 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
306 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
308 // Test non-default k too.
309 enquire.set_expansion_scheme("trad", 2.0);
310 eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
311 TEST_EQUAL(eset.size(), 3);
312 TEST_REL(eset.get_ebound(), >=, eset.size());
313 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 5.88109547674955);
314 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 5.88109547674955);
315 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.44473599216144);
317 return true;
320 // Just like test_expandweights1 but without USE_EXACT_TERMFREQ.
321 DEFINE_TESTCASE(expandweights2, backend) {
322 Xapian::Enquire enquire(get_database("apitest_simpledata"));
323 enquire.set_query(Xapian::Query("this"));
325 Xapian::MSet mymset = enquire.get_mset(0, 10);
327 Xapian::RSet myrset;
328 Xapian::MSetIterator i = mymset.begin();
329 myrset.add_document(*i);
330 myrset.add_document(*(++i));
332 Xapian::ESet eset = enquire.get_eset(3, myrset);
333 TEST_EQUAL(eset.size(), 3);
334 TEST_REL(eset.get_ebound(), >=, eset.size());
335 if (!startswith(get_dbtype(), "multi")) {
336 // For a single database, the weights should be the same with or
337 // without USE_EXACT_TERMFREQ.
338 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
339 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
340 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
341 } else {
342 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
343 // will result in different weights in some cases.
344 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
345 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
346 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
349 return true;
352 DEFINE_TESTCASE(expandweights3, backend) {
353 Xapian::Enquire enquire(get_database("apitest_simpledata"));
354 enquire.set_query(Xapian::Query("this"));
356 Xapian::MSet mymset = enquire.get_mset(0, 10);
358 Xapian::RSet myrset;
359 Xapian::MSetIterator i = mymset.begin();
360 myrset.add_document(*i);
361 myrset.add_document(*(++i));
363 // Set min_wt to 0.0
364 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 0, 0.0);
365 TEST_EQUAL(eset.size(), 50);
366 TEST_REL(eset.get_ebound(), >=, eset.size());
367 if (!startswith(get_dbtype(), "multi")) {
368 // For a single database, the weights should be the same with or
369 // without USE_EXACT_TERMFREQ.
370 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
371 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
372 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
373 } else {
374 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
375 // will result in different weights in some cases.
376 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
377 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
378 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
380 TEST_REL(eset.back().get_weight(),>=,0);
382 return true;
386 // tests that negative weights are returned
387 DEFINE_TESTCASE(expandweights4, backend) {
388 Xapian::Enquire enquire(get_database("apitest_simpledata"));
389 enquire.set_query(Xapian::Query("paragraph"));
391 Xapian::MSet mymset = enquire.get_mset(0, 10);
393 Xapian::RSet myrset;
394 Xapian::MSetIterator i = mymset.begin();
395 myrset.add_document(*i);
396 myrset.add_document(*(++i));
398 Xapian::ESet eset = enquire.get_eset(37, myrset, 0, 0, -100);
399 // Now include negative weights
400 TEST_EQUAL(eset.size(), 37);
401 TEST_REL(eset.get_ebound(), >=, eset.size());
402 TEST_REL(eset[36].get_weight(), <, 0);
403 TEST_REL(eset[36].get_weight(), >=, -100);
405 return true;
408 // test for Bo1EWeight
409 DEFINE_TESTCASE(expandweights5, backend) {
410 Xapian::Enquire enquire(get_database("apitest_simpledata"));
411 enquire.set_query(Xapian::Query("this"));
413 Xapian::MSet mymset = enquire.get_mset(0, 10);
415 Xapian::RSet myrset;
416 Xapian::MSetIterator i = mymset.begin();
417 myrset.add_document(*i);
418 myrset.add_document(*(++i));
420 enquire.set_expansion_scheme("bo1");
421 Xapian::ESet eset = enquire.get_eset(3, myrset);
423 TEST_EQUAL(eset.size(), 3);
424 TEST_REL(eset.get_ebound(), >=, eset.size());
425 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 7.21765284821702);
426 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.661623193760022);
427 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.58090119783738);
429 return true;
432 // test that "trad" can be set as an expansion scheme.
433 DEFINE_TESTCASE(expandweights6, backend) {
434 Xapian::Enquire enquire(get_database("apitest_simpledata"));
435 enquire.set_query(Xapian::Query("this"));
437 Xapian::MSet mymset = enquire.get_mset(0, 10);
439 Xapian::RSet myrset;
440 Xapian::MSetIterator i = mymset.begin();
441 myrset.add_document(*i);
442 myrset.add_document(*(++i));
444 enquire.set_expansion_scheme("trad");
445 Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
447 TEST_EQUAL(eset.size(), 3);
448 TEST_REL(eset.get_ebound(), >=, eset.size());
449 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
450 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
451 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
453 return true;
456 // test that invalid scheme names are not accepted
457 DEFINE_TESTCASE(expandweights7, backend) {
458 Xapian::Enquire enquire(get_database("apitest_simpledata"));
460 TEST_EXCEPTION(Xapian::InvalidArgumentError,
461 enquire.set_expansion_scheme("no_such_scheme"));
463 return true;
466 // test that "expand_k" can be passed as a parameter to get_eset
467 DEFINE_TESTCASE(expandweights8, backend) {
468 Xapian::Enquire enquire(get_database("apitest_simpledata"));
469 enquire.set_query(Xapian::Query("this"));
471 Xapian::MSet mymset = enquire.get_mset(0, 10);
473 Xapian::RSet myrset;
474 Xapian::MSetIterator i = mymset.begin();
475 myrset.add_document(*i);
476 myrset.add_document(*(++i));
478 // Set expand_k to 1.0 and min_wt to 0
479 enquire.set_expansion_scheme("trad", 1.0);
480 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 0, 0);
481 if (!startswith(get_dbtype(), "multi")) {
482 // For a single database, the weights should be the same with or
483 // without USE_EXACT_TERMFREQ.
484 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
485 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
486 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
487 } else {
488 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
489 // will result in different weights in some cases.
490 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
491 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
492 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
494 TEST_REL(eset.back().get_weight(),>=,0);
496 return true;
499 // tests that when specifying maxitems to get_eset, no more than
500 // that are returned.
501 DEFINE_TESTCASE(expandmaxitems1, backend) {
502 Xapian::Enquire enquire(get_database("apitest_simpledata"));
503 enquire.set_query(Xapian::Query("this"));
505 Xapian::MSet mymset = enquire.get_mset(0, 10);
506 tout << "mymset.size() = " << mymset.size() << endl;
507 TEST(mymset.size() >= 2);
509 Xapian::RSet myrset;
510 Xapian::MSetIterator i = mymset.begin();
511 myrset.add_document(*i);
512 myrset.add_document(*(++i));
514 Xapian::ESet myeset = enquire.get_eset(1, myrset);
515 TEST_EQUAL(myeset.size(), 1);
516 TEST_REL(myeset.get_ebound(), >=, myeset.size());
518 return true;
521 // tests that a pure boolean query has all weights set to 0
522 DEFINE_TESTCASE(boolquery1, backend) {
523 Xapian::Query myboolquery(query("this"));
525 // open the database (in this case a simple text file
526 // we prepared earlier)
527 Xapian::Enquire enquire(get_database("apitest_simpledata"));
528 enquire.set_query(myboolquery);
529 enquire.set_weighting_scheme(Xapian::BoolWeight());
531 // retrieve the top results
532 Xapian::MSet mymset = enquire.get_mset(0, 10);
534 TEST_NOT_EQUAL(mymset.size(), 0);
535 TEST_EQUAL(mymset.get_max_possible(), 0);
536 for (Xapian::MSetIterator i = mymset.begin(); i != mymset.end(); ++i) {
537 TEST_EQUAL(i.get_weight(), 0);
539 return true;
542 // tests that get_mset() specifying "this" works as expected
543 DEFINE_TESTCASE(msetfirst1, backend) {
544 Xapian::Enquire enquire(get_database("apitest_simpledata"));
545 enquire.set_query(query("this"));
546 Xapian::MSet mymset1 = enquire.get_mset(0, 6);
547 Xapian::MSet mymset2 = enquire.get_mset(3, 3);
548 TEST(mset_range_is_same(mymset1, 3, mymset2, 0, 3));
550 // Regression test - we weren't adjusting the index into items[] by
551 // firstitem in api/omenquire.cc.
552 TEST_EQUAL(mymset1[5].get_document().get_data(),
553 mymset2[2].get_document().get_data());
554 return true;
557 // tests the converting-to-percent functions
558 DEFINE_TESTCASE(topercent1, backend) {
559 Xapian::Enquire enquire(get_database("apitest_simpledata"));
560 enquire.set_query(query("this"));
561 Xapian::MSet mymset = enquire.get_mset(0, 20);
563 int last_pct = 100;
564 Xapian::MSetIterator i = mymset.begin();
565 for ( ; i != mymset.end(); ++i) {
566 int pct = mymset.convert_to_percent(i);
567 TEST_AND_EXPLAIN(pct == i.get_percent(),
568 "convert_to_%(msetitor) != convert_to_%(wt)");
569 TEST_AND_EXPLAIN(pct == mymset.convert_to_percent(i.get_weight()),
570 "convert_to_%(msetitor) != convert_to_%(wt)");
571 TEST_AND_EXPLAIN(pct >= 0 && pct <= 100,
572 "percentage out of range: " << pct);
573 TEST_AND_EXPLAIN(pct <= last_pct, "percentage increased down mset");
574 last_pct = pct;
576 return true;
579 // tests the percentage values returned
580 DEFINE_TESTCASE(topercent2, backend) {
581 BackendManagerLocal local_manager;
582 local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
583 Xapian::Enquire localenq(local_manager.get_database("apitest_simpledata"));
584 Xapian::Enquire enquire(get_database("apitest_simpledata"));
586 int pct;
588 // First, test a search in which the top document scores 100%.
589 enquire.set_query(query("this"));
590 localenq.set_query(query("this"));
591 Xapian::MSet mymset = enquire.get_mset(0, 20);
592 Xapian::MSet localmset = localenq.get_mset(0, 20);
594 Xapian::MSetIterator i = mymset.begin();
595 TEST(i != mymset.end());
596 pct = mymset.convert_to_percent(i);
597 TEST_EQUAL(pct, 100);
599 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
600 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
601 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
602 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
603 TEST_EQUAL(mymset.size(), localmset.size());
604 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
606 // A search in which the top document doesn't have 100%
607 Xapian::Query q = query(Xapian::Query::OP_OR,
608 "this", "line", "paragraph", "rubbish");
609 enquire.set_query(q);
610 localenq.set_query(q);
611 mymset = enquire.get_mset(0, 20);
612 localmset = localenq.get_mset(0, 20);
614 i = mymset.begin();
615 TEST(i != mymset.end());
616 pct = mymset.convert_to_percent(i);
617 TEST_REL(pct,>,60);
618 TEST_REL(pct,<,76);
620 ++i;
622 TEST(i != mymset.end());
623 pct = mymset.convert_to_percent(i);
624 TEST_REL(pct,>,40);
625 TEST_REL(pct,<,50);
627 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
628 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
629 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
630 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
631 TEST_EQUAL(mymset.size(), localmset.size());
632 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
634 return true;
637 class EvenParityExpandFunctor : public Xapian::ExpandDecider {
638 public:
639 bool operator()(const string & tname) const {
640 unsigned long sum = 0;
641 for (unsigned ch : tname) {
642 sum += ch;
644 // if (verbose) {
645 // tout << tname << "==> " << sum << "\n";
646 // }
647 return (sum % 2) == 0;
651 // tests the expand decision functor
652 DEFINE_TESTCASE(expandfunctor1, backend) {
653 Xapian::Enquire enquire(get_database("apitest_simpledata"));
654 enquire.set_query(Xapian::Query("this"));
656 Xapian::MSet mymset = enquire.get_mset(0, 10);
657 TEST(mymset.size() >= 2);
659 Xapian::RSet myrset;
660 Xapian::MSetIterator i = mymset.begin();
661 myrset.add_document(*i);
662 myrset.add_document(*(++i));
664 EvenParityExpandFunctor myfunctor;
666 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
667 unsigned int neweset_size = 0;
668 Xapian::ESetIterator j = myeset_orig.begin();
669 for ( ; j != myeset_orig.end(); ++j) {
670 if (myfunctor(*j)) neweset_size++;
672 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
674 #if 0
675 // Compare myeset with the hand-filtered version of myeset_orig.
676 if (verbose) {
677 tout << "orig_eset: ";
678 copy(myeset_orig.begin(), myeset_orig.end(),
679 ostream_iterator<Xapian::ESetItem>(tout, " "));
680 tout << "\n";
682 tout << "new_eset: ";
683 copy(myeset.begin(), myeset.end(),
684 ostream_iterator<Xapian::ESetItem>(tout, " "));
685 tout << "\n";
687 #endif
688 Xapian::ESetIterator orig = myeset_orig.begin();
689 Xapian::ESetIterator filt = myeset.begin();
690 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
691 // skip over items that shouldn't be in myeset
692 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
693 ++orig;
696 TEST_AND_EXPLAIN(*orig == *filt &&
697 orig.get_weight() == filt.get_weight(),
698 "Mismatch in items " << *orig << " vs. " << *filt
699 << " after filtering");
702 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
703 ++orig;
706 TEST_EQUAL(orig, myeset_orig.end());
707 TEST_AND_EXPLAIN(filt == myeset.end(),
708 "Extra items in the filtered eset.");
709 return true;
712 DEFINE_TESTCASE(expanddeciderfilterprefix2, backend) {
713 Xapian::Enquire enquire(get_database("apitest_simpledata"));
714 enquire.set_query(Xapian::Query("this"));
716 Xapian::MSet mymset = enquire.get_mset(0, 10);
717 TEST(mymset.size() >= 2);
719 Xapian::RSet myrset;
720 Xapian::MSetIterator i = mymset.begin();
721 myrset.add_document(*i);
722 myrset.add_document(*(++i));
724 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
725 unsigned int neweset_size = 0;
727 // Choose the first char in the first term as prefix.
728 Xapian::ESetIterator j = myeset_orig.begin();
729 TEST(myeset_orig.size() >= 1);
730 string prefix(*j, 0, 1);
731 Xapian::ExpandDeciderFilterPrefix myfunctor(prefix);
733 for ( ; j != myeset_orig.end(); ++j) {
734 if (myfunctor(*j)) neweset_size++;
736 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
738 Xapian::ESetIterator orig = myeset_orig.begin();
739 Xapian::ESetIterator filt = myeset.begin();
740 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
741 // skip over items that shouldn't be in myeset
742 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
743 ++orig;
746 TEST_AND_EXPLAIN(*orig == *filt &&
747 orig.get_weight() == filt.get_weight(),
748 "Mismatch in items " << *orig << " vs. " << *filt
749 << " after filtering");
752 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
753 ++orig;
756 TEST_EQUAL(orig, myeset_orig.end());
757 TEST_AND_EXPLAIN(filt == myeset.end(),
758 "Extra items in the filtered eset.");
760 return true;
763 // tests the percent cutoff option
764 DEFINE_TESTCASE(pctcutoff1, backend) {
765 Xapian::Enquire enquire(get_database("apitest_simpledata"));
766 enquire.set_query(query(Xapian::Query::OP_OR,
767 "this", "line", "paragraph", "rubbish"));
768 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
770 if (verbose) {
771 tout << "Original mset pcts:";
772 print_mset_percentages(mymset1);
773 tout << "\n";
776 unsigned int num_items = 0;
777 int my_pct = 100;
778 int changes = 0;
779 Xapian::MSetIterator i = mymset1.begin();
780 int c = 0;
781 for ( ; i != mymset1.end(); ++i, ++c) {
782 int new_pct = mymset1.convert_to_percent(i);
783 if (new_pct != my_pct) {
784 changes++;
785 if (changes > 3) break;
786 num_items = c;
787 my_pct = new_pct;
791 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
792 if (verbose) {
793 tout << "Cutoff percent: " << my_pct << "\n";
796 enquire.set_cutoff(my_pct);
797 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
799 if (verbose) {
800 tout << "Percentages after cutoff:";
801 print_mset_percentages(mymset2);
802 tout << "\n";
805 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
806 "Match with % cutoff lost too many items");
808 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
809 (mymset2.convert_to_percent(mymset2[num_items]) == my_pct &&
810 mymset2.convert_to_percent(mymset2.back()) == my_pct),
811 "Match with % cutoff returned too many items");
813 return true;
816 // Tests the percent cutoff option combined with collapsing
817 DEFINE_TESTCASE(pctcutoff2, backend) {
818 Xapian::Enquire enquire(get_database("apitest_simpledata"));
819 enquire.set_query(Xapian::Query("this"));
820 enquire.set_query(Xapian::Query(Xapian::Query::OP_AND_NOT, Xapian::Query("this"), Xapian::Query("banana")));
821 Xapian::MSet mset = enquire.get_mset(0, 100);
823 if (verbose) {
824 tout << "Original mset pcts:";
825 print_mset_percentages(mset);
826 tout << "\n";
829 TEST(mset.size() >= 2);
830 TEST(mset[0].get_percent() - mset[1].get_percent() >= 2);
832 int cutoff = mset[0].get_percent() + mset[1].get_percent();
833 cutoff /= 2;
835 enquire.set_cutoff(cutoff);
836 enquire.set_collapse_key(1234); // Value which is always empty.
838 Xapian::MSet mset2 = enquire.get_mset(0, 1);
839 TEST_EQUAL(mset2.size(), 1);
840 TEST_EQUAL(mset2.get_matches_lower_bound(), 1);
841 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),>=,1);
842 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset.size());
843 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset.size());
844 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
845 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset2.get_uncollapsed_matches_estimated());
847 return true;
850 // Test that the percent cutoff option returns all the answers it should.
851 DEFINE_TESTCASE(pctcutoff3, backend) {
852 Xapian::Enquire enquire(get_database("apitest_simpledata"));
853 enquire.set_query(Xapian::Query("this"));
854 Xapian::MSet mset1 = enquire.get_mset(0, 10);
856 if (verbose) {
857 tout << "Original mset pcts:";
858 print_mset_percentages(mset1);
859 tout << "\n";
862 int percent = 100;
863 for (Xapian::MSetIterator i = mset1.begin(); i != mset1.end(); ++i) {
864 int new_percent = mset1.convert_to_percent(i);
865 if (new_percent != percent) {
866 tout.str(string());
867 tout << "Testing " << percent << "% cutoff" << endl;
868 enquire.set_cutoff(percent);
869 Xapian::MSet mset2 = enquire.get_mset(0, 10);
870 TEST_EQUAL(mset2.back().get_percent(), percent);
871 TEST_EQUAL(mset2.size(), i.get_rank());
872 percent = new_percent;
876 return true;
879 // tests the cutoff option
880 DEFINE_TESTCASE(cutoff1, backend) {
881 Xapian::Enquire enquire(get_database("apitest_simpledata"));
882 enquire.set_query(query(Xapian::Query::OP_OR,
883 "this", "line", "paragraph", "rubbish"));
884 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
886 if (verbose) {
887 tout << "Original mset weights:";
888 print_mset_weights(mymset1);
889 tout << "\n";
892 unsigned int num_items = 0;
893 double my_wt = -100;
894 int changes = 0;
895 Xapian::MSetIterator i = mymset1.begin();
896 int c = 0;
897 for ( ; i != mymset1.end(); ++i, ++c) {
898 double new_wt = i.get_weight();
899 if (new_wt != my_wt) {
900 changes++;
901 if (changes > 3) break;
902 num_items = c;
903 my_wt = new_wt;
907 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
908 if (verbose) {
909 tout << "Cutoff weight: " << my_wt << "\n";
912 enquire.set_cutoff(0, my_wt);
913 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
915 if (verbose) {
916 tout << "Weights after cutoff:";
917 print_mset_weights(mymset2);
918 tout << "\n";
921 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
922 "Match with cutoff lost too many items");
924 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
925 (mymset2[num_items].get_weight() == my_wt &&
926 mymset2.back().get_weight() == my_wt),
927 "Match with cutoff returned too many items");
929 return true;
932 // tests the allow query terms expand option
933 DEFINE_TESTCASE(allowqterms1, backend) {
934 Xapian::Enquire enquire(get_database("apitest_simpledata"));
935 string term = "paragraph";
936 enquire.set_query(Xapian::Query(term));
938 Xapian::MSet mymset = enquire.get_mset(0, 10);
939 TEST(mymset.size() >= 2);
941 Xapian::RSet myrset;
942 Xapian::MSetIterator i = mymset.begin();
943 myrset.add_document(*i);
944 myrset.add_document(*(++i));
946 Xapian::ESet myeset = enquire.get_eset(1000, myrset);
947 Xapian::ESetIterator j = myeset.begin();
948 for ( ; j != myeset.end(); ++j) {
949 TEST_NOT_EQUAL(*j, term);
952 Xapian::ESet myeset2 = enquire.get_eset(1000, myrset, Xapian::Enquire::INCLUDE_QUERY_TERMS);
953 j = myeset2.begin();
954 for ( ; j != myeset2.end(); ++j) {
955 if (*j == term) break;
957 TEST(j != myeset2.end());
958 return true;
961 // tests that the MSet max_attained works
962 DEFINE_TESTCASE(maxattain1, backend) {
963 Xapian::Enquire enquire(get_database("apitest_simpledata"));
964 enquire.set_query(query("this"));
965 Xapian::MSet mymset = enquire.get_mset(0, 100);
967 double mymax = 0;
968 Xapian::MSetIterator i = mymset.begin();
969 for ( ; i != mymset.end(); ++i) {
970 if (i.get_weight() > mymax) mymax = i.get_weight();
972 TEST_EQUAL(mymax, mymset.get_max_attained());
974 return true;
977 // tests a reversed boolean query
978 DEFINE_TESTCASE(reversebool1, backend) {
979 Xapian::Enquire enquire(get_database("apitest_simpledata"));
980 enquire.set_query(Xapian::Query("this"));
981 enquire.set_weighting_scheme(Xapian::BoolWeight());
983 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
984 TEST_AND_EXPLAIN(mymset1.size() > 1,
985 "Mset was too small to test properly");
987 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
988 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
989 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
990 Xapian::MSet mymset3 = enquire.get_mset(0, 100);
992 // mymset1 and mymset2 should be identical
993 TEST_EQUAL(mymset1.size(), mymset2.size());
996 Xapian::MSetIterator i = mymset1.begin();
997 Xapian::MSetIterator j = mymset2.begin();
998 for ( ; i != mymset1.end(); ++i, j++) {
999 TEST(j != mymset2.end());
1000 // if this fails, then setting match_sort_forward=true was not
1001 // the same as the default.
1002 TEST_EQUAL(*i, *j);
1004 TEST(j == mymset2.end());
1007 // mymset1 and mymset3 should be same but reversed
1008 TEST_EQUAL(mymset1.size(), mymset3.size());
1011 Xapian::MSetIterator i = mymset1.begin();
1012 Xapian::MSetIterator j = mymset3.end();
1013 for ( ; i != mymset1.end(); ++i) {
1014 --j;
1015 // if this fails, then setting match_sort_forward=false didn't
1016 // reverse the results.
1017 TEST_EQUAL(*i, *j);
1021 return true;
1024 // tests a reversed boolean query, where the full mset isn't returned
1025 DEFINE_TESTCASE(reversebool2, backend) {
1026 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1027 enquire.set_query(Xapian::Query("this"));
1028 enquire.set_weighting_scheme(Xapian::BoolWeight());
1030 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
1032 TEST_AND_EXPLAIN(mymset1.size() > 1,
1033 "Mset was too small to test properly");
1035 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1036 Xapian::doccount msize = mymset1.size() / 2;
1037 Xapian::MSet mymset2 = enquire.get_mset(0, msize);
1038 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1039 Xapian::MSet mymset3 = enquire.get_mset(0, msize);
1041 // mymset2 should be first msize items of mymset1
1042 TEST_EQUAL(msize, mymset2.size());
1044 Xapian::MSetIterator i = mymset1.begin();
1045 Xapian::MSetIterator j = mymset2.begin();
1046 for ( ; j != mymset2.end(); ++i, ++j) {
1047 TEST(i != mymset1.end());
1048 // if this fails, then setting match_sort_forward=true was not
1049 // the same as the default.
1050 TEST_EQUAL(*i, *j);
1052 // mymset1 should be larger.
1053 TEST(i != mymset1.end());
1056 // mymset3 should be last msize items of mymset1, in reverse order
1057 TEST_EQUAL(msize, mymset3.size());
1059 Xapian::MSetIterator i = mymset1.end();
1060 Xapian::MSetIterator j;
1061 for (j = mymset3.begin(); j != mymset3.end(); ++j) {
1062 // if this fails, then setting match_sort_forward=false didn't
1063 // reverse the results.
1064 --i;
1065 TEST_EQUAL(*i, *j);
1069 return true;
1072 // tests that get_matching_terms() returns the terms in the right order
1073 DEFINE_TESTCASE(getmterms1, backend) {
1074 list<string> answers_list;
1075 answers_list.push_back("one");
1076 answers_list.push_back("two");
1077 answers_list.push_back("three");
1078 answers_list.push_back("four");
1080 Xapian::Database mydb(get_database("apitest_termorder"));
1081 Xapian::Enquire enquire(mydb);
1083 Xapian::Query myquery(Xapian::Query::OP_OR,
1084 Xapian::Query(Xapian::Query::OP_AND,
1085 Xapian::Query("one", 1, 1),
1086 Xapian::Query("three", 1, 3)),
1087 Xapian::Query(Xapian::Query::OP_OR,
1088 Xapian::Query("four", 1, 4),
1089 Xapian::Query("two", 1, 2)));
1091 enquire.set_query(myquery);
1093 Xapian::MSet mymset = enquire.get_mset(0, 10);
1095 TEST_MSET_SIZE(mymset, 1);
1096 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1097 enquire.get_matching_terms_end(mymset.begin()));
1098 TEST(list == answers_list);
1100 return true;
1103 // tests that get_matching_terms() returns the terms only once
1104 DEFINE_TESTCASE(getmterms2, backend) {
1105 list<string> answers_list;
1106 answers_list.push_back("one");
1107 answers_list.push_back("two");
1108 answers_list.push_back("three");
1110 Xapian::Database mydb(get_database("apitest_termorder"));
1111 Xapian::Enquire enquire(mydb);
1113 Xapian::Query myquery(Xapian::Query::OP_OR,
1114 Xapian::Query(Xapian::Query::OP_AND,
1115 Xapian::Query("one", 1, 1),
1116 Xapian::Query("three", 1, 3)),
1117 Xapian::Query(Xapian::Query::OP_OR,
1118 Xapian::Query("one", 1, 4),
1119 Xapian::Query("two", 1, 2)));
1121 enquire.set_query(myquery);
1123 Xapian::MSet mymset = enquire.get_mset(0, 10);
1125 TEST_MSET_SIZE(mymset, 1);
1126 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1127 enquire.get_matching_terms_end(mymset.begin()));
1128 TEST(list == answers_list);
1130 return true;
1133 // test that running a query twice returns the same results
1134 DEFINE_TESTCASE(repeatquery1, backend) {
1135 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1136 enquire.set_query(Xapian::Query("this"));
1138 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1140 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1141 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1142 TEST_EQUAL(mymset1, mymset2);
1144 return true;
1147 // test that prefetching documents works (at least, gives same results)
1148 DEFINE_TESTCASE(fetchdocs1, backend) {
1149 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1150 enquire.set_query(Xapian::Query("this"));
1152 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1154 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1155 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1156 TEST_EQUAL(mymset1, mymset2);
1157 mymset2.fetch(mymset2[0], mymset2[mymset2.size() - 1]);
1158 mymset2.fetch(mymset2.begin(), mymset2.end());
1159 mymset2.fetch(mymset2.begin());
1160 mymset2.fetch();
1162 Xapian::MSetIterator it1 = mymset1.begin();
1163 Xapian::MSetIterator it2 = mymset2.begin();
1165 while (it1 != mymset1.end() && it2 != mymset2.end()) {
1166 TEST_EQUAL(it1.get_document().get_data(),
1167 it2.get_document().get_data());
1168 TEST_NOT_EQUAL(it1.get_document().get_data(), "");
1169 TEST_NOT_EQUAL(it2.get_document().get_data(), "");
1170 it1++;
1171 it2++;
1173 TEST_EQUAL(it1, mymset1.end());
1174 TEST_EQUAL(it1, mymset2.end());
1176 return true;
1179 // test that searching for a term not in the database fails nicely
1180 DEFINE_TESTCASE(absentterm1, backend) {
1181 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1182 enquire.set_weighting_scheme(Xapian::BoolWeight());
1183 enquire.set_query(Xapian::Query("frink"));
1185 Xapian::MSet mymset = enquire.get_mset(0, 10);
1186 mset_expect_order(mymset);
1188 return true;
1191 // as absentterm1, but setting query from a vector of terms
1192 DEFINE_TESTCASE(absentterm2, backend) {
1193 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1194 vector<string> terms;
1195 terms.push_back("frink");
1197 Xapian::Query query(Xapian::Query::OP_OR, terms.begin(), terms.end());
1198 enquire.set_query(query);
1200 Xapian::MSet mymset = enquire.get_mset(0, 10);
1201 mset_expect_order(mymset);
1203 return true;
1206 // test that rsets do sensible things
1207 DEFINE_TESTCASE(rset1, backend) {
1208 Xapian::Database mydb(get_database("apitest_rset"));
1209 Xapian::Enquire enquire(mydb);
1210 Xapian::Query myquery = query(Xapian::Query::OP_OR, "giraffe", "tiger");
1211 enquire.set_query(myquery);
1213 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1215 Xapian::RSet myrset;
1216 myrset.add_document(1);
1218 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1220 // We should have the same documents turn up, but 1 and 3 should
1221 // have higher weights with the RSet.
1222 TEST_MSET_SIZE(mymset1, 3);
1223 TEST_MSET_SIZE(mymset2, 3);
1225 return true;
1228 // test that rsets do more sensible things
1229 DEFINE_TESTCASE(rset2, backend) {
1230 Xapian::Database mydb(get_database("apitest_rset"));
1231 Xapian::Enquire enquire(mydb);
1232 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
1233 enquire.set_query(myquery);
1235 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1237 Xapian::RSet myrset;
1238 myrset.add_document(2);
1240 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1242 mset_expect_order(mymset1, 1, 2);
1243 mset_expect_order(mymset2, 2, 1);
1245 return true;
1248 // test that rsets behave correctly with multiDBs
1249 DEFINE_TESTCASE(rsetmultidb1, backend && !multi) {
1250 Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1251 Xapian::Database mydb2(get_database("apitest_rset"));
1252 mydb2.add_database(get_database("apitest_simpledata2"));
1254 Xapian::Enquire enquire1(mydb1);
1255 Xapian::Enquire enquire2(mydb2);
1257 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "multiple");
1259 enquire1.set_query(myquery);
1260 enquire2.set_query(myquery);
1262 Xapian::RSet myrset1;
1263 Xapian::RSet myrset2;
1264 myrset1.add_document(4);
1265 myrset2.add_document(2);
1267 Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
1268 Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
1269 Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
1270 Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
1272 mset_expect_order(mymset1a, 1, 4);
1273 mset_expect_order(mymset1b, 4, 1);
1274 mset_expect_order(mymset2a, 1, 2);
1275 mset_expect_order(mymset2b, 2, 1);
1277 TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
1278 TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
1279 TEST_NOT_EQUAL(mymset1a, mymset1b);
1280 TEST_NOT_EQUAL(mymset2a, mymset2b);
1282 return true;
1285 // regression tests - used to cause assertion in stats.h to fail
1286 // Doesn't actually fail for multi but it doesn't make sense to run there.
1287 DEFINE_TESTCASE(rsetmultidb3, backend && !multi) {
1288 Xapian::Enquire enquire(get_database("apitest_simpledata2"));
1289 enquire.set_query(query(Xapian::Query::OP_OR, "cuddly", "people"));
1290 Xapian::MSet mset = enquire.get_mset(0, 10); // used to fail assertion
1291 return true;
1294 /// Simple test of the elite set operator.
1295 DEFINE_TESTCASE(eliteset1, backend) {
1296 Xapian::Database mydb(get_database("apitest_simpledata"));
1297 Xapian::Enquire enquire(mydb);
1299 Xapian::Query myquery1 = query(Xapian::Query::OP_OR, "word");
1301 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1302 "simple", "word");
1304 enquire.set_query(myquery1, 2); // So the query lengths are the same.
1305 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1307 enquire.set_query(myquery2);
1308 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1310 TEST_EQUAL(mymset1, mymset2);
1311 return true;
1314 /// Test that the elite set operator works if the set contains
1315 /// sub-expressions (regression test)
1316 DEFINE_TESTCASE(eliteset2, backend) {
1317 Xapian::Database mydb(get_database("apitest_simpledata"));
1318 Xapian::Enquire enquire(mydb);
1320 Xapian::Query myquery1 = query(Xapian::Query::OP_AND, "word", "search");
1322 vector<Xapian::Query> qs;
1323 qs.push_back(query("this"));
1324 qs.push_back(query(Xapian::Query::OP_AND, "word", "search"));
1325 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET,
1326 qs.begin(), qs.end(), 1);
1328 enquire.set_query(myquery1);
1329 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1331 enquire.set_query(myquery2);
1332 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1334 TEST_EQUAL(mymset1, mymset2);
1335 // query lengths differ so mset weights not the same (with some weighting
1336 // parameters)
1337 // test_mset_order_equal(mymset1, mymset2);
1339 return true;
1342 /// Test that elite set doesn't affect query results if we have fewer
1343 /// terms than the threshold
1344 DEFINE_TESTCASE(eliteset3, backend) {
1345 Xapian::Database mydb1(get_database("apitest_simpledata"));
1346 Xapian::Enquire enquire1(mydb1);
1348 Xapian::Database mydb2(get_database("apitest_simpledata"));
1349 Xapian::Enquire enquire2(mydb2);
1351 // make a query
1352 Xapian::Stem stemmer("english");
1354 string term1 = stemmer("word");
1355 string term2 = stemmer("rubbish");
1356 string term3 = stemmer("banana");
1358 vector<string> terms;
1359 terms.push_back(term1);
1360 terms.push_back(term2);
1361 terms.push_back(term3);
1363 Xapian::Query myquery1(Xapian::Query::OP_OR, terms.begin(), terms.end());
1364 enquire1.set_query(myquery1);
1366 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET, terms.begin(), terms.end(), 3);
1367 enquire2.set_query(myquery2);
1369 // retrieve the results
1370 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1371 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1373 TEST_EQUAL(mymset1.get_termfreq(term1),
1374 mymset2.get_termfreq(term1));
1375 TEST_EQUAL(mymset1.get_termweight(term1),
1376 mymset2.get_termweight(term1));
1377 TEST_EQUAL(mymset1.get_termfreq(term2),
1378 mymset2.get_termfreq(term2));
1379 TEST_EQUAL(mymset1.get_termweight(term2),
1380 mymset2.get_termweight(term2));
1381 TEST_EQUAL(mymset1.get_termfreq(term3),
1382 mymset2.get_termfreq(term3));
1383 TEST_EQUAL(mymset1.get_termweight(term3),
1384 mymset2.get_termweight(term3));
1385 // TEST_EQUAL(mymset1, mymset2);
1387 return true;
1390 /// Test that elite set doesn't pick terms with 0 frequency
1391 DEFINE_TESTCASE(eliteset4, backend) {
1392 Xapian::Database mydb1(get_database("apitest_simpledata"));
1393 Xapian::Enquire enquire1(mydb1);
1395 Xapian::Database mydb2(get_database("apitest_simpledata"));
1396 Xapian::Enquire enquire2(mydb2);
1398 Xapian::Query myquery1 = query("rubbish");
1399 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1400 "word", "rubbish", "fibble");
1401 enquire1.set_query(myquery1);
1402 enquire2.set_query(myquery2);
1404 // retrieve the results
1405 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1406 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1408 TEST_NOT_EQUAL(mymset2.size(), 0);
1409 TEST_EQUAL(mymset1, mymset2);
1410 // TEST_EQUAL(mymset1, mymset2);
1412 return true;
1415 /// Regression test for problem with excess precision.
1416 DEFINE_TESTCASE(eliteset5, backend) {
1417 Xapian::Database mydb1(get_database("apitest_simpledata"));
1418 Xapian::Enquire enquire1(mydb1);
1420 vector<string> v;
1421 for (int i = 0; i != 3; ++i) {
1422 v.push_back("simpl");
1423 v.push_back("queri");
1425 v.push_back("rubbish");
1426 v.push_back("rubbish");
1427 v.push_back("rubbish");
1428 v.push_back("word");
1429 v.push_back("word");
1430 v.push_back("word");
1433 for (Xapian::termcount n = 1; n != v.size(); ++n) {
1434 Xapian::Query myquery1 = Xapian::Query(Xapian::Query::OP_ELITE_SET,
1435 v.begin(), v.end(), n);
1436 myquery1 = Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
1437 myquery1,
1438 0.004);
1440 enquire1.set_query(myquery1);
1441 // On architectures with excess precision (or, at least, on x86), the
1442 // following call used to result in a segfault (at least when n=1).
1443 enquire1.get_mset(0, 10);
1446 return true;
1449 /// Test that the termfreq returned by termlists is correct.
1450 DEFINE_TESTCASE(termlisttermfreq1, backend) {
1451 Xapian::Database mydb(get_database("apitest_simpledata"));
1452 Xapian::Enquire enquire(mydb);
1453 Xapian::Stem stemmer("english");
1454 Xapian::RSet rset1;
1455 Xapian::RSet rset2;
1456 rset1.add_document(5);
1457 rset2.add_document(6);
1459 Xapian::ESet eset1 = enquire.get_eset(1000, rset1);
1460 Xapian::ESet eset2 = enquire.get_eset(1000, rset2);
1462 // search for weight of term 'another'
1463 string theterm = stemmer("another");
1465 double wt1 = 0;
1466 double wt2 = 0;
1468 Xapian::ESetIterator i = eset1.begin();
1469 for ( ; i != eset1.end(); ++i) {
1470 if (*i == theterm) {
1471 wt1 = i.get_weight();
1472 break;
1477 Xapian::ESetIterator i = eset2.begin();
1478 for ( ; i != eset2.end(); ++i) {
1479 if (*i == theterm) {
1480 wt2 = i.get_weight();
1481 break;
1486 TEST_NOT_EQUAL(wt1, 0);
1487 TEST_NOT_EQUAL(wt2, 0);
1488 TEST_EQUAL(wt1, wt2);
1490 return true;
1493 /// Test the termfrequency and termweight info returned for query terms
1494 DEFINE_TESTCASE(qterminfo1, backend) {
1495 Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1496 Xapian::Enquire enquire1(mydb1);
1498 Xapian::Database mydb2(get_database("apitest_simpledata"));
1499 mydb2.add_database(get_database("apitest_simpledata2"));
1500 Xapian::Enquire enquire2(mydb2);
1502 // make a query
1503 Xapian::Stem stemmer("english");
1505 string term1 = stemmer("word");
1506 string term2 = stemmer("inmemory");
1507 string term3 = stemmer("flibble");
1509 Xapian::Query myquery(Xapian::Query::OP_OR,
1510 Xapian::Query(term1),
1511 Xapian::Query(Xapian::Query::OP_OR,
1512 Xapian::Query(term2),
1513 Xapian::Query(term3)));
1514 myquery = myquery &~ Xapian::Query("Boolean");
1515 enquire1.set_query(myquery);
1516 enquire2.set_query(myquery);
1518 // retrieve the results
1519 Xapian::MSet mymset1a = enquire1.get_mset(0, 0);
1520 Xapian::MSet mymset2a = enquire2.get_mset(0, 0);
1522 TEST_EQUAL(mymset1a.get_termfreq(term1),
1523 mymset2a.get_termfreq(term1));
1524 TEST_EQUAL(mymset1a.get_termfreq(term2),
1525 mymset2a.get_termfreq(term2));
1526 TEST_EQUAL(mymset1a.get_termfreq(term3),
1527 mymset2a.get_termfreq(term3));
1529 TEST_EQUAL(mymset1a.get_termfreq(term1), 3);
1530 TEST_EQUAL(mymset1a.get_termfreq(term2), 1);
1531 TEST_EQUAL(mymset1a.get_termfreq(term3), 0);
1533 TEST_NOT_EQUAL(mymset1a.get_termweight(term1), 0);
1534 TEST_NOT_EQUAL(mymset1a.get_termweight(term2), 0);
1535 // non-existent terms should have 0 weight.
1536 TEST_EQUAL(mymset1a.get_termweight(term3), 0);
1538 TEST_EQUAL(mymset1a.get_termfreq(stemmer("banana")), 1);
1539 TEST_EQUAL(mymset1a.get_termweight(stemmer("banana")), 0.0);
1541 TEST_EQUAL(mymset1a.get_termfreq("sponge"), 0);
1542 TEST_EQUAL(mymset1a.get_termweight(stemmer("sponge")), 0.0);
1544 TEST_EQUAL(mymset1a.get_termfreq("Boolean"), 0);
1545 TEST_EQUAL(mymset1a.get_termweight("Boolean"), 0.0);
1547 return true;
1550 /// Regression test for bug #37.
1551 DEFINE_TESTCASE(qterminfo2, backend) {
1552 Xapian::Database db(get_database("apitest_simpledata"));
1553 Xapian::Enquire enquire(db);
1555 // make a query
1556 Xapian::Stem stemmer("english");
1558 string term1 = stemmer("paragraph");
1559 string term2 = stemmer("another");
1561 enquire.set_query(Xapian::Query(term1));
1562 Xapian::MSet mset0 = enquire.get_mset(0, 10);
1564 TEST_NOT_EQUAL(mset0.get_termweight("paragraph"), 0);
1566 Xapian::Query query(Xapian::Query::OP_AND_NOT, term1,
1567 Xapian::Query(Xapian::Query::OP_AND, term1, term2));
1568 enquire.set_query(query);
1570 // retrieve the results
1571 // Note: get_mset() used to throw "AssertionError" in debug builds
1572 Xapian::MSet mset = enquire.get_mset(0, 10);
1574 TEST_NOT_EQUAL(mset.get_termweight("paragraph"), 0);
1576 return true;
1579 // tests that when specifying that no items are to be returned, those
1580 // statistics which should be the same are.
1581 DEFINE_TESTCASE(msetzeroitems1, backend) {
1582 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1583 enquire.set_query(query("this"));
1584 Xapian::MSet mymset1 = enquire.get_mset(0, 0);
1586 Xapian::MSet mymset2 = enquire.get_mset(0, 1);
1588 TEST_EQUAL(mymset1.get_max_possible(), mymset2.get_max_possible());
1590 return true;
1593 // test that the matches_* of a simple query are as expected
1594 DEFINE_TESTCASE(matches1, backend) {
1595 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1596 Xapian::Query myquery;
1597 Xapian::MSet mymset;
1599 myquery = query("word");
1600 enquire.set_query(myquery);
1601 mymset = enquire.get_mset(0, 10);
1602 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1603 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1604 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1605 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1606 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1607 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1609 myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
1610 enquire.set_query(myquery);
1611 mymset = enquire.get_mset(0, 10);
1612 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1613 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1614 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1615 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1616 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1617 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1619 myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
1620 enquire.set_query(myquery);
1621 mymset = enquire.get_mset(0, 10);
1622 TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1623 TEST_EQUAL(mymset.get_matches_estimated(), 0);
1624 TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
1625 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
1626 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
1627 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
1629 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1630 enquire.set_query(myquery);
1631 mymset = enquire.get_mset(0, 10);
1632 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1633 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1634 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1635 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1636 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1637 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1639 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1640 enquire.set_query(myquery);
1641 mymset = enquire.get_mset(0, 0);
1642 // For a single database, this is true, but not for "multi" (since there
1643 // one sub-database has 3 documents and simple and word both have termfreq
1644 // of 2, so the matcher can tell at least one document must match!)
1645 // TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1646 TEST_REL(mymset.get_matches_lower_bound(),<=,mymset.get_matches_estimated());
1647 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1648 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1649 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,mymset.get_uncollapsed_matches_estimated());
1650 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1651 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1653 mymset = enquire.get_mset(0, 1);
1654 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1655 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1656 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1657 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1658 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1659 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1661 mymset = enquire.get_mset(0, 2);
1662 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1663 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1664 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1665 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1666 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1667 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1669 myquery = query(Xapian::Query::OP_AND, "paragraph", "another");
1670 enquire.set_query(myquery);
1671 mymset = enquire.get_mset(0, 0);
1672 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1673 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1674 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1675 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1676 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1677 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1679 mymset = enquire.get_mset(0, 1);
1680 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1681 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1682 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1683 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1684 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1685 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1687 mymset = enquire.get_mset(0, 2);
1688 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1689 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1690 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1691 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1692 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1693 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1695 mymset = enquire.get_mset(1, 20);
1696 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1697 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1698 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1699 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1700 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1701 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1703 return true;
1706 // tests that wqf affects the document weights
1707 DEFINE_TESTCASE(wqf1, backend) {
1708 // Both queries have length 2; in q1 word has wqf=2, in q2 word has wqf=1
1709 Xapian::Query q1("word", 2);
1710 Xapian::Query q2("word");
1711 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1712 enquire.set_query(q1);
1713 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1714 enquire.set_query(q2);
1715 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1716 // Check the weights
1717 TEST(mset1.begin().get_weight() > mset2.begin().get_weight());
1718 return true;
1721 // tests that query length affects the document weights
1722 DEFINE_TESTCASE(qlen1, backend) {
1723 Xapian::Query q1("word");
1724 Xapian::Query q2("word");
1725 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1726 enquire.set_query(q1);
1727 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1728 enquire.set_query(q2);
1729 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1730 // Check the weights
1731 // TEST(mset1.begin().get_weight() < mset2.begin().get_weight());
1732 TEST(mset1.begin().get_weight() == mset2.begin().get_weight());
1733 return true;
1736 // tests that opening a non-existent termlist throws the correct exception
1737 DEFINE_TESTCASE(termlist1, backend) {
1738 Xapian::Database db(get_database("apitest_onedoc"));
1739 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1740 Xapian::TermIterator t = db.termlist_begin(0));
1741 TEST_EXCEPTION(Xapian::DocNotFoundError,
1742 Xapian::TermIterator t = db.termlist_begin(2));
1743 /* Cause the database to be used properly, showing up problems
1744 * with the link being in a bad state. CME */
1745 Xapian::TermIterator temp = db.termlist_begin(1);
1746 TEST_EXCEPTION(Xapian::DocNotFoundError,
1747 Xapian::TermIterator t = db.termlist_begin(999999999));
1748 return true;
1751 // tests that a Xapian::TermIterator works as an STL iterator
1752 DEFINE_TESTCASE(termlist2, backend) {
1753 Xapian::Database db(get_database("apitest_onedoc"));
1754 Xapian::TermIterator t = db.termlist_begin(1);
1755 Xapian::TermIterator tend = db.termlist_end(1);
1757 // test operator= creates a copy which compares equal
1758 Xapian::TermIterator t_copy = t;
1759 TEST_EQUAL(t, t_copy);
1761 // test copy constructor creates a copy which compares equal
1762 Xapian::TermIterator t_clone(t);
1763 TEST_EQUAL(t, t_clone);
1765 vector<string> v(t, tend);
1767 t = db.termlist_begin(1);
1768 tend = db.termlist_end(1);
1769 vector<string>::const_iterator i;
1770 for (i = v.begin(); i != v.end(); ++i) {
1771 TEST_NOT_EQUAL(t, tend);
1772 TEST_EQUAL(*i, *t);
1773 t++;
1775 TEST_EQUAL(t, tend);
1776 return true;
1779 static Xapian::TermIterator
1780 test_termlist3_helper()
1782 Xapian::Database db(get_database("apitest_onedoc"));
1783 return db.termlist_begin(1);
1786 // tests that a Xapian::TermIterator still works when the DB is deleted
1787 DEFINE_TESTCASE(termlist3, backend) {
1788 Xapian::TermIterator u = test_termlist3_helper();
1789 Xapian::Database db(get_database("apitest_onedoc"));
1790 Xapian::TermIterator t = db.termlist_begin(1);
1791 Xapian::TermIterator tend = db.termlist_end(1);
1793 while (t != tend) {
1794 TEST_EQUAL(*t, *u);
1795 t++;
1796 u++;
1798 return true;
1801 // tests skip_to
1802 DEFINE_TESTCASE(termlist4, backend) {
1803 Xapian::Database db(get_database("apitest_onedoc"));
1804 Xapian::TermIterator i = db.termlist_begin(1);
1805 i.skip_to("");
1806 i.skip_to("\xff");
1807 return true;
1810 // tests punctuation is OK in terms (particularly in remote queries)
1811 DEFINE_TESTCASE(puncterms1, backend) {
1812 Xapian::Database db(get_database("apitest_punc"));
1813 Xapian::Enquire enquire(db);
1815 Xapian::Query q1("semi;colon");
1816 enquire.set_query(q1);
1817 Xapian::MSet m1 = enquire.get_mset(0, 10);
1819 Xapian::Query q2("col:on");
1820 enquire.set_query(q2);
1821 Xapian::MSet m2 = enquire.get_mset(0, 10);
1823 Xapian::Query q3("com,ma");
1824 enquire.set_query(q3);
1825 Xapian::MSet m3 = enquire.get_mset(0, 10);
1827 return true;
1830 // test that searching for a term with a space or backslash in it works
1831 DEFINE_TESTCASE(spaceterms1, backend) {
1832 Xapian::Enquire enquire(get_database("apitest_space"));
1833 Xapian::MSet mymset;
1834 Xapian::doccount count;
1835 Xapian::MSetIterator m;
1836 Xapian::Stem stemmer("english");
1838 enquire.set_query(stemmer("space man"));
1839 mymset = enquire.get_mset(0, 10);
1840 TEST_MSET_SIZE(mymset, 1);
1841 count = 0;
1842 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1843 TEST_EQUAL(count, 1);
1845 for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
1846 TEST_NOT_EQUAL(mymset.begin().get_document().get_data(), "");
1847 TEST_NOT_EQUAL(mymset.begin().get_document().get_value(value_no), "");
1850 enquire.set_query(stemmer("tab\tby"));
1851 mymset = enquire.get_mset(0, 10);
1852 TEST_MSET_SIZE(mymset, 1);
1853 count = 0;
1854 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1855 TEST_EQUAL(count, 1);
1857 for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
1858 string value = mymset.begin().get_document().get_value(value_no);
1859 TEST_NOT_EQUAL(value, "");
1860 if (value_no == 0) {
1861 TEST(value.size() > 262);
1862 TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
1866 enquire.set_query(stemmer("back\\slash"));
1867 mymset = enquire.get_mset(0, 10);
1868 TEST_MSET_SIZE(mymset, 1);
1869 count = 0;
1870 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1871 TEST_EQUAL(count, 1);
1873 return true;
1876 // test that XOR queries work
1877 DEFINE_TESTCASE(xor1, backend) {
1878 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1879 Xapian::Stem stemmer("english");
1881 vector<string> terms;
1882 terms.push_back(stemmer("this"));
1883 terms.push_back(stemmer("word"));
1884 terms.push_back(stemmer("of"));
1886 Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1887 enquire.set_weighting_scheme(Xapian::BoolWeight());
1888 enquire.set_query(query);
1890 Xapian::MSet mymset = enquire.get_mset(0, 10);
1891 // Docid this word of Match?
1892 // 1 * *
1893 // 2 * * * *
1894 // 3 * *
1895 // 4 * *
1896 // 5 * *
1897 // 6 * *
1898 mset_expect_order(mymset, 1, 2, 5, 6);
1900 return true;
1903 /// Test that weighted XOR queries work (bug fixed in 1.2.1 and 1.0.21).
1904 DEFINE_TESTCASE(xor2, backend) {
1905 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1906 Xapian::Stem stemmer("english");
1908 vector<string> terms;
1909 terms.push_back(stemmer("this"));
1910 terms.push_back(stemmer("word"));
1911 terms.push_back(stemmer("of"));
1913 Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1914 enquire.set_query(query);
1916 Xapian::MSet mymset = enquire.get_mset(0, 10);
1917 // Docid LEN this word of Match?
1918 // 1 28 2 *
1919 // 2 81 5 8 1 *
1920 // 3 15 1 2
1921 // 4 31 1 1
1922 // 5 15 1 *
1923 // 6 15 1 *
1924 mset_expect_order(mymset, 2, 1, 5, 6);
1926 return true;
1929 // test Xapian::Database::get_document()
1930 DEFINE_TESTCASE(getdoc1, backend) {
1931 Xapian::Database db(get_database("apitest_onedoc"));
1932 Xapian::Document doc(db.get_document(1));
1933 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_document(0));
1934 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(999999999));
1935 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(123456789));
1936 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
1937 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
1938 // Check that Document works as a handle on modification
1939 // (this was broken for the first try at Xapian::Document prior to 0.7).
1940 Xapian::Document doc2 = doc;
1941 doc.set_data("modified!");
1942 TEST_EQUAL(doc.get_data(), "modified!");
1943 TEST_EQUAL(doc.get_data(), doc2.get_data());
1944 return true;
1947 // test whether operators with no elements work as a null query
1948 DEFINE_TESTCASE(emptyop1, backend) {
1949 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1950 vector<Xapian::Query> nullvec;
1952 Xapian::Query query1(Xapian::Query::OP_XOR, nullvec.begin(), nullvec.end());
1954 enquire.set_query(query1);
1955 Xapian::MSet mymset = enquire.get_mset(0, 10);
1956 TEST_MSET_SIZE(mymset, 0);
1957 // In Xapian < 1.3.0, this gave InvalidArgumentError (because
1958 // query1.empty()) but elsewhere we treat an empty query as just not
1959 // matching any documents, so we now do the same here too.
1960 TEST_EQUAL(enquire.get_matching_terms_begin(1),
1961 enquire.get_matching_terms_end(1));
1963 return true;
1966 // Regression test for check_at_least SEGV when there are no matches.
1967 DEFINE_TESTCASE(checkatleast1, backend) {
1968 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1969 enquire.set_query(Xapian::Query("thom"));
1970 Xapian::MSet mymset = enquire.get_mset(0, 10, 11);
1971 TEST_EQUAL(0, mymset.size());
1973 return true;
1976 // Regression test - if check_at_least was set we returned (check_at_least - 1)
1977 // results, rather than the requested msize. Fixed in 1.0.2.
1978 DEFINE_TESTCASE(checkatleast2, backend) {
1979 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1980 enquire.set_query(Xapian::Query("paragraph"));
1982 Xapian::MSet mymset = enquire.get_mset(0, 3, 10);
1983 TEST_MSET_SIZE(mymset, 3);
1984 TEST_EQUAL(mymset.get_matches_lower_bound(), 5);
1985 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 5);
1987 mymset = enquire.get_mset(0, 2, 4);
1988 TEST_MSET_SIZE(mymset, 2);
1989 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1990 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1991 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1992 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1994 return true;
1997 // Feature tests - check_at_least with various sorting options.
1998 DEFINE_TESTCASE(checkatleast3, backend) {
1999 Xapian::Enquire enquire(get_database("etext"));
2000 enquire.set_query(Xapian::Query("prussian")); // 60 matches.
2002 for (int order = 0; order < 3; ++order) {
2003 switch (order) {
2004 case 0:
2005 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
2006 break;
2007 case 1:
2008 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
2009 break;
2010 case 2:
2011 enquire.set_docid_order(Xapian::Enquire::DONT_CARE);
2012 break;
2015 for (int sort = 0; sort < 7; ++sort) {
2016 bool reverse = (sort & 1);
2017 switch (sort) {
2018 case 0:
2019 enquire.set_sort_by_relevance();
2020 break;
2021 case 1: case 2:
2022 enquire.set_sort_by_value(0, reverse);
2023 break;
2024 case 3: case 4:
2025 enquire.set_sort_by_value_then_relevance(0, reverse);
2026 break;
2027 case 5: case 6:
2028 enquire.set_sort_by_relevance_then_value(0, reverse);
2029 break;
2032 Xapian::MSet mset = enquire.get_mset(0, 100, 500);
2033 TEST_MSET_SIZE(mset, 60);
2034 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2035 TEST_EQUAL(mset.get_matches_estimated(), 60);
2036 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2037 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2038 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2039 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2041 mset = enquire.get_mset(0, 50, 100);
2042 TEST_MSET_SIZE(mset, 50);
2043 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2044 TEST_EQUAL(mset.get_matches_estimated(), 60);
2045 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2046 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2047 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2048 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2050 mset = enquire.get_mset(0, 10, 50);
2051 TEST_MSET_SIZE(mset, 10);
2052 TEST_REL(mset.get_matches_lower_bound(),>=,50);
2053 TEST_REL(mset.get_uncollapsed_matches_lower_bound(),>=,50);
2057 return true;
2060 // tests all document postlists
2061 DEFINE_TESTCASE(allpostlist1, backend) {
2062 Xapian::Database db(get_database("apitest_manydocs"));
2063 Xapian::PostingIterator i = db.postlist_begin("");
2064 unsigned int j = 1;
2065 while (i != db.postlist_end("")) {
2066 TEST_EQUAL(*i, j);
2067 i++;
2068 j++;
2070 TEST_EQUAL(j, 513);
2072 i = db.postlist_begin("");
2073 j = 1;
2074 while (i != db.postlist_end("")) {
2075 TEST_EQUAL(*i, j);
2076 i++;
2077 j++;
2078 if (j == 50) {
2079 j += 10;
2080 i.skip_to(j);
2083 TEST_EQUAL(j, 513);
2085 return true;
2088 static void test_emptyterm1_helper(Xapian::Database & db)
2090 // Don't bother with postlist_begin() because allpostlist tests cover that.
2091 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
2092 TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
2093 TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
2094 TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
2097 // tests results of passing an empty term to various methods
2098 DEFINE_TESTCASE(emptyterm1, backend) {
2099 Xapian::Database db(get_database("apitest_manydocs"));
2100 TEST_EQUAL(db.get_doccount(), 512);
2101 test_emptyterm1_helper(db);
2103 db = get_database("apitest_onedoc");
2104 TEST_EQUAL(db.get_doccount(), 1);
2105 test_emptyterm1_helper(db);
2107 db = get_database("");
2108 TEST_EQUAL(db.get_doccount(), 0);
2109 test_emptyterm1_helper(db);
2111 return true;
2114 // Test for alldocs postlist with a sparse database.
2115 DEFINE_TESTCASE(alldocspl1, writable) {
2116 Xapian::WritableDatabase db = get_writable_database();
2117 Xapian::Document doc;
2118 doc.set_data("5");
2119 doc.add_value(0, "5");
2120 db.replace_document(5, doc);
2122 Xapian::PostingIterator i = db.postlist_begin("");
2123 TEST(i != db.postlist_end(""));
2124 TEST_EQUAL(*i, 5);
2125 TEST_EQUAL(i.get_doclength(), 0);
2126 TEST_EQUAL(i.get_unique_terms(), 0);
2127 TEST_EQUAL(i.get_wdf(), 1);
2128 ++i;
2129 TEST(i == db.postlist_end(""));
2131 return true;
2134 // Test reading and writing a modified alldocspostlist.
2135 DEFINE_TESTCASE(alldocspl2, writable) {
2136 Xapian::PostingIterator i, end;
2138 Xapian::WritableDatabase db = get_writable_database();
2139 Xapian::Document doc;
2140 doc.set_data("5");
2141 doc.add_value(0, "5");
2142 db.replace_document(5, doc);
2144 // Test iterating before committing the changes.
2145 i = db.postlist_begin("");
2146 end = db.postlist_end("");
2147 TEST(i != end);
2148 TEST_EQUAL(*i, 5);
2149 TEST_EQUAL(i.get_doclength(), 0);
2150 TEST_EQUAL(i.get_unique_terms(), 0);
2151 TEST_EQUAL(i.get_wdf(), 1);
2152 ++i;
2153 TEST(i == end);
2155 db.commit();
2157 // Test iterating after committing the changes.
2158 i = db.postlist_begin("");
2159 end = db.postlist_end("");
2160 TEST(i != end);
2161 TEST_EQUAL(*i, 5);
2162 TEST_EQUAL(i.get_doclength(), 0);
2163 TEST_EQUAL(i.get_unique_terms(), 0);
2164 TEST_EQUAL(i.get_wdf(), 1);
2165 ++i;
2166 TEST(i == end);
2168 // Add another document.
2169 doc = Xapian::Document();
2170 doc.set_data("5");
2171 doc.add_value(0, "7");
2172 db.replace_document(7, doc);
2174 // Test iterating through before committing the changes.
2175 i = db.postlist_begin("");
2176 end = db.postlist_end("");
2177 TEST(i != end);
2178 TEST_EQUAL(*i, 5);
2179 TEST_EQUAL(i.get_doclength(), 0);
2180 TEST_EQUAL(i.get_unique_terms(), 0);
2181 TEST_EQUAL(i.get_wdf(), 1);
2182 ++i;
2183 TEST(i != end);
2184 TEST_EQUAL(*i, 7);
2185 TEST_EQUAL(i.get_doclength(), 0);
2186 TEST_EQUAL(i.get_unique_terms(), 0);
2187 TEST_EQUAL(i.get_wdf(), 1);
2188 ++i;
2189 TEST(i == end);
2191 // Delete the first document.
2192 db.delete_document(5);
2194 // Test iterating through before committing the changes.
2195 i = db.postlist_begin("");
2196 end = db.postlist_end("");
2197 TEST(i != end);
2198 TEST_EQUAL(*i, 7);
2199 TEST_EQUAL(i.get_doclength(), 0);
2200 TEST_EQUAL(i.get_unique_terms(), 0);
2201 TEST_EQUAL(i.get_wdf(), 1);
2202 ++i;
2203 TEST(i == end);
2205 // Test iterating through after committing the changes, and dropping the
2206 // reference to the main DB.
2207 db.commit();
2208 i = db.postlist_begin("");
2209 end = db.postlist_end("");
2212 TEST(i != end);
2213 TEST_EQUAL(*i, 7);
2214 TEST_EQUAL(i.get_doclength(), 0);
2215 TEST_EQUAL(i.get_unique_terms(), 0);
2216 TEST_EQUAL(i.get_wdf(), 1);
2217 ++i;
2218 TEST(i == end);
2220 return true;
2223 // Feature test for Query::OP_SCALE_WEIGHT.
2224 DEFINE_TESTCASE(scaleweight1, backend) {
2225 Xapian::Database db(get_database("apitest_phrase"));
2226 Xapian::Enquire enq(db);
2227 Xapian::QueryParser qp;
2229 static const char * const queries[] = {
2230 "pad",
2231 "milk fridge",
2232 "leave milk on fridge",
2233 "ordered milk operator",
2234 "ordered phrase operator",
2235 "leave \"milk on fridge\"",
2236 "notpresent",
2237 "leave \"milk notpresent\"",
2239 static const double multipliers[] = {
2240 -1000000, -2.5, -1, -0.5, 0, 0.5, 1, 2.5, 1000000,
2241 0, 0
2244 for (auto qstr : queries) {
2245 tout.str(string());
2246 Xapian::Query query1 = qp.parse_query(qstr);
2247 tout << "query1: " << query1.get_description() << endl;
2248 for (const double *multp = multipliers; multp[0] != multp[1]; ++multp) {
2249 double mult = *multp;
2250 if (mult < 0) {
2251 TEST_EXCEPTION(Xapian::InvalidArgumentError,
2252 Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
2253 query1, mult));
2254 continue;
2256 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, mult);
2257 tout << "query2: " << query2.get_description() << endl;
2259 enq.set_query(query1);
2260 Xapian::MSet mset1 = enq.get_mset(0, 20);
2261 enq.set_query(query2);
2262 Xapian::MSet mset2 = enq.get_mset(0, 20);
2264 TEST_EQUAL(mset1.size(), mset2.size());
2266 Xapian::MSetIterator i1, i2;
2267 if (mult > 0) {
2268 for (i1 = mset1.begin(), i2 = mset2.begin();
2269 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2270 TEST_EQUAL_DOUBLE(i1.get_weight() * mult, i2.get_weight());
2271 TEST_EQUAL(*i1, *i2);
2273 } else {
2274 // Weights in mset2 are 0; so it should be sorted by docid.
2275 vector<Xapian::docid> ids1;
2276 vector<Xapian::docid> ids2;
2277 for (i1 = mset1.begin(), i2 = mset2.begin();
2278 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2279 TEST_NOT_EQUAL_DOUBLE(i1.get_weight(), 0);
2280 TEST_EQUAL_DOUBLE(i2.get_weight(), 0);
2281 ids1.push_back(*i1);
2282 ids2.push_back(*i2);
2284 sort(ids1.begin(), ids1.end());
2285 TEST_EQUAL(ids1, ids2);
2289 return true;
2292 // Test Query::OP_SCALE_WEIGHT being used to multiply some of the weights of a
2293 // search by zero.
2294 DEFINE_TESTCASE(scaleweight2, backend) {
2295 Xapian::Database db(get_database("apitest_phrase"));
2296 Xapian::Enquire enq(db);
2297 Xapian::MSetIterator i;
2299 Xapian::Query query1("fridg");
2300 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, 2.5);
2301 Xapian::Query query3("milk");
2302 Xapian::Query query4(Xapian::Query::OP_SCALE_WEIGHT, query3, 0);
2303 Xapian::Query query5(Xapian::Query::OP_OR, query2, query4);
2305 // query5 should first return the same results as query1, in the same
2306 // order, and then return the results of query3 which aren't also results
2307 // of query1, in ascending docid order. We test that this happens.
2309 // First, build a vector of docids matching the first part of the query,
2310 // and append the non-duplicate docids matching the second part of the
2311 // query.
2312 vector<Xapian::docid> ids1;
2313 set<Xapian::docid> idsin1;
2314 vector<Xapian::docid> ids3;
2316 enq.set_query(query1);
2317 Xapian::MSet mset1 = enq.get_mset(0, 20);
2318 enq.set_query(query3);
2319 Xapian::MSet mset3 = enq.get_mset(0, 20);
2320 TEST_NOT_EQUAL(mset1.size(), 0);
2321 for (i = mset1.begin(); i != mset1.end(); ++i) {
2322 ids1.push_back(*i);
2323 idsin1.insert(*i);
2325 TEST_NOT_EQUAL(mset3.size(), 0);
2326 for (i = mset3.begin(); i != mset3.end(); ++i) {
2327 if (idsin1.find(*i) != idsin1.end())
2328 continue;
2329 ids3.push_back(*i);
2331 sort(ids3.begin(), ids3.end());
2332 ids1.insert(ids1.end(), ids3.begin(), ids3.end());
2334 // Now, run the combined query and build a vector of the matching docids.
2335 vector<Xapian::docid> ids5;
2336 enq.set_query(query5);
2337 Xapian::MSet mset5 = enq.get_mset(0, 20);
2338 for (i = mset5.begin(); i != mset5.end(); ++i) {
2339 ids5.push_back(*i);
2342 TEST_EQUAL(ids1, ids5);
2343 return true;
2346 // Regression test for bug fixed in 1.0.5 - this test would failed under
2347 // valgrind because it used an uninitialised value.
2348 DEFINE_TESTCASE(bm25weight1, backend) {
2349 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2350 enquire.set_weighting_scheme(Xapian::BM25Weight(1, 25, 1, 0.01, 0.5));
2351 enquire.set_query(Xapian::Query("word"));
2353 Xapian::MSet mset = enquire.get_mset(0, 25);
2355 return true;
2358 // Feature test for TradWeight.
2359 DEFINE_TESTCASE(tradweight1, backend) {
2360 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2361 enquire.set_weighting_scheme(Xapian::TradWeight());
2362 enquire.set_query(Xapian::Query("word"));
2364 Xapian::MSet mset = enquire.get_mset(0, 25);
2365 TEST_EQUAL(mset.size(), 2);
2367 enquire.set_weighting_scheme(Xapian::TradWeight(0));
2368 enquire.set_query(Xapian::Query("this"));
2370 mset = enquire.get_mset(0, 25);
2371 TEST_EQUAL(mset.size(), 6);
2373 // Check that TradWeight(0) means wdf and doc length really don't affect
2374 // the weights as stated in the documentation.
2375 TEST_EQUAL(mset[0].get_weight(), mset[5].get_weight());
2377 return true;
2380 // Test TradWeight when weighting documents using an RSet.
2381 // Simply changed the weighting scheme used by rset2 testcase.
2382 DEFINE_TESTCASE(tradweight4, backend) {
2383 Xapian::Database mydb(get_database("apitest_rset"));
2384 Xapian::Enquire enquire(mydb);
2385 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
2387 enquire.set_query(myquery);
2388 enquire.set_weighting_scheme(Xapian::TradWeight());
2390 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
2392 Xapian::RSet myrset;
2393 myrset.add_document(2);
2395 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
2397 mset_expect_order(mymset1, 1, 2);
2398 // Document 2 should have higher weight than document 1 despite the wdf of
2399 // "people" being 1 because "people" indexes a document in the RSet whereas
2400 // "cuddly" (wdf=2) does not.
2401 mset_expect_order(mymset2, 2, 1);
2403 return true;
2406 // Feature test for Database::get_uuid().
2407 DEFINE_TESTCASE(uuid1, backend && !multi) {
2408 SKIP_TEST_FOR_BACKEND("inmemory");
2409 Xapian::Database db = get_database("apitest_simpledata");
2410 string uuid1 = db.get_uuid();
2411 TEST_EQUAL(uuid1.size(), 36);
2413 // A database with no sub-databases has an empty UUID.
2414 Xapian::Database db2;
2415 TEST(db2.get_uuid().empty());
2417 db2.add_database(db);
2418 TEST_EQUAL(uuid1, db2.get_uuid());
2420 // Multi-database has multiple UUIDs (we don't define the format exactly
2421 // so this assumes something about the implementation).
2422 db2.add_database(db);
2423 TEST_EQUAL(uuid1 + ":" + uuid1, db2.get_uuid());
2425 #ifdef XAPIAN_HAS_INMEMORY_BACKEND
2426 // This relies on InMemory databases not supporting uuids.
2427 // A multi-database containing a database with no uuid has no uuid.
2428 db2.add_database(Xapian::Database(string(), Xapian::DB_BACKEND_INMEMORY));
2429 TEST(db2.get_uuid().empty());
2430 #endif
2432 return true;