1 /* api_db.cc: tests which need a backend
3 * Copyright 1999,2000,2001 BrightStation PLC
4 * Copyright 2002 Ananova Ltd
5 * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2011,2012,2013,2015,2016 Olly Betts
6 * Copyright 2006,2007,2008,2009 Lemur Consulting Ltd
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
33 #include "safenetdb.h" // For gai_strerror().
34 #include "safesysstat.h" // For mkdir().
35 #include "safeunistd.h" // For sleep().
39 #include "backendmanager.h"
40 #include "backendmanager_local.h"
41 #include "testsuite.h"
42 #include "testutils.h"
50 query(const string
&t
)
52 return Xapian::Query(Xapian::Stem("english")(t
));
55 // #######################################################################
58 // tests Xapian::Database::get_termfreq() and Xapian::Database::term_exists()
59 DEFINE_TESTCASE(termstats
, backend
) {
60 Xapian::Database
db(get_database("apitest_simpledata"));
62 TEST(!db
.term_exists("corn"));
63 TEST_EQUAL(db
.get_termfreq("corn"), 0);
64 TEST(db
.term_exists("banana"));
65 TEST_EQUAL(db
.get_termfreq("banana"), 1);
66 TEST(db
.term_exists("paragraph"));
67 TEST_EQUAL(db
.get_termfreq("paragraph"), 5);
72 // Check that stub databases work.
73 DEFINE_TESTCASE(stubdb1
, backend
&& !inmemory
&& !remote
) {
74 // Only works for backends which have a path.
76 const char * dbpath
= ".stub/stubdb1";
79 out
<< "auto ../" << get_database_path("apitest_simpledata") << endl
;
83 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
84 Xapian::Enquire
enquire(db
);
85 enquire
.set_query(Xapian::Query("word"));
86 enquire
.get_mset(0, 10);
89 Xapian::Database
db(dbpath
);
90 Xapian::Enquire
enquire(db
);
91 enquire
.set_query(Xapian::Query("word"));
92 enquire
.get_mset(0, 10);
98 // Check that stub databases work remotely.
99 DEFINE_TESTCASE(stubdb2
, backend
&& !inmemory
&& !remote
) {
100 // Only works for backends which have a path.
101 mkdir(".stub", 0755);
102 const char * dbpath
= ".stub/stubdb2";
103 ofstream
out(dbpath
);
105 out
<< "remote :" << BackendManager::get_xapian_progsrv_command()
106 << ' ' << get_database_path("apitest_simpledata") << endl
;
110 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
111 Xapian::Enquire
enquire(db
);
112 enquire
.set_query(Xapian::Query("word"));
113 enquire
.get_mset(0, 10);
116 Xapian::Database
db(dbpath
);
117 Xapian::Enquire
enquire(db
);
118 enquire
.set_query(Xapian::Query("word"));
119 enquire
.get_mset(0, 10);
124 out
<< "remote" << endl
;
127 // Quietly ignored prior to 1.4.1.
128 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
129 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
)
132 // Quietly ignored prior to 1.4.1.
133 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
134 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
)
139 out
<< "remote foo" << endl
;
142 // Quietly ignored prior to 1.4.1.
143 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
144 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
)
147 // Quietly ignored prior to 1.4.1.
148 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
149 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
)
154 out
<< "remote [::1]:80" << endl
;
158 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
159 } catch (const Xapian::NetworkError
& e
) {
160 // 1.4.0 threw (Linux):
161 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
162 // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
163 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:80)) (nodename nor servname provided, or not known)
164 // or on OS X (EAI_NONAME):
165 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:80)) (Address family for hostname not supported)
166 // So we test the message instead of the error string for portability.
167 TEST(e
.get_msg().find("host ::1") != string::npos
);
171 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
);
172 } catch (const Xapian::NetworkError
& e
) {
173 // 1.4.0 threw (Linux):
174 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
175 // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
176 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:80)) (nodename nor servname provided, or not known)
177 // or on OS X (EAI_NONAME):
178 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:80)) (Address family for hostname not supported)
179 // So we test the message instead of the error string for portability.
180 TEST(e
.get_msg().find("host ::1") != string::npos
);
185 // Invalid - the port number is required.
186 out
<< "remote [::1]" << endl
;
190 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
191 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
192 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
196 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
197 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
198 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
);
204 // Regression test - bad entries were ignored after a good entry prior to 1.0.8.
205 DEFINE_TESTCASE(stubdb3
, backend
&& !inmemory
&& !remote
) {
206 // Only works for backends which have a path.
207 mkdir(".stub", 0755);
208 const char * dbpath
= ".stub/stubdb3";
209 ofstream
out(dbpath
);
211 out
<< "auto ../" << get_database_path("apitest_simpledata") << "\n"
215 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
216 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
218 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
219 Xapian::Database
db(dbpath
));
224 // Test a stub database with just a bad entry.
225 DEFINE_TESTCASE(stubdb4
, backend
&& !inmemory
&& !remote
) {
226 // Only works for backends which have a path.
227 mkdir(".stub", 0755);
228 const char * dbpath
= ".stub/stubdb4";
229 ofstream
out(dbpath
);
231 out
<< "bad line here\n";
234 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
235 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
237 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
238 Xapian::Database
db(dbpath
));
243 // Test a stub database with a bad entry with no spaces (prior to 1.1.0 this
244 // was deliberately allowed, though not documented.
245 DEFINE_TESTCASE(stubdb5
, backend
&& !inmemory
&& !remote
) {
246 // Only works for backends which have a path.
247 mkdir(".stub", 0755);
248 const char * dbpath
= ".stub/stubdb5";
249 ofstream
out(dbpath
);
252 "auto ../" << get_database_path("apitest_simpledata") << endl
;
255 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
256 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
258 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
259 Xapian::Database
db(dbpath
));
264 // Test a stub database with an inmemory database (new feature in 1.1.0).
265 DEFINE_TESTCASE(stubdb6
, inmemory
) {
266 mkdir(".stub", 0755);
267 const char * dbpath
= ".stub/stubdb6";
268 ofstream
out(dbpath
);
275 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
276 TEST_EQUAL(db
.get_doccount(), 0);
277 Xapian::Enquire
enquire(db
);
278 enquire
.set_query(Xapian::Query("word"));
279 Xapian::MSet mset
= enquire
.get_mset(0, 10);
283 Xapian::Database
db(dbpath
);
284 TEST_EQUAL(db
.get_doccount(), 0);
285 Xapian::Enquire
enquire(db
);
286 enquire
.set_query(Xapian::Query("word"));
287 Xapian::MSet mset
= enquire
.get_mset(0, 10);
293 Xapian::WritableDatabase
db(dbpath
,
294 Xapian::DB_OPEN
|Xapian::DB_BACKEND_STUB
);
295 TEST_EQUAL(db
.get_doccount(), 0);
296 db
.add_document(Xapian::Document());
297 TEST_EQUAL(db
.get_doccount(), 1);
300 Xapian::WritableDatabase
db(dbpath
,
301 Xapian::DB_OPEN
|Xapian::DB_BACKEND_STUB
);
302 TEST_EQUAL(db
.get_doccount(), 0);
303 db
.add_document(Xapian::Document());
304 TEST_EQUAL(db
.get_doccount(), 1);
310 #if 0 // the "force error" mechanism is no longer in place...
311 class MyErrorHandler
: public Xapian::ErrorHandler
{
315 bool handle_error(Xapian::Error
& error
) {
317 tout
<< "Error handling caught: " << error
.get_description()
318 << ", count is now " << count
<< "\n";
322 MyErrorHandler() : count (0) {}
325 // tests error handler in multimatch().
326 DEFINE_TESTCASE(multierrhandler1
, backend
) {
327 MyErrorHandler myhandler
;
329 Xapian::Database
mydb2(get_database("apitest_simpledata"));
330 Xapian::Database
mydb3(get_database("apitest_simpledata2"));
332 for (int testcount
= 0; testcount
< 14; testcount
++) {
333 tout
<< "testcount=" << testcount
<< "\n";
334 Xapian::Database
mydb4(get_database("-e", "apitest_termorder"));
335 Xapian::Database
mydb5(get_network_database("apitest_termorder", 1));
336 Xapian::Database
mydb6(get_database("-e2", "apitest_termorder"));
337 Xapian::Database
mydb7(get_database("-e3", "apitest_simpledata"));
339 Xapian::Database dbs
;
342 dbs
.add_database(mydb2
);
343 dbs
.add_database(mydb3
);
344 dbs
.add_database(mydb4
);
347 dbs
.add_database(mydb4
);
348 dbs
.add_database(mydb2
);
349 dbs
.add_database(mydb3
);
352 dbs
.add_database(mydb3
);
353 dbs
.add_database(mydb4
);
354 dbs
.add_database(mydb2
);
357 dbs
.add_database(mydb2
);
358 dbs
.add_database(mydb3
);
359 dbs
.add_database(mydb5
);
363 dbs
.add_database(mydb5
);
364 dbs
.add_database(mydb2
);
365 dbs
.add_database(mydb3
);
369 dbs
.add_database(mydb3
);
370 dbs
.add_database(mydb5
);
371 dbs
.add_database(mydb2
);
375 dbs
.add_database(mydb2
);
376 dbs
.add_database(mydb3
);
377 dbs
.add_database(mydb6
);
380 dbs
.add_database(mydb6
);
381 dbs
.add_database(mydb2
);
382 dbs
.add_database(mydb3
);
385 dbs
.add_database(mydb3
);
386 dbs
.add_database(mydb6
);
387 dbs
.add_database(mydb2
);
390 dbs
.add_database(mydb2
);
391 dbs
.add_database(mydb3
);
392 dbs
.add_database(mydb7
);
395 dbs
.add_database(mydb7
);
396 dbs
.add_database(mydb2
);
397 dbs
.add_database(mydb3
);
400 dbs
.add_database(mydb3
);
401 dbs
.add_database(mydb7
);
402 dbs
.add_database(mydb2
);
405 dbs
.add_database(mydb2
);
406 dbs
.add_database(mydb6
);
407 dbs
.add_database(mydb7
);
410 dbs
.add_database(mydb2
);
411 dbs
.add_database(mydb7
);
412 dbs
.add_database(mydb6
);
415 tout
<< "db=" << dbs
<< "\n";
416 Xapian::Enquire
enquire(dbs
, &myhandler
);
419 Xapian::Query myquery
= query(Xapian::Query::OP_OR
, "inmemory", "word");
420 enquire
.set_weighting_scheme(Xapian::BoolWeight());
421 enquire
.set_query(myquery
);
423 tout
<< "query=" << myquery
<< "\n";
424 // retrieve the top ten results
425 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
428 case 0: case 3: case 6: case 9:
429 mset_expect_order(mymset
, 2, 4, 10);
431 case 1: case 4: case 7: case 10:
432 mset_expect_order(mymset
, 3, 5, 11);
434 case 2: case 5: case 8: case 11:
435 mset_expect_order(mymset
, 1, 6, 12);
439 mset_expect_order(mymset
, 4, 10);
443 TEST_EQUAL(myhandler
.count
, errcount
);
451 class myMatchDecider
: public Xapian::MatchDecider
{
453 bool operator()(const Xapian::Document
&doc
) const {
454 // Note that this is not recommended usage of get_data()
455 return doc
.get_data().find("This is") != string::npos
;
459 // Test Xapian::MatchDecider functor.
460 DEFINE_TESTCASE(matchdecider1
, backend
&& !remote
) {
461 Xapian::Database
db(get_database("apitest_simpledata"));
462 Xapian::Enquire
enquire(db
);
463 enquire
.set_query(Xapian::Query("this"));
465 myMatchDecider myfunctor
;
467 Xapian::MSet mymset
= enquire
.get_mset(0, 100, 0, &myfunctor
);
469 vector
<bool> docid_checked(db
.get_lastdocid());
471 // Check that we get the expected number of matches, and that they
472 // satisfy the condition.
473 Xapian::MSetIterator i
= mymset
.begin();
474 TEST(i
!= mymset
.end());
475 TEST_EQUAL(mymset
.size(), 3);
476 TEST_EQUAL(mymset
.get_matches_lower_bound(), 3);
477 TEST_EQUAL(mymset
.get_matches_upper_bound(), 3);
478 TEST_EQUAL(mymset
.get_matches_estimated(), 3);
479 TEST_EQUAL(mymset
.get_uncollapsed_matches_lower_bound(), 3);
480 TEST_EQUAL(mymset
.get_uncollapsed_matches_upper_bound(), 3);
481 TEST_EQUAL(mymset
.get_uncollapsed_matches_estimated(), 3);
482 for ( ; i
!= mymset
.end(); ++i
) {
483 const Xapian::Document
doc(i
.get_document());
484 TEST(myfunctor(doc
));
485 docid_checked
[*i
] = true;
488 // Check that there are some documents which aren't accepted by the match
490 mymset
= enquire
.get_mset(0, 100);
491 TEST(mymset
.size() > 3);
493 // Check that the bounds are appropriate even if we don't ask for any
495 mymset
= enquire
.get_mset(0, 0, 0, &myfunctor
);
496 TEST_EQUAL(mymset
.size(), 0);
497 TEST_EQUAL(mymset
.get_matches_lower_bound(), 0);
498 TEST_EQUAL(mymset
.get_matches_upper_bound(), 6);
499 TEST_REL(mymset
.get_matches_estimated(),>,0);
500 TEST_REL(mymset
.get_matches_estimated(),<=,6);
501 TEST_EQUAL(mymset
.get_uncollapsed_matches_lower_bound(), 0);
502 TEST_EQUAL(mymset
.get_uncollapsed_matches_upper_bound(), 6);
503 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
504 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
506 // Check that the bounds are appropriate if we ask for only one hit.
507 // (Regression test - until SVN 10256, we didn't reduce the lower_bound
508 // appropriately, and returned 6 here.)
509 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
510 TEST_EQUAL(mymset
.size(), 1);
511 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
512 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
513 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
514 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
515 TEST_REL(mymset
.get_matches_estimated(),>,0);
516 TEST_REL(mymset
.get_matches_estimated(),<=,6);
517 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
518 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
519 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
520 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
521 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
522 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
524 // Check that the other documents don't satisfy the condition.
525 for (Xapian::docid did
= 1; did
< docid_checked
.size(); ++did
) {
526 if (!docid_checked
[did
]) {
527 TEST(!myfunctor(db
.get_document(did
)));
531 // Check that the bounds are appropriate if a collapse key is used.
532 // Use a value which is never set so we don't actually discard anything.
533 enquire
.set_collapse_key(99);
534 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
535 TEST_EQUAL(mymset
.size(), 1);
536 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
537 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
538 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
539 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
540 TEST_REL(mymset
.get_matches_estimated(),>,0);
541 TEST_REL(mymset
.get_matches_estimated(),<=,6);
542 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
543 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
544 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
545 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
546 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
547 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
549 // Check that the bounds are appropriate if a percentage cutoff is in
550 // use. Set a 1% threshold so we don't actually discard anything.
551 enquire
.set_collapse_key(Xapian::BAD_VALUENO
);
552 enquire
.set_cutoff(1);
553 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
554 TEST_EQUAL(mymset
.size(), 1);
555 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
556 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
557 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
558 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
559 TEST_REL(mymset
.get_matches_estimated(),>,0);
560 TEST_REL(mymset
.get_matches_estimated(),<=,6);
561 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
562 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
563 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
564 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
565 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
566 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
568 // And now with both a collapse key and percentage cutoff.
569 enquire
.set_collapse_key(99);
570 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
571 TEST_EQUAL(mymset
.size(), 1);
572 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
573 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
574 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
575 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
576 TEST_REL(mymset
.get_matches_estimated(),>,0);
577 TEST_REL(mymset
.get_matches_estimated(),<=,6);
578 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
579 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
580 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
581 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
582 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
583 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
588 // Test Xapian::MatchDecider functor used as a match spy.
589 DEFINE_TESTCASE(matchdecider2
, backend
&& !remote
) {
590 Xapian::Database
db(get_database("apitest_simpledata"));
591 Xapian::Enquire
enquire(db
);
592 enquire
.set_query(Xapian::Query("this"));
594 myMatchDecider myfunctor
;
596 Xapian::MSet mymset
= enquire
.get_mset(0, 100, 0, NULL
, &myfunctor
);
598 vector
<bool> docid_checked(db
.get_lastdocid());
600 // Check that we get the expected number of matches, and that they
601 // satisfy the condition.
602 Xapian::MSetIterator i
= mymset
.begin();
603 TEST(i
!= mymset
.end());
604 TEST_EQUAL(mymset
.size(), 3);
605 for ( ; i
!= mymset
.end(); ++i
) {
606 const Xapian::Document
doc(i
.get_document());
607 TEST(myfunctor(doc
));
608 docid_checked
[*i
] = true;
611 // Check that the other documents don't satisfy the condition.
612 for (Xapian::docid did
= 1; did
< docid_checked
.size(); ++did
) {
613 if (!docid_checked
[did
]) {
614 TEST(!myfunctor(db
.get_document(did
)));
621 class myMatchDecider2
: public Xapian::MatchDecider
{
623 bool operator()(const Xapian::Document
&doc
) const {
624 // Note that this is not recommended usage of get_data()
625 return doc
.get_data().find("We produce") == string::npos
;
630 // Regression test for lower bound using functor, sorting and collapsing.
631 DEFINE_TESTCASE(matchdecider3
, backend
&& !remote
) {
632 Xapian::Database
db(get_database("etext"));
633 Xapian::Enquire
enquire(db
);
634 enquire
.set_query(Xapian::Query(""));
635 enquire
.set_collapse_key(12);
636 enquire
.set_sort_by_value(11, true);
638 myMatchDecider2 myfunctor
;
640 Xapian::MSet mset1
= enquire
.get_mset(0, 2, 0, NULL
, &myfunctor
);
641 Xapian::MSet mset2
= enquire
.get_mset(0, 1000, 0, NULL
, &myfunctor
);
643 // mset2 should contain all the hits, so the statistics should be exact.
644 TEST_EQUAL(mset2
.get_matches_estimated(), mset2
.size());
645 TEST_EQUAL(mset2
.get_matches_lower_bound(), mset2
.get_matches_estimated());
646 TEST_EQUAL(mset2
.get_matches_estimated(), mset2
.get_matches_upper_bound());
648 TEST_REL(mset2
.get_uncollapsed_matches_lower_bound(),<=,mset2
.get_uncollapsed_matches_estimated());
649 TEST_REL(mset2
.get_uncollapsed_matches_estimated(),<=,mset2
.get_uncollapsed_matches_upper_bound());
651 // Check that the lower bound in mset1 is not greater than the known
652 // number of hits. This failed until revision 10811.
653 TEST_REL(mset1
.get_matches_lower_bound(),<=,mset2
.size());
655 // Check that the bounds for mset1 make sense.
656 TEST_REL(mset1
.get_matches_lower_bound(),<=,mset1
.get_matches_estimated());
657 TEST_REL(mset1
.get_matches_estimated(),<=,mset1
.get_matches_upper_bound());
658 TEST_REL(mset1
.size(),<=,mset1
.get_matches_upper_bound());
660 TEST_REL(mset1
.get_uncollapsed_matches_lower_bound(),<=,mset1
.get_uncollapsed_matches_estimated());
661 TEST_REL(mset1
.get_uncollapsed_matches_estimated(),<=,mset1
.get_uncollapsed_matches_upper_bound());
663 // The uncollapsed match would match all documents but the one the
664 // matchdecider rejects.
665 TEST_REL(mset1
.get_uncollapsed_matches_upper_bound(),>=,db
.get_doccount() - 1);
666 TEST_REL(mset1
.get_uncollapsed_matches_upper_bound(),<=,db
.get_doccount());
667 TEST_REL(mset2
.get_uncollapsed_matches_upper_bound(),>=,db
.get_doccount() - 1);
668 TEST_REL(mset2
.get_uncollapsed_matches_upper_bound(),<=,db
.get_doccount());
673 // tests that mset iterators on msets compare correctly.
674 DEFINE_TESTCASE(msetiterator1
, backend
) {
675 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
676 enquire
.set_query(Xapian::Query("this"));
677 Xapian::MSet mymset
= enquire
.get_mset(0, 2);
679 Xapian::MSetIterator j
;
681 Xapian::MSetIterator k
= mymset
.end();
682 Xapian::MSetIterator
l(j
);
683 Xapian::MSetIterator
m(k
);
684 Xapian::MSetIterator n
= mymset
.begin();
685 Xapian::MSetIterator o
= mymset
.begin();
686 TEST_NOT_EQUAL(j
, k
);
687 TEST_NOT_EQUAL(l
, m
);
697 TEST_NOT_EQUAL(j
, k
);
698 TEST_NOT_EQUAL(k
, l
);
699 TEST_NOT_EQUAL(k
, m
);
700 TEST_NOT_EQUAL(k
, o
);
704 TEST_NOT_EQUAL(j
, k
);
705 TEST_NOT_EQUAL(k
, l
);
710 TEST_NOT_EQUAL(n
, l
);
712 TEST_NOT_EQUAL(n
, mymset
.begin());
713 TEST_EQUAL(n
, mymset
.end());
718 // tests that mset iterators on empty msets compare equal.
719 DEFINE_TESTCASE(msetiterator2
, backend
) {
720 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
721 enquire
.set_query(Xapian::Query("this"));
722 Xapian::MSet mymset
= enquire
.get_mset(0, 0);
724 Xapian::MSetIterator j
= mymset
.begin();
725 Xapian::MSetIterator k
= mymset
.end();
726 Xapian::MSetIterator
l(j
);
727 Xapian::MSetIterator
m(k
);
738 // tests that begin().get_document() works when first != 0
739 DEFINE_TESTCASE(msetiterator3
, backend
) {
740 Xapian::Database
mydb(get_database("apitest_simpledata"));
741 Xapian::Enquire
enquire(mydb
);
742 enquire
.set_query(Xapian::Query("this"));
744 Xapian::MSet mymset
= enquire
.get_mset(2, 10);
746 TEST(!mymset
.empty());
747 Xapian::Document
doc(mymset
.begin().get_document());
748 TEST(!doc
.get_data().empty());
753 // tests that eset iterators on empty esets compare equal.
754 DEFINE_TESTCASE(esetiterator1
, backend
) {
755 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
756 enquire
.set_query(Xapian::Query("this"));
758 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
759 TEST(mymset
.size() >= 2);
762 Xapian::MSetIterator i
= mymset
.begin();
763 myrset
.add_document(*i
);
764 myrset
.add_document(*(++i
));
766 Xapian::ESet myeset
= enquire
.get_eset(2, myrset
);
767 Xapian::ESetIterator j
;
769 Xapian::ESetIterator k
= myeset
.end();
770 Xapian::ESetIterator
l(j
);
771 Xapian::ESetIterator
m(k
);
772 Xapian::ESetIterator n
= myeset
.begin();
774 TEST_NOT_EQUAL(j
, k
);
775 TEST_NOT_EQUAL(l
, m
);
784 TEST_NOT_EQUAL(j
, k
);
785 TEST_NOT_EQUAL(k
, l
);
786 TEST_NOT_EQUAL(k
, m
);
788 TEST_NOT_EQUAL(j
, k
);
789 TEST_NOT_EQUAL(k
, l
);
794 TEST_NOT_EQUAL(n
, l
);
796 TEST_NOT_EQUAL(n
, myeset
.begin());
797 TEST_EQUAL(n
, myeset
.end());
802 // tests that eset iterators on empty esets compare equal.
803 DEFINE_TESTCASE(esetiterator2
, backend
) {
804 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
805 enquire
.set_query(Xapian::Query("this"));
807 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
808 TEST(mymset
.size() >= 2);
811 Xapian::MSetIterator i
= mymset
.begin();
812 myrset
.add_document(*i
);
813 myrset
.add_document(*(++i
));
815 Xapian::ESet myeset
= enquire
.get_eset(0, myrset
);
816 Xapian::ESetIterator j
= myeset
.begin();
817 Xapian::ESetIterator k
= myeset
.end();
818 Xapian::ESetIterator
l(j
);
819 Xapian::ESetIterator
m(k
);
830 // tests the collapse-on-key
831 DEFINE_TESTCASE(collapsekey1
, backend
) {
832 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
833 enquire
.set_query(Xapian::Query("this"));
835 Xapian::MSet mymset1
= enquire
.get_mset(0, 100);
836 Xapian::doccount mymsize1
= mymset1
.size();
838 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
839 enquire
.set_collapse_key(value_no
);
840 Xapian::MSet mymset
= enquire
.get_mset(0, 100);
842 TEST_AND_EXPLAIN(mymsize1
> mymset
.size(),
843 "Had no fewer items when performing collapse: don't know whether it worked.");
845 map
<string
, Xapian::docid
> values
;
846 Xapian::MSetIterator i
= mymset
.begin();
847 for ( ; i
!= mymset
.end(); ++i
) {
848 string value
= i
.get_document().get_value(value_no
);
849 TEST(values
[value
] == 0 || value
.empty());
857 // tests that collapse-on-key modifies the predicted bounds for the number of
858 // matches appropriately.
859 DEFINE_TESTCASE(collapsekey2
, backend
) {
860 SKIP_TEST("Don't have a suitable database currently");
861 // FIXME: this needs an appropriate database creating, but that's quite
862 // subtle to do it seems.
863 Xapian::Enquire
enquire(get_database("apitest_simpledata2"));
864 enquire
.set_query(Xapian::Query("this"));
866 Xapian::MSet mset1
= enquire
.get_mset(0, 1);
868 // Test that if no duplicates are found, then the upper bound remains
869 // unchanged and the lower bound drops.
871 enquire
.set_query(Xapian::Query("this"));
872 Xapian::valueno value_no
= 3;
873 enquire
.set_collapse_key(value_no
);
874 Xapian::MSet mset
= enquire
.get_mset(0, 1);
876 TEST_REL(mset
.get_matches_lower_bound(),<,mset1
.get_matches_lower_bound());
877 TEST_EQUAL(mset
.get_matches_upper_bound(), mset1
.get_matches_upper_bound());
883 // tests that collapse-on-key modifies the predicted bounds for the number of
884 // matches appropriately.
885 DEFINE_TESTCASE(collapsekey3
, backend
) {
886 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
887 enquire
.set_query(Xapian::Query("this"));
889 Xapian::MSet mymset1
= enquire
.get_mset(0, 3);
891 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
892 enquire
.set_collapse_key(value_no
);
893 Xapian::MSet mymset
= enquire
.get_mset(0, 3);
895 TEST_AND_EXPLAIN(mymset1
.get_matches_lower_bound() > mymset
.get_matches_lower_bound(),
896 "Lower bound was not lower when performing collapse: don't know whether it worked.");
897 TEST_AND_EXPLAIN(mymset1
.get_matches_upper_bound() > mymset
.get_matches_upper_bound(),
898 "Upper bound was not lower when performing collapse: don't know whether it worked.");
900 map
<string
, Xapian::docid
> values
;
901 Xapian::MSetIterator i
= mymset
.begin();
902 for ( ; i
!= mymset
.end(); ++i
) {
903 string value
= i
.get_document().get_value(value_no
);
904 TEST(values
[value
] == 0 || value
.empty());
909 // Test that if the collapse value is always empty, then the upper bound
910 // remains unchanged, and the lower bound is the same or lower (it can be
911 // lower because the matcher counts the number of documents with empty
912 // collapse keys, but may have rejected a document because its weight is
913 // too low for the proto-MSet before it even looks at its collapse key).
915 Xapian::valueno value_no
= 1000;
916 enquire
.set_collapse_key(value_no
);
917 Xapian::MSet mymset
= enquire
.get_mset(0, 3);
919 TEST(mymset
.get_matches_lower_bound() <= mymset1
.get_matches_lower_bound());
920 TEST_EQUAL(mymset
.get_matches_upper_bound(), mymset1
.get_matches_upper_bound());
922 map
<string
, Xapian::docid
> values
;
923 Xapian::MSetIterator i
= mymset
.begin();
924 for ( ; i
!= mymset
.end(); ++i
) {
925 string value
= i
.get_document().get_value(value_no
);
926 TEST(values
[value
] == 0 || value
.empty());
934 // tests that collapse-on-key modifies the predicted bounds for the number of
935 // matches appropriately even when no results are requested.
936 DEFINE_TESTCASE(collapsekey4
, backend
) {
937 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
938 enquire
.set_query(Xapian::Query("this"));
940 Xapian::MSet mymset1
= enquire
.get_mset(0, 0);
942 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
943 enquire
.set_collapse_key(value_no
);
944 Xapian::MSet mymset
= enquire
.get_mset(0, 0);
946 TEST_AND_EXPLAIN(mymset
.get_matches_lower_bound() == 1,
947 "Lower bound was not 1 when performing collapse but not asking for any results.");
948 TEST_AND_EXPLAIN(mymset1
.get_matches_upper_bound() == mymset
.get_matches_upper_bound(),
949 "Upper bound was changed when performing collapse but not asking for any results.");
951 map
<string
, Xapian::docid
> values
;
952 Xapian::MSetIterator i
= mymset
.begin();
953 for ( ; i
!= mymset
.end(); ++i
) {
954 string value
= i
.get_document().get_value(value_no
);
955 TEST(values
[value
] == 0 || value
.empty());
963 // test for keepalives
964 DEFINE_TESTCASE(keepalive1
, remote
) {
965 Xapian::Database
db(get_remote_database("apitest_simpledata", 5000));
967 /* Test that keep-alives work */
968 for (int i
= 0; i
< 10; ++i
) {
972 Xapian::Enquire
enquire(db
);
973 enquire
.set_query(Xapian::Query("word"));
974 enquire
.get_mset(0, 10);
976 /* Test that things break without keepalives */
978 enquire
.set_query(Xapian::Query("word"));
979 TEST_EXCEPTION(Xapian::NetworkError
,
980 enquire
.get_mset(0, 10));
985 // test that iterating through all terms in a database works.
986 DEFINE_TESTCASE(allterms1
, backend
) {
987 Xapian::Database
db(get_database("apitest_allterms"));
988 Xapian::TermIterator ati
= db
.allterms_begin();
989 TEST(ati
!= db
.allterms_end());
990 TEST_EQUAL(*ati
, "one");
991 TEST_EQUAL(ati
.get_termfreq(), 1);
993 Xapian::TermIterator ati2
= ati
;
996 TEST(ati
!= db
.allterms_end());
998 tout
<< "*ati = '" << *ati
<< "'\n";
999 tout
<< "*ati.length = '" << (*ati
).length() << "'\n";
1000 tout
<< "*ati == \"one\" = " << (*ati
== "one") << "\n";
1001 tout
<< "*ati[3] = " << ((*ati
)[3]) << "\n";
1002 tout
<< "*ati = '" << *ati
<< "'\n";
1004 TEST(*ati
== "three");
1005 TEST(ati
.get_termfreq() == 3);
1008 TEST(ati2
!= db
.allterms_end());
1009 TEST(*ati2
== "one");
1010 TEST(ati2
.get_termfreq() == 1);
1017 TEST(ati
!= db
.allterms_end());
1018 TEST(*ati
== "two");
1019 TEST(ati
.get_termfreq() == 2);
1022 TEST(ati2
!= db
.allterms_end());
1023 TEST(*ati2
== "three");
1024 TEST(ati2
.get_termfreq() == 3);
1028 TEST(ati
== db
.allterms_end());
1033 // test that iterating through all terms in two databases works.
1034 DEFINE_TESTCASE(allterms2
, backend
) {
1035 Xapian::Database db
;
1036 db
.add_database(get_database("apitest_allterms"));
1037 db
.add_database(get_database("apitest_allterms2"));
1038 Xapian::TermIterator ati
= db
.allterms_begin();
1040 TEST(ati
!= db
.allterms_end());
1041 TEST(*ati
== "five");
1042 TEST(ati
.get_termfreq() == 2);
1045 TEST(ati
!= db
.allterms_end());
1046 TEST(*ati
== "four");
1047 TEST(ati
.get_termfreq() == 1);
1050 TEST(ati
!= db
.allterms_end());
1051 TEST(*ati
== "one");
1052 TEST(ati
.get_termfreq() == 1);
1055 TEST(ati
!= db
.allterms_end());
1056 TEST(*ati
== "six");
1057 TEST(ati
.get_termfreq() == 3);
1060 TEST(ati
!= db
.allterms_end());
1061 TEST(*ati
== "three");
1062 TEST(ati
.get_termfreq() == 3);
1065 TEST(ati
!= db
.allterms_end());
1066 TEST(*ati
== "two");
1067 TEST(ati
.get_termfreq() == 2);
1070 TEST(ati
== db
.allterms_end());
1075 // test that skip_to sets at_end (regression test)
1076 DEFINE_TESTCASE(allterms3
, backend
) {
1077 Xapian::Database db
;
1078 db
.add_database(get_database("apitest_allterms"));
1079 Xapian::TermIterator ati
= db
.allterms_begin();
1081 ati
.skip_to(string("zzzzzz"));
1082 TEST(ati
== db
.allterms_end());
1087 // test that next ignores extra entries due to long posting lists being
1088 // chunked (regression test for quartz)
1089 DEFINE_TESTCASE(allterms4
, backend
) {
1090 // apitest_allterms4 contains 682 documents each containing just the word
1091 // "foo". 682 was the magic number which started to cause Quartz problems.
1092 Xapian::Database db
= get_database("apitest_allterms4");
1094 Xapian::TermIterator i
= db
.allterms_begin();
1095 TEST(i
!= db
.allterms_end());
1097 TEST(i
.get_termfreq() == 682);
1099 TEST(i
== db
.allterms_end());
1104 // test that skip_to with an exact match sets the current term (regression test
1106 DEFINE_TESTCASE(allterms5
, backend
) {
1107 Xapian::Database db
;
1108 db
.add_database(get_database("apitest_allterms"));
1109 Xapian::TermIterator ati
= db
.allterms_begin();
1110 ati
.skip_to("three");
1111 TEST(ati
!= db
.allterms_end());
1112 TEST_EQUAL(*ati
, "three");
1117 // test allterms iterators with prefixes
1118 DEFINE_TESTCASE(allterms6
, backend
) {
1119 Xapian::Database db
;
1120 db
.add_database(get_database("apitest_allterms"));
1121 db
.add_database(get_database("apitest_allterms2"));
1123 Xapian::TermIterator ati
= db
.allterms_begin("three");
1124 TEST(ati
!= db
.allterms_end("three"));
1125 TEST_EQUAL(*ati
, "three");
1126 ati
.skip_to("three");
1127 TEST(ati
!= db
.allterms_end("three"));
1128 TEST_EQUAL(*ati
, "three");
1130 TEST(ati
== db
.allterms_end("three"));
1132 ati
= db
.allterms_begin("thre");
1133 TEST(ati
!= db
.allterms_end("thre"));
1134 TEST_EQUAL(*ati
, "three");
1135 ati
.skip_to("three");
1136 TEST(ati
!= db
.allterms_end("thre"));
1137 TEST_EQUAL(*ati
, "three");
1139 TEST(ati
== db
.allterms_end("thre"));
1141 ati
= db
.allterms_begin("f");
1142 TEST(ati
!= db
.allterms_end("f"));
1143 TEST_EQUAL(*ati
, "five");
1144 TEST(ati
!= db
.allterms_end("f"));
1145 ati
.skip_to("three");
1146 TEST(ati
== db
.allterms_end("f"));
1148 ati
= db
.allterms_begin("f");
1149 TEST(ati
!= db
.allterms_end("f"));
1150 TEST_EQUAL(*ati
, "five");
1152 TEST(ati
!= db
.allterms_end("f"));
1153 TEST_EQUAL(*ati
, "four");
1155 TEST(ati
== db
.allterms_end("f"));
1157 ati
= db
.allterms_begin("absent");
1158 TEST(ati
== db
.allterms_end("absent"));
1163 // test that searching for a term with a special characters in it works
1164 DEFINE_TESTCASE(specialterms1
, backend
) {
1165 Xapian::Enquire
enquire(get_database("apitest_space"));
1166 Xapian::MSet mymset
;
1167 Xapian::doccount count
;
1168 Xapian::MSetIterator m
;
1169 Xapian::Stem
stemmer("english");
1171 enquire
.set_query(stemmer("new\nline"));
1172 mymset
= enquire
.get_mset(0, 10);
1173 TEST_MSET_SIZE(mymset
, 1);
1175 for (m
= mymset
.begin(); m
!= mymset
.end(); ++m
) ++count
;
1176 TEST_EQUAL(count
, 1);
1178 for (Xapian::valueno value_no
= 0; value_no
< 7; ++value_no
) {
1179 string value
= mymset
.begin().get_document().get_value(value_no
);
1180 TEST_NOT_EQUAL(value
, "");
1181 if (value_no
== 0) {
1182 TEST(value
.size() > 263);
1183 TEST_EQUAL(static_cast<unsigned char>(value
[262]), 255);
1184 for (int k
= 0; k
< 256; k
++) {
1185 TEST_EQUAL(static_cast<unsigned char>(value
[k
+ 7]), k
);
1190 enquire
.set_query(stemmer(string("big\0zero", 8)));
1191 mymset
= enquire
.get_mset(0, 10);
1192 TEST_MSET_SIZE(mymset
, 1);
1194 for (m
= mymset
.begin(); m
!= mymset
.end(); ++m
) ++count
;
1195 TEST_EQUAL(count
, 1);
1200 // test that terms with a special characters in appear correctly when iterating
1202 DEFINE_TESTCASE(specialterms2
, backend
) {
1203 Xapian::Database
db(get_database("apitest_space"));
1205 // Check the terms are all as expected (after stemming) and that allterms
1206 // copes with iterating over them.
1207 Xapian::TermIterator t
;
1208 t
= db
.allterms_begin();
1209 TEST_EQUAL(*t
, "back\\slash"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1210 TEST_EQUAL(*t
, string("big\0zero", 8)); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1211 TEST_EQUAL(*t
, "new\nlin"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1212 TEST_EQUAL(*t
, "one\x01on"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1213 TEST_EQUAL(*t
, "space man"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1214 TEST_EQUAL(*t
, "tab\tbi"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1215 TEST_EQUAL(*t
, "tu\x02tu"); ++t
; TEST_EQUAL(t
, db
.allterms_end());
1217 // Now check that skip_to exactly a term containing a zero byte works.
1218 // This is a regression test for flint and quartz - an Assert() used to
1219 // fire in debug builds (the Assert was wrong - the actual code handled
1221 t
= db
.allterms_begin();
1222 t
.skip_to(string("big\0zero", 8));
1223 TEST_NOT_EQUAL(t
, db
.allterms_end());
1224 TEST_EQUAL(*t
, string("big\0zero", 8));
1229 // test that rsets behave correctly with multiDBs
1230 DEFINE_TESTCASE(rsetmultidb2
, backend
&& !multi
) {
1231 Xapian::Database
mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1232 Xapian::Database
mydb2(get_database("apitest_rset"));
1233 mydb2
.add_database(get_database("apitest_simpledata2"));
1235 Xapian::Enquire
enquire1(mydb1
);
1236 Xapian::Enquire
enquire2(mydb2
);
1238 Xapian::Query myquery
= query("is");
1240 enquire1
.set_query(myquery
);
1241 enquire2
.set_query(myquery
);
1243 Xapian::RSet myrset1
;
1244 Xapian::RSet myrset2
;
1245 myrset1
.add_document(4);
1246 myrset2
.add_document(2);
1248 Xapian::MSet mymset1a
= enquire1
.get_mset(0, 10);
1249 Xapian::MSet mymset1b
= enquire1
.get_mset(0, 10, &myrset1
);
1250 Xapian::MSet mymset2a
= enquire2
.get_mset(0, 10);
1251 Xapian::MSet mymset2b
= enquire2
.get_mset(0, 10, &myrset2
);
1253 mset_expect_order(mymset1a
, 4, 3);
1254 mset_expect_order(mymset1b
, 4, 3);
1255 mset_expect_order(mymset2a
, 2, 5);
1256 mset_expect_order(mymset2b
, 2, 5);
1258 TEST(mset_range_is_same_weights(mymset1a
, 0, mymset2a
, 0, 2));
1259 TEST(mset_range_is_same_weights(mymset1b
, 0, mymset2b
, 0, 2));
1260 TEST_NOT_EQUAL(mymset1a
, mymset1b
);
1261 TEST_NOT_EQUAL(mymset2a
, mymset2b
);
1266 // tests an expand across multiple databases
1267 DEFINE_TESTCASE(multiexpand1
, backend
&& !multi
) {
1268 Xapian::Database
mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1269 Xapian::Enquire
enquire1(mydb1
);
1271 Xapian::Database
mydb2(get_database("apitest_simpledata"));
1272 mydb2
.add_database(get_database("apitest_simpledata2"));
1273 Xapian::Enquire
enquire2(mydb2
);
1275 // make simple equivalent rsets, with a document from each database in each.
1278 rset1
.add_document(1);
1279 rset1
.add_document(7);
1280 rset2
.add_document(1);
1281 rset2
.add_document(2);
1283 // Retrieve all the ESet results in each of the three setups:
1285 // This is the single database one.
1286 Xapian::ESet eset1
= enquire1
.get_eset(1000, rset1
);
1288 // This is the multi database with approximation
1289 Xapian::ESet eset2
= enquire2
.get_eset(1000, rset2
);
1291 // This is the multi database without approximation
1292 Xapian::ESet eset3
= enquire2
.get_eset(1000, rset2
, Xapian::Enquire::USE_EXACT_TERMFREQ
);
1294 TEST_EQUAL(eset1
.size(), eset3
.size());
1296 Xapian::ESetIterator i
= eset1
.begin();
1297 Xapian::ESetIterator j
= eset3
.begin();
1298 while (i
!= eset1
.end() && j
!= eset3
.end()) {
1300 TEST_EQUAL(i
.get_weight(), j
.get_weight());
1304 TEST(i
== eset1
.end());
1305 TEST(j
== eset3
.end());
1307 bool eset1_eq_eset2
= true;
1310 while (i
!= eset1
.end() && j
!= eset2
.end()) {
1311 if (i
.get_weight() != j
.get_weight()) {
1312 eset1_eq_eset2
= false;
1318 TEST(!eset1_eq_eset2
);
1323 // tests that opening a non-existent postlist returns an empty list
1324 DEFINE_TESTCASE(postlist1
, backend
) {
1325 Xapian::Database
db(get_database("apitest_simpledata"));
1327 TEST_EQUAL(db
.postlist_begin("rosebud"), db
.postlist_end("rosebud"));
1329 string s
= "let_us_see_if_we_can_break_it_with_a_really_really_long_term.";
1330 for (int i
= 0; i
< 8; ++i
) {
1332 TEST_EQUAL(db
.postlist_begin(s
), db
.postlist_end(s
));
1335 // A regression test (no, really!)
1336 TEST_NOT_EQUAL(db
.postlist_begin("a"), db
.postlist_end("a"));
1341 // tests that a Xapian::PostingIterator works as an STL iterator
1342 DEFINE_TESTCASE(postlist2
, backend
) {
1343 Xapian::Database
db(get_database("apitest_simpledata"));
1344 Xapian::PostingIterator p
;
1345 p
= db
.postlist_begin("this");
1346 Xapian::PostingIterator pend
= db
.postlist_end("this");
1348 TEST(p
.get_description() != "PostingIterator()");
1350 // test operator= creates a copy which compares equal
1351 Xapian::PostingIterator p_copy
= p
;
1352 TEST_EQUAL(p
, p_copy
);
1354 TEST(p_copy
.get_description() != "PostingIterator()");
1356 // test copy constructor creates a copy which compares equal
1357 Xapian::PostingIterator
p_clone(p
);
1358 TEST_EQUAL(p
, p_clone
);
1360 TEST(p_clone
.get_description() != "PostingIterator()");
1362 vector
<Xapian::docid
> v(p
, pend
);
1364 p
= db
.postlist_begin("this");
1365 pend
= db
.postlist_end("this");
1366 vector
<Xapian::docid
>::const_iterator i
;
1367 for (i
= v
.begin(); i
!= v
.end(); ++i
) {
1368 TEST_NOT_EQUAL(p
, pend
);
1372 TEST_EQUAL(p
, pend
);
1374 TEST_STRINGS_EQUAL(p
.get_description(), "PostingIterator()");
1375 TEST_STRINGS_EQUAL(pend
.get_description(), "PostingIterator()");
1380 // tests that a Xapian::PostingIterator still works when the DB is deleted
1381 DEFINE_TESTCASE(postlist3
, backend
) {
1382 Xapian::PostingIterator u
;
1384 Xapian::Database
db_temp(get_database("apitest_simpledata"));
1385 u
= db_temp
.postlist_begin("this");
1388 Xapian::Database
db(get_database("apitest_simpledata"));
1389 Xapian::PostingIterator p
= db
.postlist_begin("this");
1390 Xapian::PostingIterator pend
= db
.postlist_end("this");
1401 DEFINE_TESTCASE(postlist4
, backend
) {
1402 Xapian::Database
db(get_database("apitest_simpledata"));
1403 Xapian::PostingIterator i
= db
.postlist_begin("this");
1405 i
.skip_to(999999999);
1406 TEST(i
== db
.postlist_end("this"));
1410 // tests long postlists
1411 DEFINE_TESTCASE(postlist5
, backend
) {
1412 Xapian::Database
db(get_database("apitest_manydocs"));
1413 // Allow for databases which don't support length
1414 if (db
.get_avlength() != 1)
1415 TEST_EQUAL_DOUBLE(db
.get_avlength(), 4);
1416 Xapian::PostingIterator i
= db
.postlist_begin("this");
1418 while (i
!= db
.postlist_end("this")) {
1427 // tests document length in postlists
1428 DEFINE_TESTCASE(postlist6
, backend
) {
1429 Xapian::Database
db(get_database("apitest_simpledata"));
1430 Xapian::PostingIterator i
= db
.postlist_begin("this");
1431 TEST(i
!= db
.postlist_end("this"));
1432 while (i
!= db
.postlist_end("this")) {
1433 TEST_EQUAL(i
.get_doclength(), db
.get_doclength(*i
));
1434 TEST_EQUAL(i
.get_unique_terms(), db
.get_unique_terms(*i
));
1435 TEST_REL(i
.get_wdf(),<=,i
.get_doclength());
1436 TEST_REL(1,<=,i
.get_unique_terms());
1437 // The next two aren't necessarily true if there are terms with wdf=0
1438 // in the document, but that isn't the case here.
1439 TEST_REL(i
.get_unique_terms(),<=,i
.get_doclength());
1440 TEST_REL(i
.get_wdf() + i
.get_unique_terms() - 1,<=,i
.get_doclength());
1446 // tests collection frequency
1447 DEFINE_TESTCASE(collfreq1
, backend
) {
1448 Xapian::Database
db(get_database("apitest_simpledata"));
1450 TEST_EQUAL(db
.get_collection_freq("this"), 11);
1451 TEST_EQUAL(db
.get_collection_freq("first"), 1);
1452 TEST_EQUAL(db
.get_collection_freq("last"), 0);
1453 TEST_EQUAL(db
.get_collection_freq("word"), 9);
1455 Xapian::Database
db1(get_database("apitest_simpledata", "apitest_simpledata2"));
1456 Xapian::Database
db2(get_database("apitest_simpledata"));
1457 db2
.add_database(get_database("apitest_simpledata2"));
1459 TEST_EQUAL(db1
.get_collection_freq("this"), 15);
1460 TEST_EQUAL(db1
.get_collection_freq("first"), 1);
1461 TEST_EQUAL(db1
.get_collection_freq("last"), 0);
1462 TEST_EQUAL(db1
.get_collection_freq("word"), 11);
1463 TEST_EQUAL(db2
.get_collection_freq("this"), 15);
1464 TEST_EQUAL(db2
.get_collection_freq("first"), 1);
1465 TEST_EQUAL(db2
.get_collection_freq("last"), 0);
1466 TEST_EQUAL(db2
.get_collection_freq("word"), 11);
1471 // Regression test for split msets being incorrect when sorting
1472 DEFINE_TESTCASE(sortvalue1
, backend
) {
1473 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
1474 enquire
.set_query(Xapian::Query("this"));
1476 for (int pass
= 1; pass
<= 2; ++pass
) {
1477 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
1478 tout
<< "Sorting on value " << value_no
<< endl
;
1479 enquire
.set_sort_by_value(value_no
, true);
1480 Xapian::MSet allbset
= enquire
.get_mset(0, 100);
1481 Xapian::MSet partbset1
= enquire
.get_mset(0, 3);
1482 Xapian::MSet partbset2
= enquire
.get_mset(3, 97);
1483 TEST_EQUAL(allbset
.size(), partbset1
.size() + partbset2
.size());
1487 Xapian::MSetIterator i
, j
;
1488 j
= allbset
.begin();
1489 for (i
= partbset1
.begin(); i
!= partbset1
.end(); ++i
) {
1490 tout
<< "Entry " << n
<< ": " << *i
<< " | " << *j
<< endl
;
1491 TEST(j
!= allbset
.end());
1492 if (*i
!= *j
) ok
= false;
1497 for (i
= partbset2
.begin(); i
!= partbset2
.end(); ++i
) {
1498 tout
<< "Entry " << n
<< ": " << *i
<< " | " << *j
<< endl
;
1499 TEST(j
!= allbset
.end());
1500 if (*i
!= *j
) ok
= false;
1504 TEST(j
== allbset
.end());
1506 FAIL_TEST("Split msets aren't consistent with unsplit");
1508 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1514 // consistency check match - vary mset size and check results agree.
1515 // consistency1 will run on the remote backend, but it's particularly slow
1516 // with that, and testing it there doesn't actually improve the test
1518 DEFINE_TESTCASE(consistency1
, backend
&& !remote
) {
1519 Xapian::Database
db(get_database("etext"));
1520 Xapian::Enquire
enquire(db
);
1521 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
, Xapian::Query("the"), Xapian::Query("sky")));
1522 Xapian::doccount lots
= 214;
1523 Xapian::MSet bigmset
= enquire
.get_mset(0, lots
);
1524 TEST_EQUAL(bigmset
.size(), lots
);
1526 for (Xapian::doccount start
= 0; start
< lots
; ++start
) {
1527 for (Xapian::doccount size
= 0; size
< lots
- start
; ++size
) {
1528 Xapian::MSet mset
= enquire
.get_mset(start
, size
);
1530 TEST_EQUAL(start
+ mset
.size(),
1531 min(start
+ size
, bigmset
.size()));
1533 // tout << start << mset.size() << bigmset.size() << endl;
1534 TEST(start
>= bigmset
.size());
1536 for (Xapian::doccount i
= 0; i
< mset
.size(); ++i
) {
1537 TEST_EQUAL(*mset
[i
], *bigmset
[start
+ i
]);
1538 TEST_EQUAL_DOUBLE(mset
[i
].get_weight(),
1539 bigmset
[start
+ i
].get_weight());
1543 } catch (const Xapian::NetworkTimeoutError
&) {
1544 // consistency1 is a long test - may timeout with the remote backend...
1545 SKIP_TEST("Test taking too long");
1550 // tests that specifying a nonexistent input file throws an exception.
1551 DEFINE_TESTCASE(chertdatabaseopeningerror1
, chert
) {
1552 #ifdef XAPIAN_HAS_CHERT_BACKEND
1553 mkdir(".chert", 0755);
1555 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1556 Xapian::Database(".chert/nosuchdirectory",
1557 Xapian::DB_BACKEND_CHERT
));
1558 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1559 Xapian::WritableDatabase(".chert/nosuchdirectory",
1560 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1562 mkdir(".chert/emptydirectory", 0700);
1563 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1564 Xapian::Database(".chert/emptydirectory",
1565 Xapian::DB_BACKEND_CHERT
));
1567 touch(".chert/somefile");
1568 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1569 Xapian::Database(".chert/somefile",
1570 Xapian::DB_BACKEND_CHERT
));
1571 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1572 Xapian::WritableDatabase(".chert/somefile",
1573 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1574 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1575 Xapian::WritableDatabase(".chert/somefile",
1576 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
));
1577 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1578 Xapian::WritableDatabase(".chert/somefile",
1579 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
));
1580 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1581 Xapian::WritableDatabase(".chert/somefile",
1582 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
));
1588 /// Test opening of a chert database
1589 DEFINE_TESTCASE(chertdatabaseopen1
, chert
) {
1590 #ifdef XAPIAN_HAS_CHERT_BACKEND
1591 const string dbdir
= ".chert/test_chertdatabaseopen1";
1592 mkdir(".chert", 0755);
1596 Xapian::WritableDatabase
wdb(dbdir
,
1597 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
);
1598 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1599 Xapian::WritableDatabase(dbdir
,
1600 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1601 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1606 Xapian::WritableDatabase
wdb(dbdir
,
1607 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
);
1608 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1609 Xapian::WritableDatabase(dbdir
,
1610 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
));
1611 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1616 Xapian::WritableDatabase
wdb(dbdir
,
1617 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
);
1618 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1619 Xapian::WritableDatabase(dbdir
,
1620 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
));
1621 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1625 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1626 Xapian::WritableDatabase(dbdir
,
1627 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
));
1628 Xapian::WritableDatabase
wdb(dbdir
,
1629 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
);
1630 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1634 Xapian::WritableDatabase
wdb(dbdir
,
1635 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
);
1636 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1640 Xapian::WritableDatabase
wdb(dbdir
,
1641 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
);
1642 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1649 // feature test for Enquire:
1650 // set_sort_by_value
1651 // set_sort_by_value_then_relevance
1652 // set_sort_by_relevance_then_value
1653 // Prior to 1.2.17 and 1.3.2, order8 and order9 were swapped, and
1654 // set_sort_by_relevance_then_value was buggy, so this testcase now serves as
1655 // a regression test for that bug.
1656 DEFINE_TESTCASE(sortrel1
, backend
) {
1657 Xapian::Enquire
enquire(get_database("apitest_sortrel"));
1658 enquire
.set_sort_by_value(1, true);
1659 enquire
.set_query(Xapian::Query("woman"));
1661 const Xapian::docid order1
[] = { 1,2,3,4,5,6,7,8,9 };
1662 const Xapian::docid order2
[] = { 2,1,3,6,5,4,7,9,8 };
1663 const Xapian::docid order3
[] = { 3,2,1,6,5,4,9,8,7 };
1664 const Xapian::docid order4
[] = { 7,8,9,4,5,6,1,2,3 };
1665 const Xapian::docid order5
[] = { 9,8,7,6,5,4,3,2,1 };
1666 const Xapian::docid order6
[] = { 7,9,8,6,5,4,2,1,3 };
1667 const Xapian::docid order7
[] = { 7,9,8,6,5,4,2,1,3 };
1668 const Xapian::docid order8
[] = { 2,6,7,1,5,9,3,4,8 };
1669 const Xapian::docid order9
[] = { 7,6,2,9,5,1,8,4,3 };
1674 mset
= enquire
.get_mset(0, 10);
1675 TEST_EQUAL(mset
.size(), sizeof(order1
) / sizeof(Xapian::docid
));
1676 for (i
= 0; i
< sizeof(order1
) / sizeof(Xapian::docid
); ++i
) {
1677 TEST_EQUAL(*mset
[i
], order1
[i
]);
1680 enquire
.set_sort_by_value_then_relevance(1, true);
1682 mset
= enquire
.get_mset(0, 10);
1683 TEST_EQUAL(mset
.size(), sizeof(order2
) / sizeof(Xapian::docid
));
1684 for (i
= 0; i
< sizeof(order2
) / sizeof(Xapian::docid
); ++i
) {
1685 TEST_EQUAL(*mset
[i
], order2
[i
]);
1688 enquire
.set_sort_by_value(1, true);
1690 mset
= enquire
.get_mset(0, 10);
1691 TEST_EQUAL(mset
.size(), sizeof(order1
) / sizeof(Xapian::docid
));
1692 for (i
= 0; i
< sizeof(order1
) / sizeof(Xapian::docid
); ++i
) {
1693 TEST_EQUAL(*mset
[i
], order1
[i
]);
1696 enquire
.set_sort_by_value_then_relevance(1, true);
1697 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1699 mset
= enquire
.get_mset(0, 10);
1700 TEST_EQUAL(mset
.size(), sizeof(order2
) / sizeof(Xapian::docid
));
1701 for (i
= 0; i
< sizeof(order2
) / sizeof(Xapian::docid
); ++i
) {
1702 TEST_EQUAL(*mset
[i
], order2
[i
]);
1705 enquire
.set_sort_by_value(1, true);
1706 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1708 mset
= enquire
.get_mset(0, 10);
1709 TEST_EQUAL(mset
.size(), sizeof(order3
) / sizeof(Xapian::docid
));
1710 for (i
= 0; i
< sizeof(order3
) / sizeof(Xapian::docid
); ++i
) {
1711 TEST_EQUAL(*mset
[i
], order3
[i
]);
1714 enquire
.set_sort_by_value(1, false);
1715 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1716 mset
= enquire
.get_mset(0, 10);
1717 TEST_EQUAL(mset
.size(), sizeof(order4
) / sizeof(Xapian::docid
));
1718 for (i
= 0; i
< sizeof(order4
) / sizeof(Xapian::docid
); ++i
) {
1719 TEST_EQUAL(*mset
[i
], order4
[i
]);
1722 enquire
.set_sort_by_value(1, false);
1723 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1724 mset
= enquire
.get_mset(0, 10);
1725 TEST_EQUAL(mset
.size(), sizeof(order5
) / sizeof(Xapian::docid
));
1726 for (i
= 0; i
< sizeof(order5
) / sizeof(Xapian::docid
); ++i
) {
1727 TEST_EQUAL(*mset
[i
], order5
[i
]);
1730 enquire
.set_sort_by_value_then_relevance(1, false);
1731 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1732 mset
= enquire
.get_mset(0, 10);
1733 TEST_EQUAL(mset
.size(), sizeof(order6
) / sizeof(Xapian::docid
));
1734 for (i
= 0; i
< sizeof(order6
) / sizeof(Xapian::docid
); ++i
) {
1735 TEST_EQUAL(*mset
[i
], order6
[i
]);
1738 enquire
.set_sort_by_value_then_relevance(1, false);
1739 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1740 mset
= enquire
.get_mset(0, 10);
1741 TEST_EQUAL(mset
.size(), sizeof(order7
) / sizeof(Xapian::docid
));
1742 for (i
= 0; i
< sizeof(order7
) / sizeof(Xapian::docid
); ++i
) {
1743 TEST_EQUAL(*mset
[i
], order7
[i
]);
1746 enquire
.set_sort_by_relevance_then_value(1, true);
1747 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1748 mset
= enquire
.get_mset(0, 10);
1749 TEST_EQUAL(mset
.size(), sizeof(order8
) / sizeof(Xapian::docid
));
1750 for (i
= 0; i
< sizeof(order8
) / sizeof(Xapian::docid
); ++i
) {
1751 TEST_EQUAL(*mset
[i
], order8
[i
]);
1754 enquire
.set_sort_by_relevance_then_value(1, true);
1755 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1756 mset
= enquire
.get_mset(0, 10);
1757 TEST_EQUAL(mset
.size(), sizeof(order8
) / sizeof(Xapian::docid
));
1758 for (i
= 0; i
< sizeof(order8
) / sizeof(Xapian::docid
); ++i
) {
1759 TEST_EQUAL(*mset
[i
], order8
[i
]);
1762 enquire
.set_sort_by_relevance_then_value(1, false);
1763 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1764 mset
= enquire
.get_mset(0, 10);
1765 TEST_EQUAL(mset
.size(), sizeof(order9
) / sizeof(Xapian::docid
));
1766 for (i
= 0; i
< sizeof(order9
) / sizeof(Xapian::docid
); ++i
) {
1767 TEST_EQUAL(*mset
[i
], order9
[i
]);
1770 enquire
.set_sort_by_relevance_then_value(1, false);
1771 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1772 mset
= enquire
.get_mset(0, 10);
1773 TEST_EQUAL(mset
.size(), sizeof(order9
) / sizeof(Xapian::docid
));
1774 for (i
= 0; i
< sizeof(order9
) / sizeof(Xapian::docid
); ++i
) {
1775 TEST_EQUAL(*mset
[i
], order9
[i
]);
1781 // Test network stats and local stats give the same results.
1782 DEFINE_TESTCASE(netstats1
, remote
) {
1783 BackendManagerLocal local_manager
;
1784 local_manager
.set_datadir(test_driver::get_srcdir() + "/testdata/");
1786 const char * words
[] = { "paragraph", "word" };
1787 Xapian::Query
query(Xapian::Query::OP_OR
, words
, words
+ 2);
1788 const size_t MSET_SIZE
= 10;
1791 rset
.add_document(4);
1792 rset
.add_document(9);
1794 Xapian::MSet mset_alllocal
;
1796 Xapian::Database db
;
1797 db
.add_database(local_manager
.get_database("apitest_simpledata"));
1798 db
.add_database(local_manager
.get_database("apitest_simpledata2"));
1800 Xapian::Enquire
enq(db
);
1801 enq
.set_query(query
);
1802 mset_alllocal
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1806 Xapian::Database db
;
1807 db
.add_database(local_manager
.get_database("apitest_simpledata"));
1808 db
.add_database(get_database("apitest_simpledata2"));
1810 Xapian::Enquire
enq(db
);
1811 enq
.set_query(query
);
1812 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1813 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1814 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1815 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1816 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1817 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1818 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1822 Xapian::Database db
;
1823 db
.add_database(get_database("apitest_simpledata"));
1824 db
.add_database(local_manager
.get_database("apitest_simpledata2"));
1826 Xapian::Enquire
enq(db
);
1827 enq
.set_query(query
);
1828 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1829 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1830 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1831 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1832 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1833 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1834 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1838 Xapian::Database db
;
1839 db
.add_database(get_database("apitest_simpledata"));
1840 db
.add_database(get_database("apitest_simpledata2"));
1842 Xapian::Enquire
enq(db
);
1843 enq
.set_query(query
);
1844 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1845 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1846 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1847 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1848 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1849 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1850 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1856 // Coordinate matching - scores 1 for each matching term
1857 class MyWeight
: public Xapian::Weight
{
1858 double scale_factor
;
1861 MyWeight
* clone() const {
1862 return new MyWeight
;
1864 void init(double factor
) {
1865 scale_factor
= factor
;
1869 std::string
name() const { return "MyWeight"; }
1870 string
serialise() const { return string(); }
1871 MyWeight
* unserialise(const string
&) const { return new MyWeight
; }
1872 double get_sumpart(Xapian::termcount
, Xapian::termcount
, Xapian::termcount
) const {
1873 return scale_factor
;
1875 double get_maxpart() const { return scale_factor
; }
1877 double get_sumextra(Xapian::termcount
, Xapian::termcount
) const { return 0; }
1878 double get_maxextra() const { return 0; }
1881 // tests user weighting scheme.
1882 // Would work with remote if we registered the weighting scheme.
1883 // FIXME: do this so we also test that functionality...
1884 DEFINE_TESTCASE(userweight1
, backend
&& !remote
) {
1885 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
1886 enquire
.set_weighting_scheme(MyWeight());
1887 const char * query
[] = { "this", "line", "paragraph", "rubbish" };
1888 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
, query
,
1889 query
+ sizeof(query
) / sizeof(query
[0])));
1890 Xapian::MSet mymset1
= enquire
.get_mset(0, 100);
1891 // MyWeight scores 1 for each matching term, so the weight should equal
1892 // the number of matching terms.
1893 for (Xapian::MSetIterator i
= mymset1
.begin(); i
!= mymset1
.end(); ++i
) {
1894 Xapian::termcount matching_terms
= 0;
1895 Xapian::TermIterator t
= enquire
.get_matching_terms_begin(i
);
1896 while (t
!= enquire
.get_matching_terms_end(i
)) {
1900 TEST_EQUAL(i
.get_weight(), matching_terms
);
1906 // tests MatchAll queries
1907 // This is a regression test, which failed with assertion failures in
1908 // revision 9094. Also check that the results aren't ranked by relevance
1909 // (regression test for bug fixed in 1.0.9).
1910 DEFINE_TESTCASE(matchall1
, backend
) {
1911 Xapian::Database
db(get_database("apitest_simpledata"));
1912 Xapian::Enquire
enquire(db
);
1913 enquire
.set_query(Xapian::Query::MatchAll
);
1914 Xapian::MSet mset
= enquire
.get_mset(0, 10);
1915 TEST_EQUAL(mset
.get_matches_lower_bound(), db
.get_doccount());
1916 TEST_EQUAL(mset
.get_uncollapsed_matches_lower_bound(), db
.get_doccount());
1918 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
,
1919 Xapian::Query("nosuchterm"),
1920 Xapian::Query::MatchAll
));
1921 mset
= enquire
.get_mset(0, 10);
1922 TEST_EQUAL(mset
.get_matches_lower_bound(), db
.get_doccount());
1923 TEST_EQUAL(mset
.get_uncollapsed_matches_lower_bound(), db
.get_doccount());
1925 // Check that the results aren't ranked by relevance (fixed in 1.0.9).
1926 TEST(mset
.size() > 1);
1927 TEST_EQUAL(mset
[mset
.size() - 1].get_weight(), 0);
1928 TEST_EQUAL(*mset
[0], 1);
1929 TEST_EQUAL(*mset
[mset
.size() - 1], mset
.size());
1934 // Test using a ValueSetMatchDecider
1935 DEFINE_TESTCASE(valuesetmatchdecider2
, backend
&& !remote
) {
1936 Xapian::Database
db(get_database("apitest_phrase"));
1937 Xapian::Enquire
enq(db
);
1938 enq
.set_query(Xapian::Query("leav"));
1940 Xapian::ValueSetMatchDecider
vsmd1(1, true);
1941 vsmd1
.add_value("n");
1942 Xapian::ValueSetMatchDecider
vsmd2(1, false);
1943 vsmd2
.add_value("n");
1945 Xapian::MSet mymset
= enq
.get_mset(0, 20);
1946 mset_expect_order(mymset
, 8, 6, 4, 5, 7, 10, 12, 11, 13, 9, 14);
1947 mymset
= enq
.get_mset(0, 20, 0, NULL
, &vsmd1
);
1948 mset_expect_order(mymset
, 6, 12);
1949 mymset
= enq
.get_mset(0, 20, 0, NULL
, &vsmd2
);
1950 mset_expect_order(mymset
, 8, 4, 5, 7, 10, 11, 13, 9, 14);