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