Make glass the default backend
[xapian.git] / xapian-core / tests / api_anydb.cc
blob5f3b33b2b5f51b60832e4902955c988e4536a9f8
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 // tests for the right document count for a wildcard query
217 // FIXME: move this to querytest (and just use an InMemory DB).
218 DEFINE_TESTCASE(wildquery1, backend) {
219 Xapian::QueryParser queryparser;
220 unsigned flags = Xapian::QueryParser::FLAG_WILDCARD |
221 Xapian::QueryParser::FLAG_LOVEHATE;
222 queryparser.set_stemmer(Xapian::Stem("english"));
223 queryparser.set_stemming_strategy(Xapian::QueryParser::STEM_ALL);
224 Xapian::Database db = get_database("apitest_simpledata");
225 queryparser.set_database(db);
226 Xapian::Enquire enquire(db);
228 Xapian::Query qobj = queryparser.parse_query("th*", flags);
229 tout << qobj.get_description() << endl;
230 enquire.set_query(qobj);
231 Xapian::MSet mymset = enquire.get_mset(0, 10);
232 // Check that 6 documents were returned.
233 TEST_MSET_SIZE(mymset, 6);
235 qobj = queryparser.parse_query("notindb* \"this\"", flags);
236 tout << qobj.get_description() << endl;
237 enquire.set_query(qobj);
238 mymset = enquire.get_mset(0, 10);
239 // Check that 6 documents were returned.
240 TEST_MSET_SIZE(mymset, 6);
242 qobj = queryparser.parse_query("+notindb* \"this\"", flags);
243 tout << qobj.get_description() << endl;
244 enquire.set_query(qobj);
245 mymset = enquire.get_mset(0, 10);
246 // Check that 0 documents were returned.
247 TEST_MSET_SIZE(mymset, 0);
249 return true;
252 // multidb1 and multidb2 no longer exist.
254 // test that a multidb with 2 dbs query returns correct docids
255 DEFINE_TESTCASE(multidb3, backend && !multi) {
256 Xapian::Database mydb2(get_database("apitest_simpledata"));
257 mydb2.add_database(get_database("apitest_simpledata2"));
258 Xapian::Enquire enquire(mydb2);
260 // make a query
261 Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
262 enquire.set_weighting_scheme(Xapian::BoolWeight());
263 enquire.set_query(myquery);
265 // retrieve the top ten results
266 Xapian::MSet mymset = enquire.get_mset(0, 10);
267 mset_expect_order(mymset, 2, 3, 7);
269 return true;
272 // test that a multidb with 3 dbs query returns correct docids
273 DEFINE_TESTCASE(multidb4, backend && !multi) {
274 Xapian::Database mydb2(get_database("apitest_simpledata"));
275 mydb2.add_database(get_database("apitest_simpledata2"));
276 mydb2.add_database(get_database("apitest_termorder"));
277 Xapian::Enquire enquire(mydb2);
279 // make a query
280 Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
281 enquire.set_weighting_scheme(Xapian::BoolWeight());
282 enquire.set_query(myquery);
284 // retrieve the top ten results
285 Xapian::MSet mymset = enquire.get_mset(0, 10);
286 mset_expect_order(mymset, 2, 3, 4, 10);
288 return true;
291 // tests MultiPostList::skip_to().
292 DEFINE_TESTCASE(multidb5, backend && !multi) {
293 Xapian::Database mydb2(get_database("apitest_simpledata"));
294 mydb2.add_database(get_database("apitest_simpledata2"));
295 Xapian::Enquire enquire(mydb2);
297 // make a query
298 Xapian::Query myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
299 enquire.set_weighting_scheme(Xapian::BoolWeight());
300 enquire.set_query(myquery);
302 // retrieve the top ten results
303 Xapian::MSet mymset = enquire.get_mset(0, 10);
304 mset_expect_order(mymset, 2);
306 return true;
309 // tests that when specifying maxitems to get_mset, no more than
310 // that are returned.
311 DEFINE_TESTCASE(msetmaxitems1, backend) {
312 Xapian::Enquire enquire(get_database("apitest_simpledata"));
313 enquire.set_query(query("this"));
314 Xapian::MSet mymset = enquire.get_mset(0, 1);
315 TEST_MSET_SIZE(mymset, 1);
317 mymset = enquire.get_mset(0, 5);
318 TEST_MSET_SIZE(mymset, 5);
320 return true;
323 // tests the returned weights are as expected (regression test for remote
324 // backend which was using the average weight rather than the actual document
325 // weight for computing weights - fixed in 1.0.0).
326 DEFINE_TESTCASE(expandweights1, backend) {
327 Xapian::Enquire enquire(get_database("apitest_simpledata"));
328 enquire.set_query(Xapian::Query("this"));
330 Xapian::MSet mymset = enquire.get_mset(0, 10);
332 Xapian::RSet myrset;
333 Xapian::MSetIterator i = mymset.begin();
334 myrset.add_document(*i);
335 myrset.add_document(*(++i));
337 Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
338 TEST_EQUAL(eset.size(), 3);
339 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
340 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
341 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
343 // Test non-default k too.
344 eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ, 2.0);
345 TEST_EQUAL(eset.size(), 3);
346 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 5.88109547674955);
347 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 5.88109547674955);
348 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.44473599216144);
350 return true;
353 // Just like test_expandweights1 but without USE_EXACT_TERMFREQ.
354 DEFINE_TESTCASE(expandweights2, backend) {
355 Xapian::Enquire enquire(get_database("apitest_simpledata"));
356 enquire.set_query(Xapian::Query("this"));
358 Xapian::MSet mymset = enquire.get_mset(0, 10);
360 Xapian::RSet myrset;
361 Xapian::MSetIterator i = mymset.begin();
362 myrset.add_document(*i);
363 myrset.add_document(*(++i));
365 Xapian::ESet eset = enquire.get_eset(3, myrset);
366 TEST_EQUAL(eset.size(), 3);
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);
381 return true;
384 DEFINE_TESTCASE(expandweights3, backend) {
385 Xapian::Enquire enquire(get_database("apitest_simpledata"));
386 enquire.set_query(Xapian::Query("this"));
388 Xapian::MSet mymset = enquire.get_mset(0, 10);
390 Xapian::RSet myrset;
391 Xapian::MSetIterator i = mymset.begin();
392 myrset.add_document(*i);
393 myrset.add_document(*(++i));
395 // Set min_wt to 0.0
396 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 0, 0.0);
397 if (!startswith(get_dbtype(), "multi")) {
398 // For a single database, the weights should be the same with or
399 // without USE_EXACT_TERMFREQ.
400 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
401 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
402 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
403 } else {
404 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
405 // will result in different weights in some cases.
406 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
407 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
408 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
410 TEST_REL(eset.back().get_weight(),>=,0);
412 return true;
416 // tests that negative weights are returned
417 DEFINE_TESTCASE(expandweights4, backend) {
418 Xapian::Enquire enquire(get_database("apitest_simpledata"));
419 enquire.set_query(Xapian::Query("paragraph"));
421 Xapian::MSet mymset = enquire.get_mset(0, 10);
423 Xapian::RSet myrset;
424 Xapian::MSetIterator i = mymset.begin();
425 myrset.add_document(*i);
426 myrset.add_document(*(++i));
428 Xapian::ESet eset = enquire.get_eset(37, myrset, 0, 0, -100);
429 // Now include negative weights
430 TEST_EQUAL(eset.size(), 37);
431 TEST_REL(eset[36].get_weight(),<,0);
432 TEST_REL(eset[36].get_weight(),>=,-100);
434 return true;
437 // test for Bo1EWeight
438 DEFINE_TESTCASE(expandweights5, backend) {
439 Xapian::Enquire enquire(get_database("apitest_simpledata"));
440 enquire.set_query(Xapian::Query("this"));
442 Xapian::MSet mymset = enquire.get_mset(0, 10);
444 Xapian::RSet myrset;
445 Xapian::MSetIterator i = mymset.begin();
446 myrset.add_document(*i);
447 myrset.add_document(*(++i));
449 enquire.set_expansion_scheme("bo1");
450 Xapian::ESet eset = enquire.get_eset(3, myrset);
452 TEST_EQUAL(eset.size(), 3);
453 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 7.21765284821702);
454 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.661623193760022);
455 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 5.58090119783738);
457 return true;
460 // test that "trad" can be set as an expansion scheme.
461 DEFINE_TESTCASE(expandweights6, backend) {
462 Xapian::Enquire enquire(get_database("apitest_simpledata"));
463 enquire.set_query(Xapian::Query("this"));
465 Xapian::MSet mymset = enquire.get_mset(0, 10);
467 Xapian::RSet myrset;
468 Xapian::MSetIterator i = mymset.begin();
469 myrset.add_document(*i);
470 myrset.add_document(*(++i));
472 enquire.set_expansion_scheme("trad");
473 Xapian::ESet eset = enquire.get_eset(3, myrset, enquire.USE_EXACT_TERMFREQ);
475 TEST_EQUAL(eset.size(), 3);
476 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
477 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
478 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
480 return true;
483 // test that invalid scheme names are not accepted
484 DEFINE_TESTCASE(expandweights7, backend) {
485 Xapian::Enquire enquire(get_database("apitest_simpledata"));
487 TEST_EXCEPTION(Xapian::InvalidArgumentError,
488 enquire.set_expansion_scheme("no_such_scheme"));
490 return true;
493 // test that "expand_k" can be passed as a parameter to get_eset
494 DEFINE_TESTCASE(expandweights8, backend) {
495 Xapian::Enquire enquire(get_database("apitest_simpledata"));
496 enquire.set_query(Xapian::Query("this"));
498 Xapian::MSet mymset = enquire.get_mset(0, 10);
500 Xapian::RSet myrset;
501 Xapian::MSetIterator i = mymset.begin();
502 myrset.add_document(*i);
503 myrset.add_document(*(++i));
505 // Set expand_k to 1.0 and min_wt to 0
506 Xapian::ESet eset = enquire.get_eset(50, myrset, 0, 1.0, 0, 0);
507 if (!startswith(get_dbtype(), "multi")) {
508 // For a single database, the weights should be the same with or
509 // without USE_EXACT_TERMFREQ.
510 TEST_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
511 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
512 TEST_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
513 } else {
514 // For multiple databases, we expect that using USE_EXACT_TERMFREQ
515 // will result in different weights in some cases.
516 TEST_NOT_EQUAL_DOUBLE(eset[0].get_weight(), 6.08904001099445);
517 TEST_EQUAL_DOUBLE(eset[1].get_weight(), 6.08904001099445);
518 TEST_NOT_EQUAL_DOUBLE(eset[2].get_weight(), 4.73383620844021);
520 TEST_REL(eset.back().get_weight(),>=,0);
522 return true;
525 // tests that when specifying maxitems to get_eset, no more than
526 // that are returned.
527 DEFINE_TESTCASE(expandmaxitems1, backend) {
528 Xapian::Enquire enquire(get_database("apitest_simpledata"));
529 enquire.set_query(Xapian::Query("this"));
531 Xapian::MSet mymset = enquire.get_mset(0, 10);
532 tout << "mymset.size() = " << mymset.size() << endl;
533 TEST(mymset.size() >= 2);
535 Xapian::RSet myrset;
536 Xapian::MSetIterator i = mymset.begin();
537 myrset.add_document(*i);
538 myrset.add_document(*(++i));
540 Xapian::ESet myeset = enquire.get_eset(1, myrset);
541 TEST_EQUAL(myeset.size(), 1);
543 return true;
546 // tests that a pure boolean query has all weights set to 0
547 DEFINE_TESTCASE(boolquery1, backend) {
548 Xapian::Query myboolquery(query("this"));
550 // open the database (in this case a simple text file
551 // we prepared earlier)
552 Xapian::Enquire enquire(get_database("apitest_simpledata"));
553 enquire.set_query(myboolquery);
554 enquire.set_weighting_scheme(Xapian::BoolWeight());
556 // retrieve the top results
557 Xapian::MSet mymset = enquire.get_mset(0, 10);
559 TEST_NOT_EQUAL(mymset.size(), 0);
560 TEST_EQUAL(mymset.get_max_possible(), 0);
561 for (Xapian::MSetIterator i = mymset.begin(); i != mymset.end(); ++i) {
562 TEST_EQUAL(i.get_weight(), 0);
564 return true;
567 // tests that get_mset() specifying "this" works as expected
568 DEFINE_TESTCASE(msetfirst1, backend) {
569 Xapian::Enquire enquire(get_database("apitest_simpledata"));
570 enquire.set_query(query("this"));
571 Xapian::MSet mymset1 = enquire.get_mset(0, 6);
572 Xapian::MSet mymset2 = enquire.get_mset(3, 3);
573 TEST(mset_range_is_same(mymset1, 3, mymset2, 0, 3));
575 // Regression test - we weren't adjusting the index into items[] by
576 // firstitem in api/omenquire.cc.
577 TEST_EQUAL(mymset1[5].get_document().get_data(),
578 mymset2[2].get_document().get_data());
579 return true;
582 // tests the converting-to-percent functions
583 DEFINE_TESTCASE(topercent1, backend) {
584 Xapian::Enquire enquire(get_database("apitest_simpledata"));
585 enquire.set_query(query("this"));
586 Xapian::MSet mymset = enquire.get_mset(0, 20);
588 int last_pct = 100;
589 Xapian::MSetIterator i = mymset.begin();
590 for ( ; i != mymset.end(); ++i) {
591 int pct = mymset.convert_to_percent(i);
592 TEST_AND_EXPLAIN(pct == i.get_percent(),
593 "convert_to_%(msetitor) != convert_to_%(wt)");
594 TEST_AND_EXPLAIN(pct == mymset.convert_to_percent(i.get_weight()),
595 "convert_to_%(msetitor) != convert_to_%(wt)");
596 TEST_AND_EXPLAIN(pct >= 0 && pct <= 100,
597 "percentage out of range: " << pct);
598 TEST_AND_EXPLAIN(pct <= last_pct, "percentage increased down mset");
599 last_pct = pct;
601 return true;
604 // tests the percentage values returned
605 DEFINE_TESTCASE(topercent2, backend) {
606 BackendManagerLocal local_manager;
607 local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
608 Xapian::Enquire localenq(local_manager.get_database("apitest_simpledata"));
609 Xapian::Enquire enquire(get_database("apitest_simpledata"));
611 int pct;
613 // First, test a search in which the top document scores 100%.
614 enquire.set_query(query("this"));
615 localenq.set_query(query("this"));
616 Xapian::MSet mymset = enquire.get_mset(0, 20);
617 Xapian::MSet localmset = localenq.get_mset(0, 20);
619 Xapian::MSetIterator i = mymset.begin();
620 TEST(i != mymset.end());
621 pct = mymset.convert_to_percent(i);
622 TEST_EQUAL(pct, 100);
624 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
625 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
626 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
627 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
628 TEST_EQUAL(mymset.size(), localmset.size());
629 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
631 // A search in which the top document doesn't have 100%
632 Xapian::Query q = query(Xapian::Query::OP_OR,
633 "this", "line", "paragraph", "rubbish");
634 enquire.set_query(q);
635 localenq.set_query(q);
636 mymset = enquire.get_mset(0, 20);
637 localmset = localenq.get_mset(0, 20);
639 i = mymset.begin();
640 TEST(i != mymset.end());
641 pct = mymset.convert_to_percent(i);
642 TEST_REL(pct,>,60);
643 TEST_REL(pct,<,76);
645 ++i;
647 TEST(i != mymset.end());
648 pct = mymset.convert_to_percent(i);
649 TEST_REL(pct,>,40);
650 TEST_REL(pct,<,50);
652 TEST_EQUAL(mymset.get_matches_lower_bound(), localmset.get_matches_lower_bound());
653 TEST_EQUAL(mymset.get_matches_upper_bound(), localmset.get_matches_upper_bound());
654 TEST_EQUAL(mymset.get_matches_estimated(), localmset.get_matches_estimated());
655 TEST_EQUAL_DOUBLE(mymset.get_max_attained(), localmset.get_max_attained());
656 TEST_EQUAL(mymset.size(), localmset.size());
657 TEST(mset_range_is_same(mymset, 0, localmset, 0, mymset.size()));
659 return true;
662 class myExpandFunctor : public Xapian::ExpandDecider {
663 public:
664 bool operator()(const string & tname) const {
665 unsigned long sum = 0;
666 for (string::const_iterator i=tname.begin(); i!=tname.end(); ++i) {
667 sum += *i;
669 // if (verbose) {
670 // tout << tname << "==> " << sum << "\n";
671 // }
672 return (sum % 2) == 0;
676 // tests the expand decision functor
677 DEFINE_TESTCASE(expandfunctor1, backend) {
678 Xapian::Enquire enquire(get_database("apitest_simpledata"));
679 enquire.set_query(Xapian::Query("this"));
681 Xapian::MSet mymset = enquire.get_mset(0, 10);
682 TEST(mymset.size() >= 2);
684 Xapian::RSet myrset;
685 Xapian::MSetIterator i = mymset.begin();
686 myrset.add_document(*i);
687 myrset.add_document(*(++i));
689 myExpandFunctor myfunctor;
691 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
692 unsigned int neweset_size = 0;
693 Xapian::ESetIterator j = myeset_orig.begin();
694 for ( ; j != myeset_orig.end(); ++j) {
695 if (myfunctor(*j)) neweset_size++;
697 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
699 #if 0
700 // Compare myeset with the hand-filtered version of myeset_orig.
701 if (verbose) {
702 tout << "orig_eset: ";
703 copy(myeset_orig.begin(), myeset_orig.end(),
704 ostream_iterator<Xapian::ESetItem>(tout, " "));
705 tout << "\n";
707 tout << "new_eset: ";
708 copy(myeset.begin(), myeset.end(),
709 ostream_iterator<Xapian::ESetItem>(tout, " "));
710 tout << "\n";
712 #endif
713 Xapian::ESetIterator orig = myeset_orig.begin();
714 Xapian::ESetIterator filt = myeset.begin();
715 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
716 // skip over items that shouldn't be in myeset
717 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
718 ++orig;
721 TEST_AND_EXPLAIN(*orig == *filt &&
722 orig.get_weight() == filt.get_weight(),
723 "Mismatch in items " << *orig << " vs. " << *filt
724 << " after filtering");
727 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
728 ++orig;
731 TEST_EQUAL(orig, myeset_orig.end());
732 TEST_AND_EXPLAIN(filt == myeset.end(),
733 "Extra items in the filtered eset.");
734 return true;
737 DEFINE_TESTCASE(expanddeciderfilterprefix2, backend) {
738 Xapian::Enquire enquire(get_database("apitest_simpledata"));
739 enquire.set_query(Xapian::Query("this"));
741 Xapian::MSet mymset = enquire.get_mset(0, 10);
742 TEST(mymset.size() >= 2);
744 Xapian::RSet myrset;
745 Xapian::MSetIterator i = mymset.begin();
746 myrset.add_document(*i);
747 myrset.add_document(*(++i));
749 Xapian::ESet myeset_orig = enquire.get_eset(1000, myrset);
750 unsigned int neweset_size = 0;
752 // Choose the first char in the first term as prefix.
753 Xapian::ESetIterator j = myeset_orig.begin();
754 TEST(myeset_orig.size() >= 1);
755 string prefix(*j, 0, 1);
756 Xapian::ExpandDeciderFilterPrefix myfunctor(prefix);
758 for ( ; j != myeset_orig.end(); ++j) {
759 if (myfunctor(*j)) neweset_size++;
761 Xapian::ESet myeset = enquire.get_eset(neweset_size, myrset, &myfunctor);
763 Xapian::ESetIterator orig = myeset_orig.begin();
764 Xapian::ESetIterator filt = myeset.begin();
765 for (; orig != myeset_orig.end() && filt != myeset.end(); ++orig, ++filt) {
766 // skip over items that shouldn't be in myeset
767 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
768 ++orig;
771 TEST_AND_EXPLAIN(*orig == *filt &&
772 orig.get_weight() == filt.get_weight(),
773 "Mismatch in items " << *orig << " vs. " << *filt
774 << " after filtering");
777 while (orig != myeset_orig.end() && !myfunctor(*orig)) {
778 ++orig;
781 TEST_EQUAL(orig, myeset_orig.end());
782 TEST_AND_EXPLAIN(filt == myeset.end(),
783 "Extra items in the filtered eset.");
785 return true;
788 // tests the percent cutoff option
789 DEFINE_TESTCASE(pctcutoff1, backend) {
790 Xapian::Enquire enquire(get_database("apitest_simpledata"));
791 enquire.set_query(query(Xapian::Query::OP_OR,
792 "this", "line", "paragraph", "rubbish"));
793 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
795 if (verbose) {
796 tout << "Original mset pcts:";
797 print_mset_percentages(mymset1);
798 tout << "\n";
801 unsigned int num_items = 0;
802 int my_pct = 100;
803 int changes = 0;
804 Xapian::MSetIterator i = mymset1.begin();
805 int c = 0;
806 for ( ; i != mymset1.end(); ++i, ++c) {
807 int new_pct = mymset1.convert_to_percent(i);
808 if (new_pct != my_pct) {
809 changes++;
810 if (changes > 3) break;
811 num_items = c;
812 my_pct = new_pct;
816 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
817 if (verbose) {
818 tout << "Cutoff percent: " << my_pct << "\n";
821 enquire.set_cutoff(my_pct);
822 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
824 if (verbose) {
825 tout << "Percentages after cutoff:";
826 print_mset_percentages(mymset2);
827 tout << "\n";
830 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
831 "Match with % cutoff lost too many items");
833 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
834 (mymset2.convert_to_percent(mymset2[num_items]) == my_pct &&
835 mymset2.convert_to_percent(mymset2.back()) == my_pct),
836 "Match with % cutoff returned too many items");
838 return true;
841 // Tests the percent cutoff option combined with collapsing
842 DEFINE_TESTCASE(pctcutoff2, backend) {
843 Xapian::Enquire enquire(get_database("apitest_simpledata"));
844 enquire.set_query(Xapian::Query("this"));
845 enquire.set_query(Xapian::Query(Xapian::Query::OP_AND_NOT, Xapian::Query("this"), Xapian::Query("banana")));
846 Xapian::MSet mset = enquire.get_mset(0, 100);
848 if (verbose) {
849 tout << "Original mset pcts:";
850 print_mset_percentages(mset);
851 tout << "\n";
854 TEST(mset.size() >= 2);
855 TEST(mset[0].get_percent() - mset[1].get_percent() >= 2);
857 int cutoff = mset[0].get_percent() + mset[1].get_percent();
858 cutoff /= 2;
860 enquire.set_cutoff(cutoff);
861 enquire.set_collapse_key(1234); // Value which is always empty.
863 Xapian::MSet mset2 = enquire.get_mset(0, 1);
864 TEST_EQUAL(mset2.size(), 1);
865 TEST_EQUAL(mset2.get_matches_lower_bound(), 1);
866 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),>=,1);
867 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset.size());
868 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset.size());
869 TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
870 TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,mset2.get_uncollapsed_matches_estimated());
872 return true;
875 // Test that the percent cutoff option returns all the answers it should.
876 DEFINE_TESTCASE(pctcutoff3, backend) {
877 Xapian::Enquire enquire(get_database("apitest_simpledata"));
878 enquire.set_query(Xapian::Query("this"));
879 Xapian::MSet mset1 = enquire.get_mset(0, 10);
881 if (verbose) {
882 tout << "Original mset pcts:";
883 print_mset_percentages(mset1);
884 tout << "\n";
887 int percent = 100;
888 for (Xapian::MSetIterator i = mset1.begin(); i != mset1.end(); ++i) {
889 int new_percent = mset1.convert_to_percent(i);
890 if (new_percent != percent) {
891 enquire.set_cutoff(percent);
892 Xapian::MSet mset2 = enquire.get_mset(0, 10);
893 TEST_EQUAL(mset2.size(), i.get_rank());
894 percent = new_percent;
898 return true;
901 // tests the cutoff option
902 DEFINE_TESTCASE(cutoff1, backend) {
903 Xapian::Enquire enquire(get_database("apitest_simpledata"));
904 enquire.set_query(query(Xapian::Query::OP_OR,
905 "this", "line", "paragraph", "rubbish"));
906 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
908 if (verbose) {
909 tout << "Original mset weights:";
910 print_mset_weights(mymset1);
911 tout << "\n";
914 unsigned int num_items = 0;
915 double my_wt = -100;
916 int changes = 0;
917 Xapian::MSetIterator i = mymset1.begin();
918 int c = 0;
919 for ( ; i != mymset1.end(); ++i, ++c) {
920 double new_wt = i.get_weight();
921 if (new_wt != my_wt) {
922 changes++;
923 if (changes > 3) break;
924 num_items = c;
925 my_wt = new_wt;
929 TEST_AND_EXPLAIN(changes > 3, "MSet not varied enough to test");
930 if (verbose) {
931 tout << "Cutoff weight: " << my_wt << "\n";
934 enquire.set_cutoff(0, my_wt);
935 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
937 if (verbose) {
938 tout << "Weights after cutoff:";
939 print_mset_weights(mymset2);
940 tout << "\n";
943 TEST_AND_EXPLAIN(mymset2.size() >= num_items,
944 "Match with cutoff lost too many items");
946 TEST_AND_EXPLAIN(mymset2.size() == num_items ||
947 (mymset2[num_items].get_weight() == my_wt &&
948 mymset2.back().get_weight() == my_wt),
949 "Match with cutoff returned too many items");
951 return true;
954 // tests the allow query terms expand option
955 DEFINE_TESTCASE(allowqterms1, backend) {
956 Xapian::Enquire enquire(get_database("apitest_simpledata"));
957 string term = "paragraph";
958 enquire.set_query(Xapian::Query(term));
960 Xapian::MSet mymset = enquire.get_mset(0, 10);
961 TEST(mymset.size() >= 2);
963 Xapian::RSet myrset;
964 Xapian::MSetIterator i = mymset.begin();
965 myrset.add_document(*i);
966 myrset.add_document(*(++i));
968 Xapian::ESet myeset = enquire.get_eset(1000, myrset);
969 Xapian::ESetIterator j = myeset.begin();
970 for ( ; j != myeset.end(); ++j) {
971 TEST_NOT_EQUAL(*j, term);
974 Xapian::ESet myeset2 = enquire.get_eset(1000, myrset, Xapian::Enquire::INCLUDE_QUERY_TERMS);
975 j = myeset2.begin();
976 for ( ; j != myeset2.end(); ++j) {
977 if (*j == term) break;
979 TEST(j != myeset2.end());
980 return true;
983 // tests that the MSet max_attained works
984 DEFINE_TESTCASE(maxattain1, backend) {
985 Xapian::Enquire enquire(get_database("apitest_simpledata"));
986 enquire.set_query(query("this"));
987 Xapian::MSet mymset = enquire.get_mset(0, 100);
989 double mymax = 0;
990 Xapian::MSetIterator i = mymset.begin();
991 for ( ; i != mymset.end(); ++i) {
992 if (i.get_weight() > mymax) mymax = i.get_weight();
994 TEST_EQUAL(mymax, mymset.get_max_attained());
996 return true;
999 // tests a reversed boolean query
1000 DEFINE_TESTCASE(reversebool1, backend) {
1001 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1002 enquire.set_query(Xapian::Query("this"));
1003 enquire.set_weighting_scheme(Xapian::BoolWeight());
1005 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
1006 TEST_AND_EXPLAIN(mymset1.size() > 1,
1007 "Mset was too small to test properly");
1009 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1010 Xapian::MSet mymset2 = enquire.get_mset(0, 100);
1011 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1012 Xapian::MSet mymset3 = enquire.get_mset(0, 100);
1014 // mymset1 and mymset2 should be identical
1015 TEST_EQUAL(mymset1.size(), mymset2.size());
1018 Xapian::MSetIterator i = mymset1.begin();
1019 Xapian::MSetIterator j = mymset2.begin();
1020 for ( ; i != mymset1.end(); ++i, j++) {
1021 TEST(j != mymset2.end());
1022 // if this fails, then setting match_sort_forward=true was not
1023 // the same as the default.
1024 TEST_EQUAL(*i, *j);
1026 TEST(j == mymset2.end());
1029 // mymset1 and mymset3 should be same but reversed
1030 TEST_EQUAL(mymset1.size(), mymset3.size());
1033 Xapian::MSetIterator i = mymset1.begin();
1034 Xapian::MSetIterator j = mymset3.end();
1035 for ( ; i != mymset1.end(); ++i) {
1036 // if this fails, then setting match_sort_forward=false didn't
1037 // reverse the results.
1038 TEST_EQUAL(*i, *--j);
1042 return true;
1045 // tests a reversed boolean query, where the full mset isn't returned
1046 DEFINE_TESTCASE(reversebool2, backend) {
1047 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1048 enquire.set_query(Xapian::Query("this"));
1049 enquire.set_weighting_scheme(Xapian::BoolWeight());
1051 Xapian::MSet mymset1 = enquire.get_mset(0, 100);
1053 TEST_AND_EXPLAIN(mymset1.size() > 1,
1054 "Mset was too small to test properly");
1056 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1057 Xapian::doccount msize = mymset1.size() / 2;
1058 Xapian::MSet mymset2 = enquire.get_mset(0, msize);
1059 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1060 Xapian::MSet mymset3 = enquire.get_mset(0, msize);
1062 // mymset2 should be first msize items of mymset1
1063 TEST_EQUAL(msize, mymset2.size());
1065 Xapian::MSetIterator i = mymset1.begin();
1066 Xapian::MSetIterator j = mymset2.begin();
1067 for ( ; j != mymset2.end(); ++i, j++) {
1068 TEST(i != mymset1.end());
1069 // if this fails, then setting match_sort_forward=true was not
1070 // the same as the default.
1071 TEST_EQUAL(*i, *j);
1073 // mymset1 should be larger.
1074 TEST(i != mymset1.end());
1077 // mymset3 should be last msize items of mymset1, in reverse order
1078 TEST_EQUAL(msize, mymset3.size());
1080 Xapian::MSetIterator i = mymset1.end();
1081 Xapian::MSetIterator j;
1082 for (j = mymset3.begin(); j != mymset3.end(); j++) {
1083 // if this fails, then setting match_sort_forward=false didn't
1084 // reverse the results.
1085 TEST_EQUAL(*--i, *j);
1089 return true;
1092 // tests that get_matching_terms() returns the terms in the right order
1093 DEFINE_TESTCASE(getmterms1, backend) {
1094 list<string> answers_list;
1095 answers_list.push_back("one");
1096 answers_list.push_back("two");
1097 answers_list.push_back("three");
1098 answers_list.push_back("four");
1100 Xapian::Database mydb(get_database("apitest_termorder"));
1101 Xapian::Enquire enquire(mydb);
1103 Xapian::Query myquery(Xapian::Query::OP_OR,
1104 Xapian::Query(Xapian::Query::OP_AND,
1105 Xapian::Query("one", 1, 1),
1106 Xapian::Query("three", 1, 3)),
1107 Xapian::Query(Xapian::Query::OP_OR,
1108 Xapian::Query("four", 1, 4),
1109 Xapian::Query("two", 1, 2)));
1111 enquire.set_query(myquery);
1113 Xapian::MSet mymset = enquire.get_mset(0, 10);
1115 TEST_MSET_SIZE(mymset, 1);
1116 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1117 enquire.get_matching_terms_end(mymset.begin()));
1118 TEST(list == answers_list);
1120 return true;
1123 // tests that get_matching_terms() returns the terms only once
1124 DEFINE_TESTCASE(getmterms2, backend) {
1125 list<string> answers_list;
1126 answers_list.push_back("one");
1127 answers_list.push_back("two");
1128 answers_list.push_back("three");
1130 Xapian::Database mydb(get_database("apitest_termorder"));
1131 Xapian::Enquire enquire(mydb);
1133 Xapian::Query myquery(Xapian::Query::OP_OR,
1134 Xapian::Query(Xapian::Query::OP_AND,
1135 Xapian::Query("one", 1, 1),
1136 Xapian::Query("three", 1, 3)),
1137 Xapian::Query(Xapian::Query::OP_OR,
1138 Xapian::Query("one", 1, 4),
1139 Xapian::Query("two", 1, 2)));
1141 enquire.set_query(myquery);
1143 Xapian::MSet mymset = enquire.get_mset(0, 10);
1145 TEST_MSET_SIZE(mymset, 1);
1146 list<string> list(enquire.get_matching_terms_begin(mymset.begin()),
1147 enquire.get_matching_terms_end(mymset.begin()));
1148 TEST(list == answers_list);
1150 return true;
1153 // test that running a query twice returns the same results
1154 DEFINE_TESTCASE(repeatquery1, backend) {
1155 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1156 enquire.set_query(Xapian::Query("this"));
1158 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1160 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1161 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1162 TEST_EQUAL(mymset1, mymset2);
1164 return true;
1167 // test that prefetching documents works (at least, gives same results)
1168 DEFINE_TESTCASE(fetchdocs1, backend) {
1169 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1170 enquire.set_query(Xapian::Query("this"));
1172 enquire.set_query(query(Xapian::Query::OP_OR, "this", "word"));
1174 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1175 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1176 TEST_EQUAL(mymset1, mymset2);
1177 mymset2.fetch(mymset2[0], mymset2[mymset2.size() - 1]);
1178 mymset2.fetch(mymset2.begin(), mymset2.end());
1179 mymset2.fetch(mymset2.begin());
1180 mymset2.fetch();
1182 Xapian::MSetIterator it1 = mymset1.begin();
1183 Xapian::MSetIterator it2 = mymset2.begin();
1185 while (it1 != mymset1.end() && it2 != mymset2.end()) {
1186 TEST_EQUAL(it1.get_document().get_data(),
1187 it2.get_document().get_data());
1188 TEST_NOT_EQUAL(it1.get_document().get_data(), "");
1189 TEST_NOT_EQUAL(it2.get_document().get_data(), "");
1190 it1++;
1191 it2++;
1193 TEST_EQUAL(it1, mymset1.end());
1194 TEST_EQUAL(it1, mymset2.end());
1196 return true;
1199 // test that searching for a term not in the database fails nicely
1200 DEFINE_TESTCASE(absentterm1, backend) {
1201 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1202 enquire.set_weighting_scheme(Xapian::BoolWeight());
1203 enquire.set_query(Xapian::Query("frink"));
1205 Xapian::MSet mymset = enquire.get_mset(0, 10);
1206 mset_expect_order(mymset);
1208 return true;
1211 // as absentterm1, but setting query from a vector of terms
1212 DEFINE_TESTCASE(absentterm2, backend) {
1213 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1214 vector<string> terms;
1215 terms.push_back("frink");
1217 Xapian::Query query(Xapian::Query::OP_OR, terms.begin(), terms.end());
1218 enquire.set_query(query);
1220 Xapian::MSet mymset = enquire.get_mset(0, 10);
1221 mset_expect_order(mymset);
1223 return true;
1226 // test that rsets do sensible things
1227 DEFINE_TESTCASE(rset1, backend) {
1228 Xapian::Database mydb(get_database("apitest_rset"));
1229 Xapian::Enquire enquire(mydb);
1230 Xapian::Query myquery = query(Xapian::Query::OP_OR, "giraffe", "tiger");
1231 enquire.set_query(myquery);
1233 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1235 Xapian::RSet myrset;
1236 myrset.add_document(1);
1238 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1240 // We should have the same documents turn up, but 1 and 3 should
1241 // have higher weights with the RSet.
1242 TEST_MSET_SIZE(mymset1, 3);
1243 TEST_MSET_SIZE(mymset2, 3);
1245 return true;
1248 // test that rsets do more sensible things
1249 DEFINE_TESTCASE(rset2, backend) {
1250 Xapian::Database mydb(get_database("apitest_rset"));
1251 Xapian::Enquire enquire(mydb);
1252 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
1253 enquire.set_query(myquery);
1255 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1257 Xapian::RSet myrset;
1258 myrset.add_document(2);
1260 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
1262 mset_expect_order(mymset1, 1, 2);
1263 mset_expect_order(mymset2, 2, 1);
1265 return true;
1268 // test that rsets behave correctly with multiDBs
1269 DEFINE_TESTCASE(rsetmultidb1, backend && !multi) {
1270 Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1271 Xapian::Database mydb2(get_database("apitest_rset"));
1272 mydb2.add_database(get_database("apitest_simpledata2"));
1274 Xapian::Enquire enquire1(mydb1);
1275 Xapian::Enquire enquire2(mydb2);
1277 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "multiple");
1279 enquire1.set_query(myquery);
1280 enquire2.set_query(myquery);
1282 Xapian::RSet myrset1;
1283 Xapian::RSet myrset2;
1284 myrset1.add_document(4);
1285 myrset2.add_document(2);
1287 Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
1288 Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
1289 Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
1290 Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
1292 mset_expect_order(mymset1a, 1, 4);
1293 mset_expect_order(mymset1b, 4, 1);
1294 mset_expect_order(mymset2a, 1, 2);
1295 mset_expect_order(mymset2b, 2, 1);
1297 TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
1298 TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
1299 TEST_NOT_EQUAL(mymset1a, mymset1b);
1300 TEST_NOT_EQUAL(mymset2a, mymset2b);
1302 return true;
1305 // regression tests - used to cause assertion in stats.h to fail
1306 // Doesn't actually fail for multi but it doesn't make sense to run there.
1307 DEFINE_TESTCASE(rsetmultidb3, backend && !multi) {
1308 Xapian::Enquire enquire(get_database("apitest_simpledata2"));
1309 enquire.set_query(query(Xapian::Query::OP_OR, "cuddly", "people"));
1310 Xapian::MSet mset = enquire.get_mset(0, 10); // used to fail assertion
1311 return true;
1314 /// Simple test of the elite set operator.
1315 DEFINE_TESTCASE(eliteset1, backend) {
1316 Xapian::Database mydb(get_database("apitest_simpledata"));
1317 Xapian::Enquire enquire(mydb);
1319 Xapian::Query myquery1 = query(Xapian::Query::OP_OR, "word");
1321 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1322 "simple", "word");
1324 enquire.set_query(myquery1, 2); // So the query lengths are the same.
1325 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1327 enquire.set_query(myquery2);
1328 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1330 TEST_EQUAL(mymset1, mymset2);
1331 return true;
1334 /// Test that the elite set operator works if the set contains
1335 /// sub-expressions (regression test)
1336 DEFINE_TESTCASE(eliteset2, backend) {
1337 Xapian::Database mydb(get_database("apitest_simpledata"));
1338 Xapian::Enquire enquire(mydb);
1340 Xapian::Query myquery1 = query(Xapian::Query::OP_AND, "word", "search");
1342 vector<Xapian::Query> qs;
1343 qs.push_back(query("this"));
1344 qs.push_back(query(Xapian::Query::OP_AND, "word", "search"));
1345 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET,
1346 qs.begin(), qs.end(), 1);
1348 enquire.set_query(myquery1);
1349 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
1351 enquire.set_query(myquery2);
1352 Xapian::MSet mymset2 = enquire.get_mset(0, 10);
1354 TEST_EQUAL(mymset1, mymset2);
1355 // query lengths differ so mset weights not the same (with some weighting
1356 // parameters)
1357 //test_mset_order_equal(mymset1, mymset2);
1359 return true;
1362 /// Test that elite set doesn't affect query results if we have fewer
1363 /// terms than the threshold
1364 DEFINE_TESTCASE(eliteset3, backend) {
1365 Xapian::Database mydb1(get_database("apitest_simpledata"));
1366 Xapian::Enquire enquire1(mydb1);
1368 Xapian::Database mydb2(get_database("apitest_simpledata"));
1369 Xapian::Enquire enquire2(mydb2);
1371 // make a query
1372 Xapian::Stem stemmer("english");
1374 string term1 = stemmer("word");
1375 string term2 = stemmer("rubbish");
1376 string term3 = stemmer("banana");
1378 vector<string> terms;
1379 terms.push_back(term1);
1380 terms.push_back(term2);
1381 terms.push_back(term3);
1383 Xapian::Query myquery1(Xapian::Query::OP_OR, terms.begin(), terms.end());
1384 enquire1.set_query(myquery1);
1386 Xapian::Query myquery2(Xapian::Query::OP_ELITE_SET, terms.begin(), terms.end(), 3);
1387 enquire2.set_query(myquery2);
1389 // retrieve the results
1390 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1391 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1393 TEST_EQUAL(mymset1.get_termfreq(term1),
1394 mymset2.get_termfreq(term1));
1395 TEST_EQUAL(mymset1.get_termweight(term1),
1396 mymset2.get_termweight(term1));
1397 TEST_EQUAL(mymset1.get_termfreq(term2),
1398 mymset2.get_termfreq(term2));
1399 TEST_EQUAL(mymset1.get_termweight(term2),
1400 mymset2.get_termweight(term2));
1401 TEST_EQUAL(mymset1.get_termfreq(term3),
1402 mymset2.get_termfreq(term3));
1403 TEST_EQUAL(mymset1.get_termweight(term3),
1404 mymset2.get_termweight(term3));
1405 // TEST_EQUAL(mymset1, mymset2);
1407 return true;
1410 /// Test that elite set doesn't pick terms with 0 frequency
1411 DEFINE_TESTCASE(eliteset4, backend) {
1412 Xapian::Database mydb1(get_database("apitest_simpledata"));
1413 Xapian::Enquire enquire1(mydb1);
1415 Xapian::Database mydb2(get_database("apitest_simpledata"));
1416 Xapian::Enquire enquire2(mydb2);
1418 Xapian::Query myquery1 = query("rubbish");
1419 Xapian::Query myquery2 = query(Xapian::Query::OP_ELITE_SET, 1,
1420 "word", "rubbish", "fibble");
1421 enquire1.set_query(myquery1);
1422 enquire2.set_query(myquery2);
1424 // retrieve the results
1425 Xapian::MSet mymset1 = enquire1.get_mset(0, 10);
1426 Xapian::MSet mymset2 = enquire2.get_mset(0, 10);
1428 TEST_NOT_EQUAL(mymset2.size(), 0);
1429 TEST_EQUAL(mymset1, mymset2);
1430 // TEST_EQUAL(mymset1, mymset2);
1432 return true;
1435 /// Regression test for problem with excess precision.
1436 DEFINE_TESTCASE(eliteset5, backend) {
1437 Xapian::Database mydb1(get_database("apitest_simpledata"));
1438 Xapian::Enquire enquire1(mydb1);
1440 vector<string> v;
1441 for (int i = 0; i != 3; ++i) {
1442 v.push_back("simpl");
1443 v.push_back("queri");
1445 v.push_back("rubbish");
1446 v.push_back("rubbish");
1447 v.push_back("rubbish");
1448 v.push_back("word");
1449 v.push_back("word");
1450 v.push_back("word");
1453 Xapian::Query myquery1 = Xapian::Query(Xapian::Query::OP_ELITE_SET,
1454 v.begin(), v.end(), 1);
1455 myquery1 = Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
1456 myquery1,
1457 0.004);
1459 enquire1.set_query(myquery1);
1460 // On architectures with excess precision (or, at least, on x86), the
1461 // following call used to result in a segfault.
1462 enquire1.get_mset(0, 10);
1464 return true;
1467 /// Test that the termfreq returned by termlists is correct.
1468 DEFINE_TESTCASE(termlisttermfreq1, backend) {
1469 Xapian::Database mydb(get_database("apitest_simpledata"));
1470 Xapian::Enquire enquire(mydb);
1471 Xapian::Stem stemmer("english");
1472 Xapian::RSet rset1;
1473 Xapian::RSet rset2;
1474 rset1.add_document(5);
1475 rset2.add_document(6);
1477 Xapian::ESet eset1 = enquire.get_eset(1000, rset1);
1478 Xapian::ESet eset2 = enquire.get_eset(1000, rset2);
1480 // search for weight of term 'another'
1481 string theterm = stemmer("another");
1483 double wt1 = 0;
1484 double wt2 = 0;
1486 Xapian::ESetIterator i = eset1.begin();
1487 for ( ; i != eset1.end(); i++) {
1488 if (*i == theterm) {
1489 wt1 = i.get_weight();
1490 break;
1495 Xapian::ESetIterator i = eset2.begin();
1496 for ( ; i != eset2.end(); i++) {
1497 if (*i == theterm) {
1498 wt2 = i.get_weight();
1499 break;
1504 TEST_NOT_EQUAL(wt1, 0);
1505 TEST_NOT_EQUAL(wt2, 0);
1506 TEST_EQUAL(wt1, wt2);
1508 return true;
1511 /// Test the termfrequency and termweight info returned for query terms
1512 DEFINE_TESTCASE(qterminfo1, backend) {
1513 Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1514 Xapian::Enquire enquire1(mydb1);
1516 Xapian::Database mydb2(get_database("apitest_simpledata"));
1517 mydb2.add_database(get_database("apitest_simpledata2"));
1518 Xapian::Enquire enquire2(mydb2);
1520 // make a query
1521 Xapian::Stem stemmer("english");
1523 string term1 = stemmer("word");
1524 string term2 = stemmer("inmemory");
1525 string term3 = stemmer("flibble");
1527 Xapian::Query myquery(Xapian::Query::OP_OR,
1528 Xapian::Query(term1),
1529 Xapian::Query(Xapian::Query::OP_OR,
1530 Xapian::Query(term2),
1531 Xapian::Query(term3)));
1532 enquire1.set_query(myquery);
1533 enquire2.set_query(myquery);
1535 // retrieve the results
1536 Xapian::MSet mymset1a = enquire1.get_mset(0, 0);
1537 Xapian::MSet mymset2a = enquire2.get_mset(0, 0);
1539 TEST_EQUAL(mymset1a.get_termfreq(term1),
1540 mymset2a.get_termfreq(term1));
1541 TEST_EQUAL(mymset1a.get_termfreq(term2),
1542 mymset2a.get_termfreq(term2));
1543 TEST_EQUAL(mymset1a.get_termfreq(term3),
1544 mymset2a.get_termfreq(term3));
1546 TEST_EQUAL(mymset1a.get_termfreq(term1), 3);
1547 TEST_EQUAL(mymset1a.get_termfreq(term2), 1);
1548 TEST_EQUAL(mymset1a.get_termfreq(term3), 0);
1550 TEST_NOT_EQUAL(mymset1a.get_termweight(term1), 0);
1551 TEST_NOT_EQUAL(mymset1a.get_termweight(term2), 0);
1552 // non-existent terms should have 0 weight.
1553 TEST_EQUAL(mymset1a.get_termweight(term3), 0);
1555 TEST_EQUAL(mymset1a.get_termfreq(stemmer("banana")), 1);
1556 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1557 mymset1a.get_termweight(stemmer("banana")));
1559 TEST_EQUAL(mymset1a.get_termfreq("sponge"), 0);
1560 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1561 mymset1a.get_termweight("sponge"));
1563 return true;
1566 /// Regression test for bug #37.
1567 DEFINE_TESTCASE(qterminfo2, backend) {
1568 Xapian::Database db(get_database("apitest_simpledata"));
1569 Xapian::Enquire enquire(db);
1571 // make a query
1572 Xapian::Stem stemmer("english");
1574 string term1 = stemmer("paragraph");
1575 string term2 = stemmer("another");
1577 Xapian::Query query(Xapian::Query::OP_AND_NOT, term1,
1578 Xapian::Query(Xapian::Query::OP_AND, term1, term2));
1579 enquire.set_query(query);
1581 // retrieve the results
1582 // Note: get_mset() used to throw "AssertionError" in debug builds
1583 Xapian::MSet mset = enquire.get_mset(0, 10);
1585 TEST_NOT_EQUAL(mset.get_termweight("paragraph"), 0);
1587 return true;
1590 // tests that when specifying that no items are to be returned, those
1591 // statistics which should be the same are.
1592 DEFINE_TESTCASE(msetzeroitems1, backend) {
1593 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1594 enquire.set_query(query("this"));
1595 Xapian::MSet mymset1 = enquire.get_mset(0, 0);
1597 Xapian::MSet mymset2 = enquire.get_mset(0, 1);
1599 TEST_EQUAL(mymset1.get_max_possible(), mymset2.get_max_possible());
1601 return true;
1604 // test that the matches_* of a simple query are as expected
1605 DEFINE_TESTCASE(matches1, backend) {
1606 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1607 Xapian::Query myquery;
1608 Xapian::MSet mymset;
1610 myquery = query("word");
1611 enquire.set_query(myquery);
1612 mymset = enquire.get_mset(0, 10);
1613 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1614 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1615 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1616 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1617 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1618 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1620 myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
1621 enquire.set_query(myquery);
1622 mymset = enquire.get_mset(0, 10);
1623 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1624 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1625 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1626 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1627 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1628 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1630 myquery = query(Xapian::Query::OP_AND, "inmemory", "word");
1631 enquire.set_query(myquery);
1632 mymset = enquire.get_mset(0, 10);
1633 TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1634 TEST_EQUAL(mymset.get_matches_estimated(), 0);
1635 TEST_EQUAL(mymset.get_matches_upper_bound(), 0);
1636 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
1637 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 0);
1638 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 0);
1640 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1641 enquire.set_query(myquery);
1642 mymset = enquire.get_mset(0, 10);
1643 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1644 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1645 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1646 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1647 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1648 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1650 myquery = query(Xapian::Query::OP_AND, "simple", "word");
1651 enquire.set_query(myquery);
1652 mymset = enquire.get_mset(0, 0);
1653 // For a single database, this is true, but not for "multi" (since there
1654 // one sub-database has 3 documents and simple and word both have termfreq
1655 // of 2, so the matcher can tell at least one document must match!)
1656 // TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
1657 TEST_REL(mymset.get_matches_lower_bound(),<=,mymset.get_matches_estimated());
1658 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1659 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1660 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,mymset.get_uncollapsed_matches_estimated());
1661 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1662 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1664 mymset = enquire.get_mset(0, 1);
1665 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1666 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1667 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1668 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1669 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1670 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1672 mymset = enquire.get_mset(0, 2);
1673 TEST_EQUAL(mymset.get_matches_lower_bound(), 2);
1674 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1675 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1676 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 2);
1677 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1678 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1680 myquery = query(Xapian::Query::OP_AND, "paragraph", "another");
1681 enquire.set_query(myquery);
1682 mymset = enquire.get_mset(0, 0);
1683 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1684 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1685 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1686 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1687 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1688 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1690 mymset = enquire.get_mset(0, 1);
1691 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1692 TEST_EQUAL(mymset.get_matches_estimated(), 2);
1693 TEST_EQUAL(mymset.get_matches_upper_bound(), 2);
1694 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1695 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 2);
1696 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 2);
1698 mymset = enquire.get_mset(0, 2);
1699 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1700 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1701 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1702 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1703 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1704 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1706 mymset = enquire.get_mset(1, 20);
1707 TEST_EQUAL(mymset.get_matches_lower_bound(), 1);
1708 TEST_EQUAL(mymset.get_matches_estimated(), 1);
1709 TEST_EQUAL(mymset.get_matches_upper_bound(), 1);
1710 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 1);
1711 TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 1);
1712 TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 1);
1714 return true;
1717 // tests that wqf affects the document weights
1718 DEFINE_TESTCASE(wqf1, backend) {
1719 // Both queries have length 2; in q1 word has wqf=2, in q2 word has wqf=1
1720 Xapian::Query q1("word", 2);
1721 Xapian::Query q2("word");
1722 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1723 enquire.set_query(q1);
1724 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1725 enquire.set_query(q2);
1726 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1727 // Check the weights
1728 TEST(mset1.begin().get_weight() > mset2.begin().get_weight());
1729 return true;
1732 // tests that query length affects the document weights
1733 DEFINE_TESTCASE(qlen1, backend) {
1734 Xapian::Query q1("word");
1735 Xapian::Query q2("word");
1736 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1737 enquire.set_query(q1);
1738 Xapian::MSet mset1 = enquire.get_mset(0, 10);
1739 enquire.set_query(q2);
1740 Xapian::MSet mset2 = enquire.get_mset(0, 2);
1741 // Check the weights
1742 //TEST(mset1.begin().get_weight() < mset2.begin().get_weight());
1743 TEST(mset1.begin().get_weight() == mset2.begin().get_weight());
1744 return true;
1747 // tests that opening a non-existent termlist throws the correct exception
1748 DEFINE_TESTCASE(termlist1, backend) {
1749 Xapian::Database db(get_database("apitest_onedoc"));
1750 TEST_EXCEPTION(Xapian::InvalidArgumentError,
1751 Xapian::TermIterator t = db.termlist_begin(0));
1752 TEST_EXCEPTION(Xapian::DocNotFoundError,
1753 Xapian::TermIterator t = db.termlist_begin(2));
1754 /* Cause the database to be used properly, showing up problems
1755 * with the link being in a bad state. CME */
1756 Xapian::TermIterator temp = db.termlist_begin(1);
1757 TEST_EXCEPTION(Xapian::DocNotFoundError,
1758 Xapian::TermIterator t = db.termlist_begin(999999999));
1759 return true;
1762 // tests that a Xapian::TermIterator works as an STL iterator
1763 DEFINE_TESTCASE(termlist2, backend) {
1764 Xapian::Database db(get_database("apitest_onedoc"));
1765 Xapian::TermIterator t = db.termlist_begin(1);
1766 Xapian::TermIterator tend = db.termlist_end(1);
1768 // test operator= creates a copy which compares equal
1769 Xapian::TermIterator t_copy = t;
1770 TEST_EQUAL(t, t_copy);
1772 // test copy constructor creates a copy which compares equal
1773 Xapian::TermIterator t_clone(t);
1774 TEST_EQUAL(t, t_clone);
1776 vector<string> v(t, tend);
1778 t = db.termlist_begin(1);
1779 tend = db.termlist_end(1);
1780 vector<string>::const_iterator i;
1781 for (i = v.begin(); i != v.end(); ++i) {
1782 TEST_NOT_EQUAL(t, tend);
1783 TEST_EQUAL(*i, *t);
1784 t++;
1786 TEST_EQUAL(t, tend);
1787 return true;
1790 static Xapian::TermIterator
1791 test_termlist3_helper()
1793 Xapian::Database db(get_database("apitest_onedoc"));
1794 return db.termlist_begin(1);
1797 // tests that a Xapian::TermIterator still works when the DB is deleted
1798 DEFINE_TESTCASE(termlist3, backend) {
1799 Xapian::TermIterator u = test_termlist3_helper();
1800 Xapian::Database db(get_database("apitest_onedoc"));
1801 Xapian::TermIterator t = db.termlist_begin(1);
1802 Xapian::TermIterator tend = db.termlist_end(1);
1804 while (t != tend) {
1805 TEST_EQUAL(*t, *u);
1806 t++;
1807 u++;
1809 return true;
1812 // tests skip_to
1813 DEFINE_TESTCASE(termlist4, backend) {
1814 Xapian::Database db(get_database("apitest_onedoc"));
1815 Xapian::TermIterator i = db.termlist_begin(1);
1816 i.skip_to("");
1817 i.skip_to("\xff");
1818 return true;
1821 // tests punctuation is OK in terms (particularly in remote queries)
1822 DEFINE_TESTCASE(puncterms1, backend) {
1823 Xapian::Database db(get_database("apitest_punc"));
1824 Xapian::Enquire enquire(db);
1826 Xapian::Query q1("semi;colon");
1827 enquire.set_query(q1);
1828 Xapian::MSet m1 = enquire.get_mset(0, 10);
1830 Xapian::Query q2("col:on");
1831 enquire.set_query(q2);
1832 Xapian::MSet m2 = enquire.get_mset(0, 10);
1834 Xapian::Query q3("com,ma");
1835 enquire.set_query(q3);
1836 Xapian::MSet m3 = enquire.get_mset(0, 10);
1838 return true;
1841 // test that searching for a term with a space or backslash in it works
1842 DEFINE_TESTCASE(spaceterms1, backend) {
1843 Xapian::Enquire enquire(get_database("apitest_space"));
1844 Xapian::MSet mymset;
1845 Xapian::doccount count;
1846 Xapian::MSetIterator m;
1847 Xapian::Stem stemmer("english");
1849 enquire.set_query(stemmer("space man"));
1850 mymset = enquire.get_mset(0, 10);
1851 TEST_MSET_SIZE(mymset, 1);
1852 count = 0;
1853 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1854 TEST_EQUAL(count, 1);
1856 for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
1857 TEST_NOT_EQUAL(mymset.begin().get_document().get_data(), "");
1858 TEST_NOT_EQUAL(mymset.begin().get_document().get_value(value_no), "");
1861 enquire.set_query(stemmer("tab\tby"));
1862 mymset = enquire.get_mset(0, 10);
1863 TEST_MSET_SIZE(mymset, 1);
1864 count = 0;
1865 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1866 TEST_EQUAL(count, 1);
1868 for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
1869 string value = mymset.begin().get_document().get_value(value_no);
1870 TEST_NOT_EQUAL(value, "");
1871 if (value_no == 0) {
1872 TEST(value.size() > 262);
1873 TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
1877 enquire.set_query(stemmer("back\\slash"));
1878 mymset = enquire.get_mset(0, 10);
1879 TEST_MSET_SIZE(mymset, 1);
1880 count = 0;
1881 for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1882 TEST_EQUAL(count, 1);
1884 return true;
1887 // test that XOR queries work
1888 DEFINE_TESTCASE(xor1, 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_weighting_scheme(Xapian::BoolWeight());
1899 enquire.set_query(query);
1901 Xapian::MSet mymset = enquire.get_mset(0, 10);
1902 // Docid this word of Match?
1903 // 1 * *
1904 // 2 * * * *
1905 // 3 * *
1906 // 4 * *
1907 // 5 * *
1908 // 6 * *
1909 mset_expect_order(mymset, 1, 2, 5, 6);
1911 return true;
1914 /// Test that weighted XOR queries work (bug fixed in 1.2.1 and 1.0.21).
1915 DEFINE_TESTCASE(xor2, backend) {
1916 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1917 Xapian::Stem stemmer("english");
1919 vector<string> terms;
1920 terms.push_back(stemmer("this"));
1921 terms.push_back(stemmer("word"));
1922 terms.push_back(stemmer("of"));
1924 Xapian::Query query(Xapian::Query::OP_XOR, terms.begin(), terms.end());
1925 enquire.set_query(query);
1927 Xapian::MSet mymset = enquire.get_mset(0, 10);
1928 // Docid LEN this word of Match?
1929 // 1 28 2 *
1930 // 2 81 5 8 1 *
1931 // 3 15 1 2
1932 // 4 31 1 1
1933 // 5 15 1 *
1934 // 6 15 1 *
1935 mset_expect_order(mymset, 2, 1, 5, 6);
1937 return true;
1940 // test Xapian::Database::get_document()
1941 DEFINE_TESTCASE(getdoc1, backend) {
1942 Xapian::Database db(get_database("apitest_onedoc"));
1943 Xapian::Document doc(db.get_document(1));
1944 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_document(0));
1945 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(999999999));
1946 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(123456789));
1947 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
1948 TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
1949 // Check that Document works as a handle on modification
1950 // (this was broken for the first try at Xapian::Document prior to 0.7).
1951 Xapian::Document doc2 = doc;
1952 doc.set_data("modified!");
1953 TEST_EQUAL(doc.get_data(), "modified!");
1954 TEST_EQUAL(doc.get_data(), doc2.get_data());
1955 return true;
1958 // test whether operators with no elements work as a null query
1959 DEFINE_TESTCASE(emptyop1, backend) {
1960 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1961 vector<Xapian::Query> nullvec;
1963 Xapian::Query query1(Xapian::Query::OP_XOR, nullvec.begin(), nullvec.end());
1965 enquire.set_query(query1);
1966 Xapian::MSet mymset = enquire.get_mset(0, 10);
1967 TEST_MSET_SIZE(mymset, 0);
1968 // In Xapian < 1.3.0, this gave InvalidArgumentError (because
1969 // query1.empty()) but elsewhere we treat an empty query as just not
1970 // matching any documents, so we now do the same here too.
1971 TEST_EQUAL(enquire.get_matching_terms_begin(1),
1972 enquire.get_matching_terms_end(1));
1974 return true;
1977 // Regression test for check_at_least SEGV when there are no matches.
1978 DEFINE_TESTCASE(checkatleast1, backend) {
1979 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1980 enquire.set_query(Xapian::Query("thom"));
1981 Xapian::MSet mymset = enquire.get_mset(0, 10, 11);
1982 TEST_EQUAL(0, mymset.size());
1984 return true;
1987 // Regression test - if check_at_least was set we returned (check_at_least - 1)
1988 // results, rather than the requested msize. Fixed in 1.0.2.
1989 DEFINE_TESTCASE(checkatleast2, backend) {
1990 Xapian::Enquire enquire(get_database("apitest_simpledata"));
1991 enquire.set_query(Xapian::Query("paragraph"));
1993 Xapian::MSet mymset = enquire.get_mset(0, 3, 10);
1994 TEST_MSET_SIZE(mymset, 3);
1995 TEST_EQUAL(mymset.get_matches_lower_bound(), 5);
1996 TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 5);
1998 mymset = enquire.get_mset(0, 2, 4);
1999 TEST_MSET_SIZE(mymset, 2);
2000 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
2001 TEST_REL(mymset.get_matches_lower_bound(),>=,4);
2002 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
2003 TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,4);
2005 return true;
2008 // Feature tests - check_at_least with various sorting options.
2009 DEFINE_TESTCASE(checkatleast3, backend) {
2010 Xapian::Enquire enquire(get_database("etext"));
2011 enquire.set_query(Xapian::Query("prussian")); // 60 matches.
2013 for (int order = 0; order < 3; ++order) {
2014 switch (order) {
2015 case 0:
2016 enquire.set_docid_order(Xapian::Enquire::ASCENDING);
2017 break;
2018 case 1:
2019 enquire.set_docid_order(Xapian::Enquire::DESCENDING);
2020 break;
2021 case 2:
2022 enquire.set_docid_order(Xapian::Enquire::DONT_CARE);
2023 break;
2026 for (int sort = 0; sort < 7; ++sort) {
2027 bool reverse = (sort & 1);
2028 switch (sort) {
2029 case 0:
2030 enquire.set_sort_by_relevance();
2031 break;
2032 case 1: case 2:
2033 enquire.set_sort_by_value(0, reverse);
2034 break;
2035 case 3: case 4:
2036 enquire.set_sort_by_value_then_relevance(0, reverse);
2037 break;
2038 case 5: case 6:
2039 enquire.set_sort_by_relevance_then_value(0, reverse);
2040 break;
2043 Xapian::MSet mset = enquire.get_mset(0, 100, 500);
2044 TEST_MSET_SIZE(mset, 60);
2045 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2046 TEST_EQUAL(mset.get_matches_estimated(), 60);
2047 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2048 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2049 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2050 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2052 mset = enquire.get_mset(0, 50, 100);
2053 TEST_MSET_SIZE(mset, 50);
2054 TEST_EQUAL(mset.get_matches_lower_bound(), 60);
2055 TEST_EQUAL(mset.get_matches_estimated(), 60);
2056 TEST_EQUAL(mset.get_matches_upper_bound(), 60);
2057 TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), 60);
2058 TEST_EQUAL(mset.get_uncollapsed_matches_estimated(), 60);
2059 TEST_EQUAL(mset.get_uncollapsed_matches_upper_bound(), 60);
2061 mset = enquire.get_mset(0, 10, 50);
2062 TEST_MSET_SIZE(mset, 10);
2063 TEST_REL(mset.get_matches_lower_bound(),>=,50);
2064 TEST_REL(mset.get_uncollapsed_matches_lower_bound(),>=,50);
2068 return true;
2071 // tests all document postlists
2072 DEFINE_TESTCASE(allpostlist1, backend) {
2073 Xapian::Database db(get_database("apitest_manydocs"));
2074 Xapian::PostingIterator i = db.postlist_begin("");
2075 unsigned int j = 1;
2076 while (i != db.postlist_end("")) {
2077 TEST_EQUAL(*i, j);
2078 i++;
2079 j++;
2081 TEST_EQUAL(j, 513);
2083 i = db.postlist_begin("");
2084 j = 1;
2085 while (i != db.postlist_end("")) {
2086 TEST_EQUAL(*i, j);
2087 i++;
2088 j++;
2089 if (j == 50) {
2090 j += 10;
2091 i.skip_to(j);
2094 TEST_EQUAL(j, 513);
2096 return true;
2099 static void test_emptyterm1_helper(Xapian::Database & db)
2101 // Don't bother with postlist_begin() because allpostlist tests cover that.
2102 TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
2103 TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
2104 TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
2105 TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
2108 // tests results of passing an empty term to various methods
2109 DEFINE_TESTCASE(emptyterm1, backend) {
2110 Xapian::Database db(get_database("apitest_manydocs"));
2111 TEST_EQUAL(db.get_doccount(), 512);
2112 test_emptyterm1_helper(db);
2114 db = get_database("apitest_onedoc");
2115 TEST_EQUAL(db.get_doccount(), 1);
2116 test_emptyterm1_helper(db);
2118 db = get_database("");
2119 TEST_EQUAL(db.get_doccount(), 0);
2120 test_emptyterm1_helper(db);
2122 return true;
2125 // Test for alldocs postlist with a sparse database.
2126 DEFINE_TESTCASE(alldocspl1, writable) {
2127 Xapian::WritableDatabase db = get_writable_database();
2128 Xapian::Document doc;
2129 doc.set_data("5");
2130 doc.add_value(0, "5");
2131 db.replace_document(5, doc);
2133 Xapian::PostingIterator i = db.postlist_begin("");
2134 TEST(i != db.postlist_end(""));
2135 TEST_EQUAL(*i, 5);
2136 TEST_EQUAL(i.get_doclength(), 0);
2137 TEST_EQUAL(i.get_unique_terms(), 0);
2138 TEST_EQUAL(i.get_wdf(), 1);
2139 ++i;
2140 TEST(i == db.postlist_end(""));
2142 return true;
2145 // Test reading and writing a modified alldocspostlist.
2146 DEFINE_TESTCASE(alldocspl2, writable) {
2147 Xapian::PostingIterator i, end;
2149 Xapian::WritableDatabase db = get_writable_database();
2150 Xapian::Document doc;
2151 doc.set_data("5");
2152 doc.add_value(0, "5");
2153 db.replace_document(5, doc);
2155 // Test iterating before committing the changes.
2156 i = db.postlist_begin("");
2157 end = db.postlist_end("");
2158 TEST(i != end);
2159 TEST_EQUAL(*i, 5);
2160 TEST_EQUAL(i.get_doclength(), 0);
2161 TEST_EQUAL(i.get_unique_terms(), 0);
2162 TEST_EQUAL(i.get_wdf(), 1);
2163 ++i;
2164 TEST(i == end);
2166 db.commit();
2168 // Test iterating after committing the changes.
2169 i = db.postlist_begin("");
2170 end = db.postlist_end("");
2171 TEST(i != end);
2172 TEST_EQUAL(*i, 5);
2173 TEST_EQUAL(i.get_doclength(), 0);
2174 TEST_EQUAL(i.get_unique_terms(), 0);
2175 TEST_EQUAL(i.get_wdf(), 1);
2176 ++i;
2177 TEST(i == end);
2179 // Add another document.
2180 doc = Xapian::Document();
2181 doc.set_data("5");
2182 doc.add_value(0, "7");
2183 db.replace_document(7, doc);
2185 // Test iterating through before committing the changes.
2186 i = db.postlist_begin("");
2187 end = db.postlist_end("");
2188 TEST(i != end);
2189 TEST_EQUAL(*i, 5);
2190 TEST_EQUAL(i.get_doclength(), 0);
2191 TEST_EQUAL(i.get_unique_terms(), 0);
2192 TEST_EQUAL(i.get_wdf(), 1);
2193 ++i;
2194 TEST(i != end);
2195 TEST_EQUAL(*i, 7);
2196 TEST_EQUAL(i.get_doclength(), 0);
2197 TEST_EQUAL(i.get_unique_terms(), 0);
2198 TEST_EQUAL(i.get_wdf(), 1);
2199 ++i;
2200 TEST(i == end);
2202 // Delete the first document.
2203 db.delete_document(5);
2205 // Test iterating through before committing the changes.
2206 i = db.postlist_begin("");
2207 end = db.postlist_end("");
2208 TEST(i != end);
2209 TEST_EQUAL(*i, 7);
2210 TEST_EQUAL(i.get_doclength(), 0);
2211 TEST_EQUAL(i.get_unique_terms(), 0);
2212 TEST_EQUAL(i.get_wdf(), 1);
2213 ++i;
2214 TEST(i == end);
2216 // Test iterating through after committing the changes, and dropping the
2217 // reference to the main DB.
2218 db.commit();
2219 i = db.postlist_begin("");
2220 end = db.postlist_end("");
2223 TEST(i != end);
2224 TEST_EQUAL(*i, 7);
2225 TEST_EQUAL(i.get_doclength(), 0);
2226 TEST_EQUAL(i.get_unique_terms(), 0);
2227 TEST_EQUAL(i.get_wdf(), 1);
2228 ++i;
2229 TEST(i == end);
2231 return true;
2234 // Feature test for Query::OP_SCALE_WEIGHT.
2235 DEFINE_TESTCASE(scaleweight1, backend) {
2236 Xapian::Database db(get_database("apitest_phrase"));
2237 Xapian::Enquire enq(db);
2238 Xapian::QueryParser qp;
2240 static const char * queries[] = {
2241 "pad",
2242 "milk fridge",
2243 "leave milk on fridge",
2244 "ordered milk operator",
2245 "ordered phrase operator",
2246 "leave \"milk on fridge\"",
2247 "notpresent",
2248 "leave \"milk notpresent\"",
2249 NULL
2251 static const double multipliers[] = {
2252 -1000000, -2.5, -1, -0.5, 0, 0.5, 1, 2.5, 1000000,
2253 0, 0
2256 for (const char **qstr = queries; *qstr; ++qstr) {
2257 tout.str(string());
2258 Xapian::Query query1 = qp.parse_query(*qstr);
2259 tout << "query1: " << query1.get_description() << endl;
2260 for (const double *multp = multipliers; multp[0] != multp[1]; ++multp) {
2261 double mult = *multp;
2262 if (mult < 0) {
2263 TEST_EXCEPTION(Xapian::InvalidArgumentError,
2264 Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
2265 query1, mult));
2266 continue;
2268 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, mult);
2269 tout << "query2: " << query2.get_description() << endl;
2271 enq.set_query(query1);
2272 Xapian::MSet mset1 = enq.get_mset(0, 20);
2273 enq.set_query(query2);
2274 Xapian::MSet mset2 = enq.get_mset(0, 20);
2276 TEST_EQUAL(mset1.size(), mset2.size());
2278 Xapian::MSetIterator i1, i2;
2279 if (mult > 0) {
2280 for (i1 = mset1.begin(), i2 = mset2.begin();
2281 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2282 TEST_EQUAL_DOUBLE(i1.get_weight() * mult, i2.get_weight());
2283 TEST_EQUAL(*i1, *i2);
2285 } else {
2286 // Weights in mset2 are 0; so it should be sorted by docid.
2287 vector<Xapian::docid> ids1;
2288 vector<Xapian::docid> ids2;
2289 for (i1 = mset1.begin(), i2 = mset2.begin();
2290 i1 != mset1.end() && i2 != mset2.end(); ++i1, ++i2) {
2291 TEST_NOT_EQUAL_DOUBLE(i1.get_weight(), 0);
2292 TEST_EQUAL_DOUBLE(i2.get_weight(), 0);
2293 ids1.push_back(*i1);
2294 ids2.push_back(*i2);
2296 sort(ids1.begin(), ids1.end());
2297 TEST_EQUAL(ids1, ids2);
2301 return true;
2304 // Test Query::OP_SCALE_WEIGHT being used to multiply some of the weights of a
2305 // search by zero.
2306 DEFINE_TESTCASE(scaleweight2, backend) {
2307 Xapian::Database db(get_database("apitest_phrase"));
2308 Xapian::Enquire enq(db);
2309 Xapian::MSetIterator i;
2311 Xapian::Query query1("fridg");
2312 Xapian::Query query2(Xapian::Query::OP_SCALE_WEIGHT, query1, 2.5);
2313 Xapian::Query query3("milk");
2314 Xapian::Query query4(Xapian::Query::OP_SCALE_WEIGHT, query3, 0);
2315 Xapian::Query query5(Xapian::Query::OP_OR, query2, query4);
2317 // query5 should first return the same results as query1, in the same
2318 // order, and then return the results of query3 which aren't also results
2319 // of query1, in ascending docid order. We test that this happens.
2321 // First, build a vector of docids matching the first part of the query,
2322 // and append the non-duplicate docids matching the second part of the
2323 // query.
2324 vector<Xapian::docid> ids1;
2325 set<Xapian::docid> idsin1;
2326 vector<Xapian::docid> ids3;
2328 enq.set_query(query1);
2329 Xapian::MSet mset1 = enq.get_mset(0, 20);
2330 enq.set_query(query3);
2331 Xapian::MSet mset3 = enq.get_mset(0, 20);
2332 TEST_NOT_EQUAL(mset1.size(), 0);
2333 for (i = mset1.begin(); i != mset1.end(); ++i) {
2334 ids1.push_back(*i);
2335 idsin1.insert(*i);
2337 TEST_NOT_EQUAL(mset3.size(), 0);
2338 for (i = mset3.begin(); i != mset3.end(); ++i) {
2339 if (idsin1.find(*i) != idsin1.end())
2340 continue;
2341 ids3.push_back(*i);
2343 sort(ids3.begin(), ids3.end());
2344 ids1.insert(ids1.end(), ids3.begin(), ids3.end());
2346 // Now, run the combined query and build a vector of the matching docids.
2347 vector<Xapian::docid> ids5;
2348 enq.set_query(query5);
2349 Xapian::MSet mset5 = enq.get_mset(0, 20);
2350 for (i = mset5.begin(); i != mset5.end(); ++i) {
2351 ids5.push_back(*i);
2354 TEST_EQUAL(ids1, ids5);
2355 return true;
2358 // Regression test for bug fixed in 1.0.5 - this test would failed under
2359 // valgrind because it used an uninitialised value.
2360 DEFINE_TESTCASE(bm25weight1, backend) {
2361 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2362 enquire.set_weighting_scheme(Xapian::BM25Weight(1, 25, 1, 0.01, 0.5));
2363 enquire.set_query(Xapian::Query("word") );
2365 Xapian::MSet mset = enquire.get_mset(0, 25);
2367 return true;
2370 // Feature test for TradWeight.
2371 DEFINE_TESTCASE(tradweight1, backend) {
2372 Xapian::Enquire enquire(get_database("apitest_simpledata"));
2373 enquire.set_weighting_scheme(Xapian::TradWeight());
2374 enquire.set_query(Xapian::Query("word") );
2376 Xapian::MSet mset = enquire.get_mset(0, 25);
2377 TEST_EQUAL(mset.size(), 2);
2379 enquire.set_weighting_scheme(Xapian::TradWeight(0));
2380 enquire.set_query(Xapian::Query("this") );
2382 mset = enquire.get_mset(0, 25);
2383 TEST_EQUAL(mset.size(), 6);
2385 // Check that TradWeight(0) means wdf and doc length really don't affect
2386 // the weights as stated in the documentation.
2387 TEST_EQUAL(mset[0].get_weight(), mset[5].get_weight());
2389 return true;
2392 // Test TradWeight when weighting documents using an RSet.
2393 // Simply changed the weighting scheme used by rset2 testcase.
2394 DEFINE_TESTCASE(tradweight4, backend) {
2395 Xapian::Database mydb(get_database("apitest_rset"));
2396 Xapian::Enquire enquire(mydb);
2397 Xapian::Query myquery = query(Xapian::Query::OP_OR, "cuddly", "people");
2399 enquire.set_query(myquery);
2400 enquire.set_weighting_scheme(Xapian::TradWeight());
2402 Xapian::MSet mymset1 = enquire.get_mset(0, 10);
2404 Xapian::RSet myrset;
2405 myrset.add_document(2);
2407 Xapian::MSet mymset2 = enquire.get_mset(0, 10, &myrset);
2409 mset_expect_order(mymset1, 1, 2);
2410 // Document 2 should have higher weight than document 1 despite the wdf of
2411 // "people" being 1 because "people" indexes a document in the RSet whereas
2412 // "cuddly" (wdf=2) does not.
2413 mset_expect_order(mymset2, 2, 1);
2415 return true;
2418 // Feature test for Database::get_uuid().
2419 DEFINE_TESTCASE(uuid1, backend && !multi) {
2420 SKIP_TEST_FOR_BACKEND("inmemory");
2421 Xapian::Database db = get_database("apitest_simpledata");
2422 string uuid1 = db.get_uuid();
2423 TEST_EQUAL(uuid1.size(), 36);
2425 // A database with no sub-databases has an empty UUID.
2426 Xapian::Database db2;
2427 TEST(db2.get_uuid().empty());
2429 db2.add_database(db);
2430 TEST_EQUAL(uuid1, db2.get_uuid());
2432 // Multi-database has multiple UUIDs (we don't define the format exactly
2433 // so this assumes something about the implementation).
2434 db2.add_database(db);
2435 TEST_EQUAL(uuid1 + ":" + uuid1, db2.get_uuid());
2437 #ifdef XAPIAN_HAS_INMEMORY_BACKEND
2438 // This relies on InMemory databases not supporting uuids.
2439 // A multi-database containing a database with no uuid has no uuid.
2440 db2.add_database(Xapian::InMemory::open());
2441 TEST(db2.get_uuid().empty());
2442 #endif
2444 return true;