Fix whitespace irregularities in code
[xapian.git] / xapian-core / tests / api_anydb.cc
blob39d6195720bcfb56260bb5ab745b4840c60218ad
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 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 eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ, 2.0);
310 TEST_EQUAL(eset.size(), 3);
311 TEST_REL(eset.get_ebound(), >=, eset.size());
312 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 5.88109547674955);
313 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 5.88109547674955);
314 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.44473599216144);
316 return true;
319 // Just like test_expandweights1 but without USE_EXACT_TERMFREQ.
320 DEFINE_TESTCASE(expandweights2, backend) {
321 Xapian::Enquire enquire(get_database("apitest_simpledata"));
322 enquire.set_query(Xapian::Query("this"));
324 Xapian::MSet mymset = enquire.get_mset(0, 10);
326 Xapian::RSet myrset;
327 Xapian::MSetIterator i = mymset.begin();
328 myrset.add_document(*i);
329 myrset.add_document(*(++i));
331 Xapian::ESet eset = enquire.get_eset(3, myrset);
332 TEST_EQUAL(eset.size(), 3);
333 TEST_REL(eset.get_ebound(), >=, eset.size());
334 if (!startswith(get_dbtype(), "multi")) {
335 // For a single database, the weights should be the same with or
336 // without USE_EXACT_TERMFREQ.
337 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
338 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
339 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
340 } else {
341 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
342 // will result in different weights in some cases.
343 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
344 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
345 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
348 return true;
351 DEFINE_TESTCASE(expandweights3, backend) {
352 Xapian::Enquire enquire(get_database("apitest_simpledata"));
353 enquire.set_query(Xapian::Query("this"));
355 Xapian::MSet mymset = enquire.get_mset(0, 10);
357 Xapian::RSet myrset;
358 Xapian::MSetIterator i = mymset.begin();
359 myrset.add_document(*i);
360 myrset.add_document(*(++i));
362 // Set min_wt to 0.0
363 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 0, 0.0);
364 TEST_EQUAL(eset.size(), 50);
365 TEST_REL(eset.get_ebound(), >=, eset.size());
366 if (!startswith(get_dbtype(), "multi")) {
367 // For a single database, the weights should be the same with or
368 // without USE_EXACT_TERMFREQ.
369 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
370 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
371 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
372 } else {
373 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
374 // will result in different weights in some cases.
375 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
376 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
377 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
379 TEST_REL(eset.back().get_weight(),>=,0);
381 return true;
385 // tests that negative weights are returned
386 DEFINE_TESTCASE(expandweights4, backend) {
387 Xapian::Enquire enquire(get_database("apitest_simpledata"));
388 enquire.set_query(Xapian::Query("paragraph"));
390 Xapian::MSet mymset = enquire.get_mset(0, 10);
392 Xapian::RSet myrset;
393 Xapian::MSetIterator i = mymset.begin();
394 myrset.add_document(*i);
395 myrset.add_document(*(++i));
397 Xapian::ESet eset = enquire.get_eset(37, myrset, 0, 0, -100);
398 // Now include negative weights
399 TEST_EQUAL(eset.size(), 37);
400 TEST_REL(eset.get_ebound(), >=, eset.size());
401 TEST_REL(eset[36].get_weight(),<,0);
402 TEST_REL(eset[36].get_weight(),>=,-100);
404 return true;
407 // test for Bo1EWeight
408 DEFINE_TESTCASE(expandweights5, backend) {
409 Xapian::Enquire enquire(get_database("apitest_simpledata"));
410 enquire.set_query(Xapian::Query("this"));
412 Xapian::MSet mymset = enquire.get_mset(0, 10);
414 Xapian::RSet myrset;
415 Xapian::MSetIterator i = mymset.begin();
416 myrset.add_document(*i);
417 myrset.add_document(*(++i));
419 enquire.set_expansion_scheme("bo1");
420 Xapian::ESet eset = enquire.get_eset(3, myrset);
422 TEST_EQUAL(eset.size(), 3);
423 TEST_REL(eset.get_ebound(), >=, eset.size());
424 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 7.21765284821702);
425 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.661623193760022);
426 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.58090119783738);
428 return true;
431 // test that "trad" can be set as an expansion scheme.
432 DEFINE_TESTCASE(expandweights6, backend) {
433 Xapian::Enquire enquire(get_database("apitest_simpledata"));
434 enquire.set_query(Xapian::Query("this"));
436 Xapian::MSet mymset = enquire.get_mset(0, 10);
438 Xapian::RSet myrset;
439 Xapian::MSetIterator i = mymset.begin();
440 myrset.add_document(*i);
441 myrset.add_document(*(++i));
443 enquire.set_expansion_scheme("trad");
444 Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
446 TEST_EQUAL(eset.size(), 3);
447 TEST_REL(eset.get_ebound(), >=, eset.size());
448 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
449 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
450 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
452 return true;
455 // test that invalid scheme names are not accepted
456 DEFINE_TESTCASE(expandweights7, backend) {
457 Xapian::Enquire enquire(get_database("apitest_simpledata"));
459 TEST_EXCEPTION(Xapian::InvalidArgumentError,
460 enquire.set_expansion_scheme("no_such_scheme"));
462 return true;
465 // test that "expand_k" can be passed as a parameter to get_eset
466 DEFINE_TESTCASE(expandweights8, backend) {
467 Xapian::Enquire enquire(get_database("apitest_simpledata"));
468 enquire.set_query(Xapian::Query("this"));
470 Xapian::MSet mymset = enquire.get_mset(0, 10);
472 Xapian::RSet myrset;
473 Xapian::MSetIterator i = mymset.begin();
474 myrset.add_document(*i);
475 myrset.add_document(*(++i));
477 // Set expand_k to 1.0 and min_wt to 0
478 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 1.0, 0, 0);
479 if (!startswith(get_dbtype(), "multi")) {
480 // For a single database, the weights should be the same with or
481 // without USE_EXACT_TERMFREQ.
482 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
483 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
484 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
485 } else {
486 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
487 // will result in different weights in some cases.
488 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
489 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
490 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
492 TEST_REL(eset.back().get_weight(),>=,0);
494 return true;
497 // tests that when specifying maxitems to get_eset, no more than
498 // that are returned.
499 DEFINE_TESTCASE(expandmaxitems1, backend) {
500 Xapian::Enquire enquire(get_database("apitest_simpledata"));
501 enquire.set_query(Xapian::Query("this"));
503 Xapian::MSet mymset = enquire.get_mset(0, 10);
504 tout << "mymset.size() = " << mymset.size() << endl;
505 TEST(mymset.size() >= 2);
507 Xapian::RSet myrset;
508 Xapian::MSetIterator i = mymset.begin();
509 myrset.add_document(*i);
510 myrset.add_document(*(++i));
512 Xapian::ESet myeset = enquire.get_eset(1, myrset);
513 TEST_EQUAL(myeset.size(), 1);
514 TEST_REL(myeset.get_ebound(), >=, myeset.size());
516 return true;
519 // tests that a pure boolean query has all weights set to 0
520 DEFINE_TESTCASE(boolquery1, backend) {
521 Xapian::Query myboolquery(query("this"));
523 // open the database (in this case a simple text file
524 // we prepared earlier)
525 Xapian::Enquire enquire(get_database("apitest_simpledata"));
526 enquire.set_query(myboolquery);
527 enquire.set_weighting_scheme(Xapian::BoolWeight());
529 // retrieve the top results
530 Xapian::MSet mymset = enquire.get_mset(0, 10);
532 TEST_NOT_EQUAL(mymset.size(), 0);
533 TEST_EQUAL(mymset.get_max_possible(), 0);
534 for (Xapian::MSetIterator i = mymset.begin(); i != mymset.end(); ++i) {
535 TEST_EQUAL(i.get_weight(), 0);
537 return true;
540 // tests that get_mset() specifying "this" works as expected
541 DEFINE_TESTCASE(msetfirst1, backend) {
542 Xapian::Enquire enquire(get_database("apitest_simpledata"));
543 enquire.set_query(query("this"));
544 Xapian::MSet mymset1 = enquire.get_mset(0, 6);
545 Xapian::MSet mymset2 = enquire.get_mset(3, 3);
546 TEST(mset_range_is_same(mymset1, 3, mymset2, 0, 3));
548 // Regression test - we weren't adjusting the index into items[] by
549 // firstitem in api/omenquire.cc.
550 TEST_EQUAL(mymset1[5].get_document().get_data(),
551 mymset2[2].get_document().get_data());
552 return true;
555 // tests the converting-to-percent functions
556 DEFINE_TESTCASE(topercent1, backend) {
557 Xapian::Enquire enquire(get_database("apitest_simpledata"));
558 enquire.set_query(query("this"));
559 Xapian::MSet mymset = enquire.get_mset(0, 20);
561 int last_pct = 100;
562 Xapian::MSetIterator i = mymset.begin();
563 for ( ; i != mymset.end(); ++i) {
564 int pct = mymset.convert_to_percent(i);
565 TEST_AND_EXPLAIN(pct == i.get_percent(),
566 "convert_to_%(msetitor) != convert_to_%(wt)");
567 TEST_AND_EXPLAIN(pct == mymset.convert_to_percent(i.get_weight()),
568 "convert_to_%(msetitor) != convert_to_%(wt)");
569 TEST_AND_EXPLAIN(pct >= 0 && pct <= 100,
570 "percentage out of range: " << pct);
571 TEST_AND_EXPLAIN(pct <= last_pct, "percentage increased down mset");
572 last_pct = pct;
574 return true;
577 // tests the percentage values returned
578 DEFINE_TESTCASE(topercent2, backend) {
579 BackendManagerLocal local_manager;
580 local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
581 Xapian::Enquire localenq(local_manager.get_database("apitest_simpledata"));
582 Xapian::Enquire enquire(get_database("apitest_simpledata"));
584 int pct;
586 // First, test a search in which the top document scores 100%.
587 enquire.set_query(query("this"));
588 localenq.set_query(query("this"));
589 Xapian::MSet mymset = enquire.get_mset(0, 20);
590 Xapian::MSet localmset = localenq.get_mset(0, 20);
592 Xapian::MSetIterator i = mymset.begin();
593 TEST(i != mymset.end());
594 pct = mymset.convert_to_percent(i);
595 TEST_EQUAL(pct, 100);
597 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
598 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
599 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
600 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
601 TEST_EQUAL(mymset.size(), localmset.size());
602 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
604 // A search in which the top document doesn't have 100%
605 Xapian::Query q = query(Xapian::Query::OP_OR,
606 "this", "line", "paragraph", "rubbish");
607 enquire.set_query(q);
608 localenq.set_query(q);
609 mymset = enquire.get_mset(0, 20);
610 localmset = localenq.get_mset(0, 20);
612 i = mymset.begin();
613 TEST(i != mymset.end());
614 pct = mymset.convert_to_percent(i);
615 TEST_REL(pct,>,60);
616 TEST_REL(pct,<,76);
618 ++i;
620 TEST(i != mymset.end());
621 pct = mymset.convert_to_percent(i);
622 TEST_REL(pct,>,40);
623 TEST_REL(pct,<,50);
625 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
626 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
627 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
628 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
629 TEST_EQUAL(mymset.size(), localmset.size());
630 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
632 return true;
635 class myExpandFunctor : public Xapian::ExpandDecider {
636 public:
637 bool operator()(const string & tname) const {
638 unsigned long sum = 0;
639 for (unsigned ch : tname) {
640 sum += ch;
642 // if (verbose) {
643 // tout << tname << "==> " << sum << "\n";
644 // }
645 return (sum % 2) == 0;
649 // tests the expand decision functor
650 DEFINE_TESTCASE(expandfunctor1, backend) {
651 Xapian::Enquire enquire(get_database("apitest_simpledata"));
652 enquire.set_query(Xapian::Query("this"));
654 Xapian::MSet mymset = enquire.get_mset(0, 10);
655 TEST(mymset.size() >= 2);
657 Xapian::RSet myrset;
658 Xapian::MSetIterator i = mymset.begin();
659 myrset.add_document(*i);
660 myrset.add_document(*(++i));
662 myExpandFunctor myfunctor;
664 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
665 unsigned int neweset_size = 0;
666 Xapian::ESetIterator j = myeset_orig.begin();
667 for ( ; j != myeset_orig.end(); ++j) {
668 if (myfunctor(*j)) neweset_size++;
670 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
672 #if 0
673 // Compare myeset with the hand-filtered version of myeset_orig.
674 if (verbose) {
675 tout << "orig_eset: ";
676 copy(myeset_orig.begin(), myeset_orig.end(),
677 ostream_iterator<Xapian::ESetItem>(tout, " "));
678 tout << "\n";
680 tout << "new_eset: ";
681 copy(myeset.begin(), myeset.end(),
682 ostream_iterator<Xapian::ESetItem>(tout, " "));
683 tout << "\n";
685 #endif
686 Xapian::ESetIterator orig = myeset_orig.begin();
687 Xapian::ESetIterator filt = myeset.begin();
688 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
689 // skip over items that shouldn't be in myeset
690 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
691 ++orig;
694 TEST_AND_EXPLAIN(*orig == *filt &&
695 orig.get_weight() == filt.get_weight(),
696 "Mismatch in items " << *orig << " vs. " << *filt
697 << " after filtering");
700 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
701 ++orig;
704 TEST_EQUAL(orig, myeset_orig.end());
705 TEST_AND_EXPLAIN(filt == myeset.end(),
706 "Extra items in the filtered eset.");
707 return true;
710 DEFINE_TESTCASE(expanddeciderfilterprefix2, backend) {
711 Xapian::Enquire enquire(get_database("apitest_simpledata"));
712 enquire.set_query(Xapian::Query("this"));
714 Xapian::MSet mymset = enquire.get_mset(0, 10);
715 TEST(mymset.size() >= 2);
717 Xapian::RSet myrset;
718 Xapian::MSetIterator i = mymset.begin();
719 myrset.add_document(*i);
720 myrset.add_document(*(++i));
722 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
723 unsigned int neweset_size = 0;
725 // Choose the first char in the first term as prefix.
726 Xapian::ESetIterator j = myeset_orig.begin();
727 TEST(myeset_orig.size() >= 1);
728 string prefix(*j, 0, 1);
729 Xapian::ExpandDeciderFilterPrefix myfunctor(prefix);
731 for ( ; j != myeset_orig.end(); ++j) {
732 if (myfunctor(*j)) neweset_size++;
734 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
736 Xapian::ESetIterator orig = myeset_orig.begin();
737 Xapian::ESetIterator filt = myeset.begin();
738 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
739 // skip over items that shouldn't be in myeset
740 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
741 ++orig;
744 TEST_AND_EXPLAIN(*orig == *filt &&
745 orig.get_weight() == filt.get_weight(),
746 "Mismatch in items " << *orig << " vs. " << *filt
747 << " after filtering");
750 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
751 ++orig;
754 TEST_EQUAL(orig, myeset_orig.end());
755 TEST_AND_EXPLAIN(filt == myeset.end(),
756 "Extra items in the filtered eset.");
758 return true;
761 // tests the percent cutoff option
762 DEFINE_TESTCASE(pctcutoff1, backend) {
763 Xapian::Enquire enquire(get_database("apitest_simpledata"));
764 enquire.set_query(query(Xapian::Query::OP_OR,
765 "this", "line", "paragraph", "rubbish"));
766 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
768 if (verbose) {
769 tout << "Original mset pcts:";
770 print_mset_percentages(mymset1);
771 tout << "\n";
774 unsigned int num_items = 0;
775 int my_pct = 100;
776 int changes = 0;
777 Xapian::MSetIterator i = mymset1.begin();
778 int c = 0;
779 for ( ; i != mymset1.end(); ++i, ++c) {
780 int new_pct = mymset1.convert_to_percent(i);
781 if (new_pct != my_pct) {
782 changes++;
783 if (changes > 3) break;
784 num_items = c;
785 my_pct = new_pct;
789 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
790 if (verbose) {
791 tout << "Cutoff percent: " << my_pct << "\n";
794 enquire.set_cutoff(my_pct);
795 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
797 if (verbose) {
798 tout << "Percentages after cutoff:";
799 print_mset_percentages(mymset2);
800 tout << "\n";
803 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
804 "Match with % cutoff lost too many items");
806 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
807 (mymset2.convert_to_percent(mymset2[num_items]) == my_pct &&
808 mymset2.convert_to_percent(mymset2.back()) == my_pct),
809 "Match with % cutoff returned too many items");
811 return true;
814 // Tests the percent cutoff option combined with collapsing
815 DEFINE_TESTCASE(pctcutoff2, backend) {
816 Xapian::Enquire enquire(get_database("apitest_simpledata"));
817 enquire.set_query(Xapian::Query("this"));
818 enquire.set_query(Xapian::Query(Xapian::Query::OP_AND_NOT, Xapian::Query("this"), Xapian::Query("banana")));
819 Xapian::MSet mset = enquire.get_mset(0, 100);
821 if (verbose) {
822 tout << "Original mset pcts:";
823 print_mset_percentages(mset);
824 tout << "\n";
827 TEST(mset.size() >= 2);
828 TEST(mset[0].get_percent() - mset[1].get_percent() >= 2);
830 int cutoff = mset[0].get_percent() + mset[1].get_percent();
831 cutoff /= 2;
833 enquire.set_cutoff(cutoff);
834 enquire.set_collapse_key(1234); // Value which is always empty.
836 Xapian::MSet mset2 = enquire.get_mset(0, 1);
837 TEST_EQUAL(mset2.size(), 1);
838 TEST_EQUAL(mset2.get_matches_lower_bound(), 1);
839 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),>=,1);
840 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset.size());
841 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset.size());
842 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
843 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset2.get_uncollapsed_matches_estimated());
845 return true;
848 // Test that the percent cutoff option returns all the answers it should.
849 DEFINE_TESTCASE(pctcutoff3, backend) {
850 Xapian::Enquire enquire(get_database("apitest_simpledata"));
851 enquire.set_query(Xapian::Query("this"));
852 Xapian::MSet mset1 = enquire.get_mset(0, 10);
854 if (verbose) {
855 tout << "Original mset pcts:";
856 print_mset_percentages(mset1);
857 tout << "\n";
860 int percent = 100;
861 for (Xapian::MSetIterator i = mset1.begin(); i != mset1.end(); ++i) {
862 int new_percent = mset1.convert_to_percent(i);
863 if (new_percent != percent) {
864 enquire.set_cutoff(percent);
865 Xapian::MSet mset2 = enquire.get_mset(0, 10);
866 TEST_EQUAL(mset2.size(), i.get_rank());
867 percent = new_percent;
871 return true;
874 // tests the cutoff option
875 DEFINE_TESTCASE(cutoff1, backend) {
876 Xapian::Enquire enquire(get_database("apitest_simpledata"));
877 enquire.set_query(query(Xapian::Query::OP_OR,
878 "this", "line", "paragraph", "rubbish"));
879 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
881 if (verbose) {
882 tout << "Original mset weights:";
883 print_mset_weights(mymset1);
884 tout << "\n";
887 unsigned int num_items = 0;
888 double my_wt = -100;
889 int changes = 0;
890 Xapian::MSetIterator i = mymset1.begin();
891 int c = 0;
892 for ( ; i != mymset1.end(); ++i, ++c) {
893 double new_wt = i.get_weight();
894 if (new_wt != my_wt) {
895 changes++;
896 if (changes > 3) break;
897 num_items = c;
898 my_wt = new_wt;
902 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
903 if (verbose) {
904 tout << "Cutoff weight: " << my_wt << "\n";
907 enquire.set_cutoff(0, my_wt);
908 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
910 if (verbose) {
911 tout << "Weights after cutoff:";
912 print_mset_weights(mymset2);
913 tout << "\n";
916 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
917 "Match with cutoff lost too many items");
919 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
920 (mymset2[num_items].get_weight() == my_wt &&
921 mymset2.back().get_weight() == my_wt),
922 "Match with cutoff returned too many items");
924 return true;
927 // tests the allow query terms expand option
928 DEFINE_TESTCASE(allowqterms1, backend) {
929 Xapian::Enquire enquire(get_database("apitest_simpledata"));
930 string term = "paragraph";
931 enquire.set_query(Xapian::Query(term));
933 Xapian::MSet mymset = enquire.get_mset(0, 10);
934 TEST(mymset.size() >= 2);
936 Xapian::RSet myrset;
937 Xapian::MSetIterator i = mymset.begin();
938 myrset.add_document(*i);
939 myrset.add_document(*(++i));
941 Xapian::ESet myeset = enquire.get_eset(1000, myrset);
942 Xapian::ESetIterator j = myeset.begin();
943 for ( ; j != myeset.end(); ++j) {
944 TEST_NOT_EQUAL(*j, term);
947 Xapian::ESet myeset2 = enquire.get_eset(1000, myrset, Xapian::Enquire::INCLUDE_QUERY_TERMS);
948 j = myeset2.begin();
949 for ( ; j != myeset2.end(); ++j) {
950 if (*j == term) break;
952 TEST(j != myeset2.end());
953 return true;
956 // tests that the MSet max_attained works
957 DEFINE_TESTCASE(maxattain1, backend) {
958 Xapian::Enquire enquire(get_database("apitest_simpledata"));
959 enquire.set_query(query("this"));
960 Xapian::MSet mymset = enquire.get_mset(0, 100);
962 double mymax = 0;
963 Xapian::MSetIterator i = mymset.begin();
964 for ( ; i != mymset.end(); ++i) {
965 if (i.get_weight() > mymax) mymax = i.get_weight();
967 TEST_EQUAL(mymax, mymset.get_max_attained());
969 return true;
972 // tests a reversed boolean query
973 DEFINE_TESTCASE(reversebool1, backend) {
974 Xapian::Enquire enquire(get_database("apitest_simpledata"));
975 enquire.set_query(Xapian::Query("this"));
976 enquire.set_weighting_scheme(Xapian::BoolWeight());
978 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
979 TEST_AND_EXPLAIN(mymset1.size() > 1,
980 "Mset was too small to test properly");
982 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
983 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
984 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
985 Xapian::MSet mymset3 = enquire.get_mset(0, 100);
987 // mymset1 and mymset2 should be identical
988 TEST_EQUAL(mymset1.size(), mymset2.size());
991 Xapian::MSetIterator i = mymset1.begin();
992 Xapian::MSetIterator j = mymset2.begin();
993 for ( ; i != mymset1.end(); ++i, j++) {
994 TEST(j != mymset2.end());
995 // if this fails, then setting match_sort_forward=true was not
996 // the same as the default.
997 TEST_EQUAL(*i, *j);
999 TEST(j == mymset2.end());
1002 // mymset1 and mymset3 should be same but reversed
1003 TEST_EQUAL(mymset1.size(), mymset3.size());
1006 Xapian::MSetIterator i = mymset1.begin();
1007 Xapian::MSetIterator j = mymset3.end();
1008 for ( ; i != mymset1.end(); ++i) {
1009 // if this fails, then setting match_sort_forward=false didn't
1010 // reverse the results.
1011 TEST_EQUAL(*i, *--j);
1015 return true;
1018 // tests a reversed boolean query, where the full mset isn't returned
1019 DEFINE_TESTCASE(reversebool2, backend) {
1020 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1021 enquire.set_query(Xapian::Query("this"));
1022 enquire.set_weighting_scheme(Xapian::BoolWeight());
1024 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
1026 TEST_AND_EXPLAIN(mymset1.size() > 1,
1027 "Mset was too small to test properly");
1029 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1030 Xapian::doccount msize = mymset1.size() / 2;
1031 Xapian::MSet mymset2 = enquire.get_mset(0, msize);
1032 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1033 Xapian::MSet mymset3 = enquire.get_mset(0, msize);
1035 // mymset2 should be first msize items of mymset1
1036 TEST_EQUAL(msize, mymset2.size());
1038 Xapian::MSetIterator i = mymset1.begin();
1039 Xapian::MSetIterator j = mymset2.begin();
1040 for ( ; j != mymset2.end(); ++i, j++) {
1041 TEST(i != mymset1.end());
1042 // if this fails, then setting match_sort_forward=true was not
1043 // the same as the default.
1044 TEST_EQUAL(*i, *j);
1046 // mymset1 should be larger.
1047 TEST(i != mymset1.end());
1050 // mymset3 should be last msize items of mymset1, in reverse order
1051 TEST_EQUAL(msize, mymset3.size());
1053 Xapian::MSetIterator i = mymset1.end();
1054 Xapian::MSetIterator j;
1055 for (j = mymset3.begin(); j != mymset3.end(); j++) {
1056 // if this fails, then setting match_sort_forward=false didn't
1057 // reverse the results.
1058 TEST_EQUAL(*--i, *j);
1062 return true;
1065 // tests that get_matching_terms() returns the terms in the right order
1066 DEFINE_TESTCASE(getmterms1, backend) {
1067 list<string> answers_list;
1068 answers_list.push_back("one");
1069 answers_list.push_back("two");
1070 answers_list.push_back("three");
1071 answers_list.push_back("four");
1073 Xapian::Database mydb(get_database("apitest_termorder"));
1074 Xapian::Enquire enquire(mydb);
1076 Xapian::Query myquery(Xapian::Query::OP_OR,
1077 Xapian::Query(Xapian::Query::OP_AND,
1078 Xapian::Query("one", 1, 1),
1079 Xapian::Query("three", 1, 3)),
1080 Xapian::Query(Xapian::Query::OP_OR,
1081 Xapian::Query("four", 1, 4),
1082 Xapian::Query("two", 1, 2)));
1084 enquire.set_query(myquery);
1086 Xapian::MSet mymset = enquire.get_mset(0, 10);
1088 TEST_MSET_SIZE(mymset, 1);
1089 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1090 enquire.get_matching_terms_end(mymset.begin()));
1091 TEST(list == answers_list);
1093 return true;
1096 // tests that get_matching_terms() returns the terms only once
1097 DEFINE_TESTCASE(getmterms2, backend) {
1098 list<string> answers_list;
1099 answers_list.push_back("one");
1100 answers_list.push_back("two");
1101 answers_list.push_back("three");
1103 Xapian::Database mydb(get_database("apitest_termorder"));
1104 Xapian::Enquire enquire(mydb);
1106 Xapian::Query myquery(Xapian::Query::OP_OR,
1107 Xapian::Query(Xapian::Query::OP_AND,
1108 Xapian::Query("one", 1, 1),
1109 Xapian::Query("three", 1, 3)),
1110 Xapian::Query(Xapian::Query::OP_OR,
1111 Xapian::Query("one", 1, 4),
1112 Xapian::Query("two", 1, 2)));
1114 enquire.set_query(myquery);
1116 Xapian::MSet mymset = enquire.get_mset(0, 10);
1118 TEST_MSET_SIZE(mymset, 1);
1119 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1120 enquire.get_matching_terms_end(mymset.begin()));
1121 TEST(list == answers_list);
1123 return true;
1126 // test that running a query twice returns the same results
1127 DEFINE_TESTCASE(repeatquery1, backend) {
1128 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1129 enquire.set_query(Xapian::Query("this"));
1131 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1133 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1134 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1135 TEST_EQUAL(mymset1, mymset2);
1137 return true;
1140 // test that prefetching documents works (at least, gives same results)
1141 DEFINE_TESTCASE(fetchdocs1, backend) {
1142 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1143 enquire.set_query(Xapian::Query("this"));
1145 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1147 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1148 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1149 TEST_EQUAL(mymset1, mymset2);
1150 mymset2.fetch(mymset2[0], mymset2[mymset2.size() - 1]);
1151 mymset2.fetch(mymset2.begin(), mymset2.end());
1152 mymset2.fetch(mymset2.begin());
1153 mymset2.fetch();
1155 Xapian::MSetIterator it1 = mymset1.begin();
1156 Xapian::MSetIterator it2 = mymset2.begin();
1158 while (it1 != mymset1.end() && it2 != mymset2.end()) {
1159 TEST_EQUAL(it1.get_document().get_data(),
1160 it2.get_document().get_data());
1161 TEST_NOT_EQUAL(it1.get_document().get_data(), "");
1162 TEST_NOT_EQUAL(it2.get_document().get_data(), "");
1163 it1++;
1164 it2++;
1166 TEST_EQUAL(it1, mymset1.end());
1167 TEST_EQUAL(it1, mymset2.end());
1169 return true;
1172 // test that searching for a term not in the database fails nicely
1173 DEFINE_TESTCASE(absentterm1, backend) {
1174 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1175 enquire.set_weighting_scheme(Xapian::BoolWeight());
1176 enquire.set_query(Xapian::Query("frink"));
1178 Xapian::MSet mymset = enquire.get_mset(0, 10);
1179 mset_expect_order(mymset);
1181 return true;
1184 // as absentterm1, but setting query from a vector of terms
1185 DEFINE_TESTCASE(absentterm2, backend) {
1186 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1187 vector<string> terms;
1188 terms.push_back("frink");
1190 Xapian::Query query(Xapian::Query::OP_OR, terms.begin(), terms.end());
1191 enquire.set_query(query);
1193 Xapian::MSet mymset = enquire.get_mset(0, 10);
1194 mset_expect_order(mymset);
1196 return true;
1199 // test that rsets do sensible things
1200 DEFINE_TESTCASE(rset1, backend) {
1201 Xapian::Database mydb(get_database("apitest_rset"));
1202 Xapian::Enquire enquire(mydb);
1203 Xapian::Query myquery = query(Xapian::Query::OP_OR, "giraffe", "tiger");
1204 enquire.set_query(myquery);
1206 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1208 Xapian::RSet myrset;
1209 myrset.add_document(1);
1211 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1213 // We should have the same documents turn up, but 1 and 3 should
1214 // have higher weights with the RSet.
1215 TEST_MSET_SIZE(mymset1, 3);
1216 TEST_MSET_SIZE(mymset2, 3);
1218 return true;
1221 // test that rsets do more sensible things
1222 DEFINE_TESTCASE(rset2, backend) {
1223 Xapian::Database mydb(get_database("apitest_rset"));
1224 Xapian::Enquire enquire(mydb);
1225 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
1226 enquire.set_query(myquery);
1228 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1230 Xapian::RSet myrset;
1231 myrset.add_document(2);
1233 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1235 mset_expect_order(mymset1, 1, 2);
1236 mset_expect_order(mymset2, 2, 1);
1238 return true;
1241 // test that rsets behave correctly with multiDBs
1242 DEFINE_TESTCASE(rsetmultidb1, backend && !multi) {
1243 Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1244 Xapian::Database mydb2(get_database("apitest_rset"));
1245 mydb2.add_database(get_database("apitest_simpledata2"));
1247 Xapian::Enquire enquire1(mydb1);
1248 Xapian::Enquire enquire2(mydb2);
1250 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "multiple");
1252 enquire1.set_query(myquery);
1253 enquire2.set_query(myquery);
1255 Xapian::RSet myrset1;
1256 Xapian::RSet myrset2;
1257 myrset1.add_document(4);
1258 myrset2.add_document(2);
1260 Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
1261 Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
1262 Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
1263 Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
1265 mset_expect_order(mymset1a, 1, 4);
1266 mset_expect_order(mymset1b, 4, 1);
1267 mset_expect_order(mymset2a, 1, 2);
1268 mset_expect_order(mymset2b, 2, 1);
1270 TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
1271 TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
1272 TEST_NOT_EQUAL(mymset1a, mymset1b);
1273 TEST_NOT_EQUAL(mymset2a, mymset2b);
1275 return true;
1278 // regression tests - used to cause assertion in stats.h to fail
1279 // Doesn't actually fail for multi but it doesn't make sense to run there.
1280 DEFINE_TESTCASE(rsetmultidb3, backend && !multi) {
1281 Xapian::Enquire enquire(get_database("apitest_simpledata2"));
1282 enquire.set_query(query(Xapian::Query::OP_OR, "cuddly", "people"));
1283 Xapian::MSet mset = enquire.get_mset(0, 10); // used to fail assertion
1284 return true;
1287 /// Simple test of the elite set operator.
1288 DEFINE_TESTCASE(eliteset1, backend) {
1289 Xapian::Database mydb(get_database("apitest_simpledata"));
1290 Xapian::Enquire enquire(mydb);
1292 Xapian::Query myquery1 = query(Xapian::Query::OP_OR, "word");
1294 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1295 "simple", "word");
1297 enquire.set_query(myquery1, 2); // So the query lengths are the same.
1298 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1300 enquire.set_query(myquery2);
1301 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1303 TEST_EQUAL(mymset1, mymset2);
1304 return true;
1307 /// Test that the elite set operator works if the set contains
1308 /// sub-expressions (regression test)
1309 DEFINE_TESTCASE(eliteset2, backend) {
1310 Xapian::Database mydb(get_database("apitest_simpledata"));
1311 Xapian::Enquire enquire(mydb);
1313 Xapian::Query myquery1 = query(Xapian::Query::OP_AND, "word", "search");
1315 vector<Xapian::Query> qs;
1316 qs.push_back(query("this"));
1317 qs.push_back(query(Xapian::Query::OP_AND, "word", "search"));
1318 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET,
1319 qs.begin(), qs.end(), 1);
1321 enquire.set_query(myquery1);
1322 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1324 enquire.set_query(myquery2);
1325 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1327 TEST_EQUAL(mymset1, mymset2);
1328 // query lengths differ so mset weights not the same (with some weighting
1329 // parameters)
1330 //test_mset_order_equal(mymset1, mymset2);
1332 return true;
1335 /// Test that elite set doesn't affect query results if we have fewer
1336 /// terms than the threshold
1337 DEFINE_TESTCASE(eliteset3, backend) {
1338 Xapian::Database mydb1(get_database("apitest_simpledata"));
1339 Xapian::Enquire enquire1(mydb1);
1341 Xapian::Database mydb2(get_database("apitest_simpledata"));
1342 Xapian::Enquire enquire2(mydb2);
1344 // make a query
1345 Xapian::Stem stemmer("english");
1347 string term1 = stemmer("word");
1348 string term2 = stemmer("rubbish");
1349 string term3 = stemmer("banana");
1351 vector<string> terms;
1352 terms.push_back(term1);
1353 terms.push_back(term2);
1354 terms.push_back(term3);
1356 Xapian::Query myquery1(Xapian::Query::OP_OR, terms.begin(), terms.end());
1357 enquire1.set_query(myquery1);
1359 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET, terms.begin(), terms.end(), 3);
1360 enquire2.set_query(myquery2);
1362 // retrieve the results
1363 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1364 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1366 TEST_EQUAL(mymset1.get_termfreq(term1),
1367 mymset2.get_termfreq(term1));
1368 TEST_EQUAL(mymset1.get_termweight(term1),
1369 mymset2.get_termweight(term1));
1370 TEST_EQUAL(mymset1.get_termfreq(term2),
1371 mymset2.get_termfreq(term2));
1372 TEST_EQUAL(mymset1.get_termweight(term2),
1373 mymset2.get_termweight(term2));
1374 TEST_EQUAL(mymset1.get_termfreq(term3),
1375 mymset2.get_termfreq(term3));
1376 TEST_EQUAL(mymset1.get_termweight(term3),
1377 mymset2.get_termweight(term3));
1378 // TEST_EQUAL(mymset1, mymset2);
1380 return true;
1383 /// Test that elite set doesn't pick terms with 0 frequency
1384 DEFINE_TESTCASE(eliteset4, backend) {
1385 Xapian::Database mydb1(get_database("apitest_simpledata"));
1386 Xapian::Enquire enquire1(mydb1);
1388 Xapian::Database mydb2(get_database("apitest_simpledata"));
1389 Xapian::Enquire enquire2(mydb2);
1391 Xapian::Query myquery1 = query("rubbish");
1392 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1393 "word", "rubbish", "fibble");
1394 enquire1.set_query(myquery1);
1395 enquire2.set_query(myquery2);
1397 // retrieve the results
1398 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1399 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1401 TEST_NOT_EQUAL(mymset2.size(), 0);
1402 TEST_EQUAL(mymset1, mymset2);
1403 // TEST_EQUAL(mymset1, mymset2);
1405 return true;
1408 /// Regression test for problem with excess precision.
1409 DEFINE_TESTCASE(eliteset5, backend) {
1410 Xapian::Database mydb1(get_database("apitest_simpledata"));
1411 Xapian::Enquire enquire1(mydb1);
1413 vector<string> v;
1414 for (int i = 0; i != 3; ++i) {
1415 v.push_back("simpl");
1416 v.push_back("queri");
1418 v.push_back("rubbish");
1419 v.push_back("rubbish");
1420 v.push_back("rubbish");
1421 v.push_back("word");
1422 v.push_back("word");
1423 v.push_back("word");
1426 Xapian::Query myquery1 = Xapian::Query(Xapian::Query::OP_ELITE_SET,
1427 v.begin(), v.end(), 1);
1428 myquery1 = Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
1429 myquery1,
1430 0.004);
1432 enquire1.set_query(myquery1);
1433 // On architectures with excess precision (or, at least, on x86), the
1434 // following call used to result in a segfault.
1435 enquire1.get_mset(0, 10);
1437 return true;
1440 /// Test that the termfreq returned by termlists is correct.
1441 DEFINE_TESTCASE(termlisttermfreq1, backend) {
1442 Xapian::Database mydb(get_database("apitest_simpledata"));
1443 Xapian::Enquire enquire(mydb);
1444 Xapian::Stem stemmer("english");
1445 Xapian::RSet rset1;
1446 Xapian::RSet rset2;
1447 rset1.add_document(5);
1448 rset2.add_document(6);
1450 Xapian::ESet eset1 = enquire.get_eset(1000, rset1);
1451 Xapian::ESet eset2 = enquire.get_eset(1000, rset2);
1453 // search for weight of term 'another'
1454 string theterm = stemmer("another");
1456 double wt1 = 0;
1457 double wt2 = 0;
1459 Xapian::ESetIterator i = eset1.begin();
1460 for ( ; i != eset1.end(); i++) {
1461 if (*i == theterm) {
1462 wt1 = i.get_weight();
1463 break;
1468 Xapian::ESetIterator i = eset2.begin();
1469 for ( ; i != eset2.end(); i++) {
1470 if (*i == theterm) {
1471 wt2 = i.get_weight();
1472 break;
1477 TEST_NOT_EQUAL(wt1, 0);
1478 TEST_NOT_EQUAL(wt2, 0);
1479 TEST_EQUAL(wt1, wt2);
1481 return true;
1484 /// Test the termfrequency and termweight info returned for query terms
1485 DEFINE_TESTCASE(qterminfo1, backend) {
1486 Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1487 Xapian::Enquire enquire1(mydb1);
1489 Xapian::Database mydb2(get_database("apitest_simpledata"));
1490 mydb2.add_database(get_database("apitest_simpledata2"));
1491 Xapian::Enquire enquire2(mydb2);
1493 // make a query
1494 Xapian::Stem stemmer("english");
1496 string term1 = stemmer("word");
1497 string term2 = stemmer("inmemory");
1498 string term3 = stemmer("flibble");
1500 Xapian::Query myquery(Xapian::Query::OP_OR,
1501 Xapian::Query(term1),
1502 Xapian::Query(Xapian::Query::OP_OR,
1503 Xapian::Query(term2),
1504 Xapian::Query(term3)));
1505 enquire1.set_query(myquery);
1506 enquire2.set_query(myquery);
1508 // retrieve the results
1509 Xapian::MSet mymset1a = enquire1.get_mset(0, 0);
1510 Xapian::MSet mymset2a = enquire2.get_mset(0, 0);
1512 TEST_EQUAL(mymset1a.get_termfreq(term1),
1513 mymset2a.get_termfreq(term1));
1514 TEST_EQUAL(mymset1a.get_termfreq(term2),
1515 mymset2a.get_termfreq(term2));
1516 TEST_EQUAL(mymset1a.get_termfreq(term3),
1517 mymset2a.get_termfreq(term3));
1519 TEST_EQUAL(mymset1a.get_termfreq(term1), 3);
1520 TEST_EQUAL(mymset1a.get_termfreq(term2), 1);
1521 TEST_EQUAL(mymset1a.get_termfreq(term3), 0);
1523 TEST_NOT_EQUAL(mymset1a.get_termweight(term1), 0);
1524 TEST_NOT_EQUAL(mymset1a.get_termweight(term2), 0);
1525 // non-existent terms should have 0 weight.
1526 TEST_EQUAL(mymset1a.get_termweight(term3), 0);
1528 TEST_EQUAL(mymset1a.get_termfreq(stemmer("banana")), 1);
1529 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1530 mymset1a.get_termweight(stemmer("banana")));
1532 TEST_EQUAL(mymset1a.get_termfreq("sponge"), 0);
1533 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1534 mymset1a.get_termweight("sponge"));
1536 return true;
1539 /// Regression test for bug #37.
1540 DEFINE_TESTCASE(qterminfo2, backend) {
1541 Xapian::Database db(get_database("apitest_simpledata"));
1542 Xapian::Enquire enquire(db);
1544 // make a query
1545 Xapian::Stem stemmer("english");
1547 string term1 = stemmer("paragraph");
1548 string term2 = stemmer("another");
1550 Xapian::Query query(Xapian::Query::OP_AND_NOT, term1,
1551 Xapian::Query(Xapian::Query::OP_AND, term1, term2));
1552 enquire.set_query(query);
1554 // retrieve the results
1555 // Note: get_mset() used to throw "AssertionError" in debug builds
1556 Xapian::MSet mset = enquire.get_mset(0, 10);
1558 TEST_NOT_EQUAL(mset.get_termweight("paragraph"), 0);
1560 return true;
1563 // tests that when specifying that no items are to be returned, those
1564 // statistics which should be the same are.
1565 DEFINE_TESTCASE(msetzeroitems1, backend) {
1566 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1567 enquire.set_query(query("this"));
1568 Xapian::MSet mymset1 = enquire.get_mset(0, 0);
1570 Xapian::MSet mymset2 = enquire.get_mset(0, 1);
1572 TEST_EQUAL(mymset1.get_max_possible(), mymset2.get_max_possible());
1574 return true;
1577 // test that the matches_* of a simple query are as expected
1578 DEFINE_TESTCASE(matches1, backend) {
1579 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1580 Xapian::Query myquery;
1581 Xapian::MSet mymset;
1583 myquery = query("word");
1584 enquire.set_query(myquery);
1585 mymset = enquire.get_mset(0, 10);
1586 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1587 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1588 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1589 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1590 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1591 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1593 myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
1594 enquire.set_query(myquery);
1595 mymset = enquire.get_mset(0, 10);
1596 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1597 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1598 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1599 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1600 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1601 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1603 myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
1604 enquire.set_query(myquery);
1605 mymset = enquire.get_mset(0, 10);
1606 TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1607 TEST_EQUAL(mymset.get_matches_estimated(), 0);
1608 TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
1609 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
1610 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
1611 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
1613 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1614 enquire.set_query(myquery);
1615 mymset = enquire.get_mset(0, 10);
1616 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1617 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1618 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1619 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1620 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1621 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1623 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1624 enquire.set_query(myquery);
1625 mymset = enquire.get_mset(0, 0);
1626 // For a single database, this is true, but not for "multi" (since there
1627 // one sub-database has 3 documents and simple and word both have termfreq
1628 // of 2, so the matcher can tell at least one document must match!)
1629 // TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1630 TEST_REL(mymset.get_matches_lower_bound(),<=,mymset.get_matches_estimated());
1631 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1632 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1633 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,mymset.get_uncollapsed_matches_estimated());
1634 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1635 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1637 mymset = enquire.get_mset(0, 1);
1638 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1639 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1640 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1641 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1642 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1643 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1645 mymset = enquire.get_mset(0, 2);
1646 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1647 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1648 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1649 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1650 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1651 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1653 myquery = query(Xapian::Query::OP_AND, "paragraph", "another");
1654 enquire.set_query(myquery);
1655 mymset = enquire.get_mset(0, 0);
1656 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1657 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1658 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1659 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1660 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1661 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1663 mymset = enquire.get_mset(0, 1);
1664 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1665 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1666 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1667 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1668 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1669 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1671 mymset = enquire.get_mset(0, 2);
1672 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1673 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1674 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1675 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1676 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1677 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1679 mymset = enquire.get_mset(1, 20);
1680 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1681 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1682 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1683 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1684 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1685 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1687 return true;
1690 // tests that wqf affects the document weights
1691 DEFINE_TESTCASE(wqf1, backend) {
1692 // Both queries have length 2; in q1 word has wqf=2, in q2 word has wqf=1
1693 Xapian::Query q1("word", 2);
1694 Xapian::Query q2("word");
1695 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1696 enquire.set_query(q1);
1697 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1698 enquire.set_query(q2);
1699 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1700 // Check the weights
1701 TEST(mset1.begin().get_weight() > mset2.begin().get_weight());
1702 return true;
1705 // tests that query length affects the document weights
1706 DEFINE_TESTCASE(qlen1, backend) {
1707 Xapian::Query q1("word");
1708 Xapian::Query q2("word");
1709 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1710 enquire.set_query(q1);
1711 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1712 enquire.set_query(q2);
1713 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1714 // Check the weights
1715 //TEST(mset1.begin().get_weight() < mset2.begin().get_weight());
1716 TEST(mset1.begin().get_weight() == mset2.begin().get_weight());
1717 return true;
1720 // tests that opening a non-existent termlist throws the correct exception
1721 DEFINE_TESTCASE(termlist1, backend) {
1722 Xapian::Database db(get_database("apitest_onedoc"));
1723 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1724 Xapian::TermIterator t = db.termlist_begin(0));
1725 TEST_EXCEPTION(Xapian::DocNotFoundError,
1726 Xapian::TermIterator t = db.termlist_begin(2));
1727 /* Cause the database to be used properly, showing up problems
1728 * with the link being in a bad state. CME */
1729 Xapian::TermIterator temp = db.termlist_begin(1);
1730 TEST_EXCEPTION(Xapian::DocNotFoundError,
1731 Xapian::TermIterator t = db.termlist_begin(999999999));
1732 return true;
1735 // tests that a Xapian::TermIterator works as an STL iterator
1736 DEFINE_TESTCASE(termlist2, backend) {
1737 Xapian::Database db(get_database("apitest_onedoc"));
1738 Xapian::TermIterator t = db.termlist_begin(1);
1739 Xapian::TermIterator tend = db.termlist_end(1);
1741 // test operator= creates a copy which compares equal
1742 Xapian::TermIterator t_copy = t;
1743 TEST_EQUAL(t, t_copy);
1745 // test copy constructor creates a copy which compares equal
1746 Xapian::TermIterator t_clone(t);
1747 TEST_EQUAL(t, t_clone);
1749 vector<string> v(t, tend);
1751 t = db.termlist_begin(1);
1752 tend = db.termlist_end(1);
1753 vector<string>::const_iterator i;
1754 for (i = v.begin(); i != v.end(); ++i) {
1755 TEST_NOT_EQUAL(t, tend);
1756 TEST_EQUAL(*i, *t);
1757 t++;
1759 TEST_EQUAL(t, tend);
1760 return true;
1763 static Xapian::TermIterator
1764 test_termlist3_helper()
1766 Xapian::Database db(get_database("apitest_onedoc"));
1767 return db.termlist_begin(1);
1770 // tests that a Xapian::TermIterator still works when the DB is deleted
1771 DEFINE_TESTCASE(termlist3, backend) {
1772 Xapian::TermIterator u = test_termlist3_helper();
1773 Xapian::Database db(get_database("apitest_onedoc"));
1774 Xapian::TermIterator t = db.termlist_begin(1);
1775 Xapian::TermIterator tend = db.termlist_end(1);
1777 while (t != tend) {
1778 TEST_EQUAL(*t, *u);
1779 t++;
1780 u++;
1782 return true;
1785 // tests skip_to
1786 DEFINE_TESTCASE(termlist4, backend) {
1787 Xapian::Database db(get_database("apitest_onedoc"));
1788 Xapian::TermIterator i = db.termlist_begin(1);
1789 i.skip_to("");
1790 i.skip_to("\xff");
1791 return true;
1794 // tests punctuation is OK in terms (particularly in remote queries)
1795 DEFINE_TESTCASE(puncterms1, backend) {
1796 Xapian::Database db(get_database("apitest_punc"));
1797 Xapian::Enquire enquire(db);
1799 Xapian::Query q1("semi;colon");
1800 enquire.set_query(q1);
1801 Xapian::MSet m1 = enquire.get_mset(0, 10);
1803 Xapian::Query q2("col:on");
1804 enquire.set_query(q2);
1805 Xapian::MSet m2 = enquire.get_mset(0, 10);
1807 Xapian::Query q3("com,ma");
1808 enquire.set_query(q3);
1809 Xapian::MSet m3 = enquire.get_mset(0, 10);
1811 return true;
1814 // test that searching for a term with a space or backslash in it works
1815 DEFINE_TESTCASE(spaceterms1, backend) {
1816 Xapian::Enquire enquire(get_database("apitest_space"));
1817 Xapian::MSet mymset;
1818 Xapian::doccount count;
1819 Xapian::MSetIterator m;
1820 Xapian::Stem stemmer("english");
1822 enquire.set_query(stemmer("space man"));
1823 mymset = enquire.get_mset(0, 10);
1824 TEST_MSET_SIZE(mymset, 1);
1825 count = 0;
1826 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1827 TEST_EQUAL(count, 1);
1829 for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
1830 TEST_NOT_EQUAL(mymset.begin().get_document().get_data(), "");
1831 TEST_NOT_EQUAL(mymset.begin().get_document().get_value(value_no), "");
1834 enquire.set_query(stemmer("tab\tby"));
1835 mymset = enquire.get_mset(0, 10);
1836 TEST_MSET_SIZE(mymset, 1);
1837 count = 0;
1838 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1839 TEST_EQUAL(count, 1);
1841 for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
1842 string value = mymset.begin().get_document().get_value(value_no);
1843 TEST_NOT_EQUAL(value, "");
1844 if (value_no == 0) {
1845 TEST(value.size() > 262);
1846 TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
1850 enquire.set_query(stemmer("back\\slash"));
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 return true;
1860 // test that XOR queries work
1861 DEFINE_TESTCASE(xor1, backend) {
1862 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1863 Xapian::Stem stemmer("english");
1865 vector<string> terms;
1866 terms.push_back(stemmer("this"));
1867 terms.push_back(stemmer("word"));
1868 terms.push_back(stemmer("of"));
1870 Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1871 enquire.set_weighting_scheme(Xapian::BoolWeight());
1872 enquire.set_query(query);
1874 Xapian::MSet mymset = enquire.get_mset(0, 10);
1875 // Docid this word of Match?
1876 // 1 * *
1877 // 2 * * * *
1878 // 3 * *
1879 // 4 * *
1880 // 5 * *
1881 // 6 * *
1882 mset_expect_order(mymset, 1, 2, 5, 6);
1884 return true;
1887 /// Test that weighted XOR queries work (bug fixed in 1.2.1 and 1.0.21).
1888 DEFINE_TESTCASE(xor2, backend) {
1889 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1890 Xapian::Stem stemmer("english");
1892 vector<string> terms;
1893 terms.push_back(stemmer("this"));
1894 terms.push_back(stemmer("word"));
1895 terms.push_back(stemmer("of"));
1897 Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1898 enquire.set_query(query);
1900 Xapian::MSet mymset = enquire.get_mset(0, 10);
1901 // Docid LEN this word of Match?
1902 // 1 28 2 *
1903 // 2 81 5 8 1 *
1904 // 3 15 1 2
1905 // 4 31 1 1
1906 // 5 15 1 *
1907 // 6 15 1 *
1908 mset_expect_order(mymset, 2, 1, 5, 6);
1910 return true;
1913 // test Xapian::Database::get_document()
1914 DEFINE_TESTCASE(getdoc1, backend) {
1915 Xapian::Database db(get_database("apitest_onedoc"));
1916 Xapian::Document doc(db.get_document(1));
1917 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_document(0));
1918 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(999999999));
1919 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(123456789));
1920 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
1921 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
1922 // Check that Document works as a handle on modification
1923 // (this was broken for the first try at Xapian::Document prior to 0.7).
1924 Xapian::Document doc2 = doc;
1925 doc.set_data("modified!");
1926 TEST_EQUAL(doc.get_data(), "modified!");
1927 TEST_EQUAL(doc.get_data(), doc2.get_data());
1928 return true;
1931 // test whether operators with no elements work as a null query
1932 DEFINE_TESTCASE(emptyop1, backend) {
1933 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1934 vector<Xapian::Query> nullvec;
1936 Xapian::Query query1(Xapian::Query::OP_XOR, nullvec.begin(), nullvec.end());
1938 enquire.set_query(query1);
1939 Xapian::MSet mymset = enquire.get_mset(0, 10);
1940 TEST_MSET_SIZE(mymset, 0);
1941 // In Xapian < 1.3.0, this gave InvalidArgumentError (because
1942 // query1.empty()) but elsewhere we treat an empty query as just not
1943 // matching any documents, so we now do the same here too.
1944 TEST_EQUAL(enquire.get_matching_terms_begin(1),
1945 enquire.get_matching_terms_end(1));
1947 return true;
1950 // Regression test for check_at_least SEGV when there are no matches.
1951 DEFINE_TESTCASE(checkatleast1, backend) {
1952 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1953 enquire.set_query(Xapian::Query("thom"));
1954 Xapian::MSet mymset = enquire.get_mset(0, 10, 11);
1955 TEST_EQUAL(0, mymset.size());
1957 return true;
1960 // Regression test - if check_at_least was set we returned (check_at_least - 1)
1961 // results, rather than the requested msize. Fixed in 1.0.2.
1962 DEFINE_TESTCASE(checkatleast2, backend) {
1963 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1964 enquire.set_query(Xapian::Query("paragraph"));
1966 Xapian::MSet mymset = enquire.get_mset(0, 3, 10);
1967 TEST_MSET_SIZE(mymset, 3);
1968 TEST_EQUAL(mymset.get_matches_lower_bound(), 5);
1969 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 5);
1971 mymset = enquire.get_mset(0, 2, 4);
1972 TEST_MSET_SIZE(mymset, 2);
1973 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1974 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
1975 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1976 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
1978 return true;
1981 // Feature tests - check_at_least with various sorting options.
1982 DEFINE_TESTCASE(checkatleast3, backend) {
1983 Xapian::Enquire enquire(get_database("etext"));
1984 enquire.set_query(Xapian::Query("prussian")); // 60 matches.
1986 for (int order = 0; order < 3; ++order) {
1987 switch (order) {
1988 case 0:
1989 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1990 break;
1991 case 1:
1992 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1993 break;
1994 case 2:
1995 enquire.set_docid_order(Xapian::Enquire::DONT_CARE);
1996 break;
1999 for (int sort = 0; sort < 7; ++sort) {
2000 bool reverse = (sort & 1);
2001 switch (sort) {
2002 case 0:
2003 enquire.set_sort_by_relevance();
2004 break;
2005 case 1: case 2:
2006 enquire.set_sort_by_value(0, reverse);
2007 break;
2008 case 3: case 4:
2009 enquire.set_sort_by_value_then_relevance(0, reverse);
2010 break;
2011 case 5: case 6:
2012 enquire.set_sort_by_relevance_then_value(0, reverse);
2013 break;
2016 Xapian::MSet mset = enquire.get_mset(0, 100, 500);
2017 TEST_MSET_SIZE(mset, 60);
2018 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2019 TEST_EQUAL(mset.get_matches_estimated(), 60);
2020 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2021 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2022 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2023 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2025 mset = enquire.get_mset(0, 50, 100);
2026 TEST_MSET_SIZE(mset, 50);
2027 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2028 TEST_EQUAL(mset.get_matches_estimated(), 60);
2029 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2030 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2031 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2032 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2034 mset = enquire.get_mset(0, 10, 50);
2035 TEST_MSET_SIZE(mset, 10);
2036 TEST_REL(mset.get_matches_lower_bound(),>=,50);
2037 TEST_REL(mset.get_uncollapsed_matches_lower_bound(),>=,50);
2041 return true;
2044 // tests all document postlists
2045 DEFINE_TESTCASE(allpostlist1, backend) {
2046 Xapian::Database db(get_database("apitest_manydocs"));
2047 Xapian::PostingIterator i = db.postlist_begin("");
2048 unsigned int j = 1;
2049 while (i != db.postlist_end("")) {
2050 TEST_EQUAL(*i, j);
2051 i++;
2052 j++;
2054 TEST_EQUAL(j, 513);
2056 i = db.postlist_begin("");
2057 j = 1;
2058 while (i != db.postlist_end("")) {
2059 TEST_EQUAL(*i, j);
2060 i++;
2061 j++;
2062 if (j == 50) {
2063 j += 10;
2064 i.skip_to(j);
2067 TEST_EQUAL(j, 513);
2069 return true;
2072 static void test_emptyterm1_helper(Xapian::Database & db)
2074 // Don't bother with postlist_begin() because allpostlist tests cover that.
2075 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
2076 TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
2077 TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
2078 TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
2081 // tests results of passing an empty term to various methods
2082 DEFINE_TESTCASE(emptyterm1, backend) {
2083 Xapian::Database db(get_database("apitest_manydocs"));
2084 TEST_EQUAL(db.get_doccount(), 512);
2085 test_emptyterm1_helper(db);
2087 db = get_database("apitest_onedoc");
2088 TEST_EQUAL(db.get_doccount(), 1);
2089 test_emptyterm1_helper(db);
2091 db = get_database("");
2092 TEST_EQUAL(db.get_doccount(), 0);
2093 test_emptyterm1_helper(db);
2095 return true;
2098 // Test for alldocs postlist with a sparse database.
2099 DEFINE_TESTCASE(alldocspl1, writable) {
2100 Xapian::WritableDatabase db = get_writable_database();
2101 Xapian::Document doc;
2102 doc.set_data("5");
2103 doc.add_value(0, "5");
2104 db.replace_document(5, doc);
2106 Xapian::PostingIterator i = db.postlist_begin("");
2107 TEST(i != db.postlist_end(""));
2108 TEST_EQUAL(*i, 5);
2109 TEST_EQUAL(i.get_doclength(), 0);
2110 TEST_EQUAL(i.get_unique_terms(), 0);
2111 TEST_EQUAL(i.get_wdf(), 1);
2112 ++i;
2113 TEST(i == db.postlist_end(""));
2115 return true;
2118 // Test reading and writing a modified alldocspostlist.
2119 DEFINE_TESTCASE(alldocspl2, writable) {
2120 Xapian::PostingIterator i, end;
2122 Xapian::WritableDatabase db = get_writable_database();
2123 Xapian::Document doc;
2124 doc.set_data("5");
2125 doc.add_value(0, "5");
2126 db.replace_document(5, doc);
2128 // Test iterating before committing the changes.
2129 i = db.postlist_begin("");
2130 end = db.postlist_end("");
2131 TEST(i != end);
2132 TEST_EQUAL(*i, 5);
2133 TEST_EQUAL(i.get_doclength(), 0);
2134 TEST_EQUAL(i.get_unique_terms(), 0);
2135 TEST_EQUAL(i.get_wdf(), 1);
2136 ++i;
2137 TEST(i == end);
2139 db.commit();
2141 // Test iterating after committing the changes.
2142 i = db.postlist_begin("");
2143 end = db.postlist_end("");
2144 TEST(i != end);
2145 TEST_EQUAL(*i, 5);
2146 TEST_EQUAL(i.get_doclength(), 0);
2147 TEST_EQUAL(i.get_unique_terms(), 0);
2148 TEST_EQUAL(i.get_wdf(), 1);
2149 ++i;
2150 TEST(i == end);
2152 // Add another document.
2153 doc = Xapian::Document();
2154 doc.set_data("5");
2155 doc.add_value(0, "7");
2156 db.replace_document(7, doc);
2158 // Test iterating through before committing the changes.
2159 i = db.postlist_begin("");
2160 end = db.postlist_end("");
2161 TEST(i != end);
2162 TEST_EQUAL(*i, 5);
2163 TEST_EQUAL(i.get_doclength(), 0);
2164 TEST_EQUAL(i.get_unique_terms(), 0);
2165 TEST_EQUAL(i.get_wdf(), 1);
2166 ++i;
2167 TEST(i != end);
2168 TEST_EQUAL(*i, 7);
2169 TEST_EQUAL(i.get_doclength(), 0);
2170 TEST_EQUAL(i.get_unique_terms(), 0);
2171 TEST_EQUAL(i.get_wdf(), 1);
2172 ++i;
2173 TEST(i == end);
2175 // Delete the first document.
2176 db.delete_document(5);
2178 // Test iterating through before committing the changes.
2179 i = db.postlist_begin("");
2180 end = db.postlist_end("");
2181 TEST(i != end);
2182 TEST_EQUAL(*i, 7);
2183 TEST_EQUAL(i.get_doclength(), 0);
2184 TEST_EQUAL(i.get_unique_terms(), 0);
2185 TEST_EQUAL(i.get_wdf(), 1);
2186 ++i;
2187 TEST(i == end);
2189 // Test iterating through after committing the changes, and dropping the
2190 // reference to the main DB.
2191 db.commit();
2192 i = db.postlist_begin("");
2193 end = db.postlist_end("");
2196 TEST(i != end);
2197 TEST_EQUAL(*i, 7);
2198 TEST_EQUAL(i.get_doclength(), 0);
2199 TEST_EQUAL(i.get_unique_terms(), 0);
2200 TEST_EQUAL(i.get_wdf(), 1);
2201 ++i;
2202 TEST(i == end);
2204 return true;
2207 // Feature test for Query::OP_SCALE_WEIGHT.
2208 DEFINE_TESTCASE(scaleweight1, backend) {
2209 Xapian::Database db(get_database("apitest_phrase"));
2210 Xapian::Enquire enq(db);
2211 Xapian::QueryParser qp;
2213 static const char * queries[] = {
2214 "pad",
2215 "milk fridge",
2216 "leave milk on fridge",
2217 "ordered milk operator",
2218 "ordered phrase operator",
2219 "leave \"milk on fridge\"",
2220 "notpresent",
2221 "leave \"milk notpresent\"",
2222 NULL
2224 static const double multipliers[] = {
2225 -1000000, -2.5, -1, -0.5, 0, 0.5, 1, 2.5, 1000000,
2226 0, 0
2229 for (const char **qstr = queries; *qstr; ++qstr) {
2230 tout.str(string());
2231 Xapian::Query query1 = qp.parse_query(*qstr);
2232 tout << "query1: " << query1.get_description() << endl;
2233 for (const double *multp = multipliers; multp[0] != multp[1]; ++multp) {
2234 double mult = *multp;
2235 if (mult < 0) {
2236 TEST_EXCEPTION(Xapian::InvalidArgumentError,
2237 Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
2238 query1, mult));
2239 continue;
2241 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, mult);
2242 tout << "query2: " << query2.get_description() << endl;
2244 enq.set_query(query1);
2245 Xapian::MSet mset1 = enq.get_mset(0, 20);
2246 enq.set_query(query2);
2247 Xapian::MSet mset2 = enq.get_mset(0, 20);
2249 TEST_EQUAL(mset1.size(), mset2.size());
2251 Xapian::MSetIterator i1, i2;
2252 if (mult > 0) {
2253 for (i1 = mset1.begin(), i2 = mset2.begin();
2254 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2255 TEST_EQUAL_DOUBLE(i1.get_weight() * mult, i2.get_weight());
2256 TEST_EQUAL(*i1, *i2);
2258 } else {
2259 // Weights in mset2 are 0; so it should be sorted by docid.
2260 vector<Xapian::docid> ids1;
2261 vector<Xapian::docid> ids2;
2262 for (i1 = mset1.begin(), i2 = mset2.begin();
2263 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2264 TEST_NOT_EQUAL_DOUBLE(i1.get_weight(), 0);
2265 TEST_EQUAL_DOUBLE(i2.get_weight(), 0);
2266 ids1.push_back(*i1);
2267 ids2.push_back(*i2);
2269 sort(ids1.begin(), ids1.end());
2270 TEST_EQUAL(ids1, ids2);
2274 return true;
2277 // Test Query::OP_SCALE_WEIGHT being used to multiply some of the weights of a
2278 // search by zero.
2279 DEFINE_TESTCASE(scaleweight2, backend) {
2280 Xapian::Database db(get_database("apitest_phrase"));
2281 Xapian::Enquire enq(db);
2282 Xapian::MSetIterator i;
2284 Xapian::Query query1("fridg");
2285 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, 2.5);
2286 Xapian::Query query3("milk");
2287 Xapian::Query query4(Xapian::Query::OP_SCALE_WEIGHT, query3, 0);
2288 Xapian::Query query5(Xapian::Query::OP_OR, query2, query4);
2290 // query5 should first return the same results as query1, in the same
2291 // order, and then return the results of query3 which aren't also results
2292 // of query1, in ascending docid order. We test that this happens.
2294 // First, build a vector of docids matching the first part of the query,
2295 // and append the non-duplicate docids matching the second part of the
2296 // query.
2297 vector<Xapian::docid> ids1;
2298 set<Xapian::docid> idsin1;
2299 vector<Xapian::docid> ids3;
2301 enq.set_query(query1);
2302 Xapian::MSet mset1 = enq.get_mset(0, 20);
2303 enq.set_query(query3);
2304 Xapian::MSet mset3 = enq.get_mset(0, 20);
2305 TEST_NOT_EQUAL(mset1.size(), 0);
2306 for (i = mset1.begin(); i != mset1.end(); ++i) {
2307 ids1.push_back(*i);
2308 idsin1.insert(*i);
2310 TEST_NOT_EQUAL(mset3.size(), 0);
2311 for (i = mset3.begin(); i != mset3.end(); ++i) {
2312 if (idsin1.find(*i) != idsin1.end())
2313 continue;
2314 ids3.push_back(*i);
2316 sort(ids3.begin(), ids3.end());
2317 ids1.insert(ids1.end(), ids3.begin(), ids3.end());
2319 // Now, run the combined query and build a vector of the matching docids.
2320 vector<Xapian::docid> ids5;
2321 enq.set_query(query5);
2322 Xapian::MSet mset5 = enq.get_mset(0, 20);
2323 for (i = mset5.begin(); i != mset5.end(); ++i) {
2324 ids5.push_back(*i);
2327 TEST_EQUAL(ids1, ids5);
2328 return true;
2331 // Regression test for bug fixed in 1.0.5 - this test would failed under
2332 // valgrind because it used an uninitialised value.
2333 DEFINE_TESTCASE(bm25weight1, backend) {
2334 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2335 enquire.set_weighting_scheme(Xapian::BM25Weight(1, 25, 1, 0.01, 0.5));
2336 enquire.set_query(Xapian::Query("word"));
2338 Xapian::MSet mset = enquire.get_mset(0, 25);
2340 return true;
2343 // Feature test for TradWeight.
2344 DEFINE_TESTCASE(tradweight1, backend) {
2345 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2346 enquire.set_weighting_scheme(Xapian::TradWeight());
2347 enquire.set_query(Xapian::Query("word"));
2349 Xapian::MSet mset = enquire.get_mset(0, 25);
2350 TEST_EQUAL(mset.size(), 2);
2352 enquire.set_weighting_scheme(Xapian::TradWeight(0));
2353 enquire.set_query(Xapian::Query("this"));
2355 mset = enquire.get_mset(0, 25);
2356 TEST_EQUAL(mset.size(), 6);
2358 // Check that TradWeight(0) means wdf and doc length really don't affect
2359 // the weights as stated in the documentation.
2360 TEST_EQUAL(mset[0].get_weight(), mset[5].get_weight());
2362 return true;
2365 // Test TradWeight when weighting documents using an RSet.
2366 // Simply changed the weighting scheme used by rset2 testcase.
2367 DEFINE_TESTCASE(tradweight4, backend) {
2368 Xapian::Database mydb(get_database("apitest_rset"));
2369 Xapian::Enquire enquire(mydb);
2370 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
2372 enquire.set_query(myquery);
2373 enquire.set_weighting_scheme(Xapian::TradWeight());
2375 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
2377 Xapian::RSet myrset;
2378 myrset.add_document(2);
2380 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
2382 mset_expect_order(mymset1, 1, 2);
2383 // Document 2 should have higher weight than document 1 despite the wdf of
2384 // "people" being 1 because "people" indexes a document in the RSet whereas
2385 // "cuddly" (wdf=2) does not.
2386 mset_expect_order(mymset2, 2, 1);
2388 return true;
2391 // Feature test for Database::get_uuid().
2392 DEFINE_TESTCASE(uuid1, backend && !multi) {
2393 SKIP_TEST_FOR_BACKEND("inmemory");
2394 Xapian::Database db = get_database("apitest_simpledata");
2395 string uuid1 = db.get_uuid();
2396 TEST_EQUAL(uuid1.size(), 36);
2398 // A database with no sub-databases has an empty UUID.
2399 Xapian::Database db2;
2400 TEST(db2.get_uuid().empty());
2402 db2.add_database(db);
2403 TEST_EQUAL(uuid1, db2.get_uuid());
2405 // Multi-database has multiple UUIDs (we don't define the format exactly
2406 // so this assumes something about the implementation).
2407 db2.add_database(db);
2408 TEST_EQUAL(uuid1 + ":" + uuid1, db2.get_uuid());
2410 #ifdef XAPIAN_HAS_INMEMORY_BACKEND
2411 // This relies on InMemory databases not supporting uuids.
2412 // A multi-database containing a database with no uuid has no uuid.
2413 db2.add_database(Xapian::Database(string(), Xapian::DB_BACKEND_INMEMORY));
2414 TEST(db2.get_uuid().empty());
2415 #endif
2417 return true;