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,2017 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);
114 } catch (Xapian::FeatureUnavailableError
&) {
115 #ifdef XAPIAN_HAS_REMOTE_BACKEND
121 Xapian::Database
db(dbpath
);
122 Xapian::Enquire
enquire(db
);
123 enquire
.set_query(Xapian::Query("word"));
124 enquire
.get_mset(0, 10);
125 } catch (Xapian::FeatureUnavailableError
&) {
126 #ifdef XAPIAN_HAS_REMOTE_BACKEND
133 out
<< "remote" << endl
;
136 // Quietly ignored prior to 1.4.1.
137 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
138 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
)
141 // Quietly ignored prior to 1.4.1.
142 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
143 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
)
146 #ifdef XAPIAN_HAS_REMOTE_BACKEND
147 # define EXPECTED_EXCEPTION Xapian::DatabaseOpeningError
149 # define EXPECTED_EXCEPTION Xapian::FeatureUnavailableError
154 out
<< "remote foo" << endl
;
157 // Quietly ignored prior to 1.4.1.
158 TEST_EXCEPTION(EXPECTED_EXCEPTION
,
159 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
)
162 // Quietly ignored prior to 1.4.1.
163 TEST_EXCEPTION(EXPECTED_EXCEPTION
,
164 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
)
167 #ifdef XAPIAN_HAS_REMOTE_BACKEND
170 out
<< "remote [::1]:65535" << endl
;
174 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
175 } catch (const Xapian::NetworkError
& e
) {
176 // 1.4.0 threw (on Linux) the confusing message:
177 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
178 // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
179 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (nodename nor servname provided, or not known)
180 // or on OS X (EAI_NONAME):
181 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (Address family for hostname not supported)
183 // But NetBSD seems to resolve ::1 to an IPv4 address and then tries
184 // to connect to it (which hopefully fails), so just test the message
185 // doesn't match the bad 1.4.0 result.
186 TEST(e
.get_msg().find("host [") == string::npos
);
190 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
);
191 } catch (const Xapian::NetworkError
& e
) {
192 // 1.4.0 threw (Linux):
193 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
194 // 1.4.1 throws (because we don't actually support IPv6 yet) on Linux (EAI_ADDRFAMILY):
195 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (nodename nor servname provided, or not known)
196 // or on OS X (EAI_NONAME):
197 // NetworkError: Couldn't resolve host ::1 (context: remote:tcp(::1:65535)) (Address family for hostname not supported)
198 // So we test the message instead of the error string for portability.
200 // But NetBSD seems to resolve ::1 to an IPv4 address and then tries
201 // to connect to it (which hopefully fails), so just test the message
202 // doesn't match the bad 1.4.0 result.
203 TEST(e
.get_msg().find("host [") == string::npos
);
209 // Invalid - the port number is required.
210 out
<< "remote [::1]" << endl
;
214 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
215 TEST_EXCEPTION(EXPECTED_EXCEPTION
,
216 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
220 // NetworkError: Couldn't resolve host [ (context: remote:tcp([:0)) (No address associated with hostname)
221 TEST_EXCEPTION(EXPECTED_EXCEPTION
,
222 Xapian::WritableDatabase
db(dbpath
, Xapian::DB_BACKEND_STUB
);
228 // Regression test - bad entries were ignored after a good entry prior to 1.0.8.
229 DEFINE_TESTCASE(stubdb3
, backend
&& !inmemory
&& !remote
) {
230 // Only works for backends which have a path.
231 mkdir(".stub", 0755);
232 const char * dbpath
= ".stub/stubdb3";
233 ofstream
out(dbpath
);
235 out
<< "auto ../" << get_database_path("apitest_simpledata") << "\n"
239 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
240 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
242 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
243 Xapian::Database
db(dbpath
));
248 // Test a stub database with just a bad entry.
249 DEFINE_TESTCASE(stubdb4
, backend
&& !inmemory
&& !remote
) {
250 // Only works for backends which have a path.
251 mkdir(".stub", 0755);
252 const char * dbpath
= ".stub/stubdb4";
253 ofstream
out(dbpath
);
255 out
<< "bad line here\n";
258 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
259 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
261 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
262 Xapian::Database
db(dbpath
));
267 // Test a stub database with a bad entry with no spaces (prior to 1.1.0 this
268 // was deliberately allowed, though not documented.
269 DEFINE_TESTCASE(stubdb5
, backend
&& !inmemory
&& !remote
) {
270 // Only works for backends which have a path.
271 mkdir(".stub", 0755);
272 const char * dbpath
= ".stub/stubdb5";
273 ofstream
out(dbpath
);
276 "auto ../" << get_database_path("apitest_simpledata") << endl
;
279 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
280 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
));
282 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
283 Xapian::Database
db(dbpath
));
288 // Test a stub database with an inmemory database (new feature in 1.1.0).
289 DEFINE_TESTCASE(stubdb6
, inmemory
) {
290 mkdir(".stub", 0755);
291 const char * dbpath
= ".stub/stubdb6";
292 ofstream
out(dbpath
);
299 Xapian::Database
db(dbpath
, Xapian::DB_BACKEND_STUB
);
300 TEST_EQUAL(db
.get_doccount(), 0);
301 Xapian::Enquire
enquire(db
);
302 enquire
.set_query(Xapian::Query("word"));
303 Xapian::MSet mset
= enquire
.get_mset(0, 10);
307 Xapian::Database
db(dbpath
);
308 TEST_EQUAL(db
.get_doccount(), 0);
309 Xapian::Enquire
enquire(db
);
310 enquire
.set_query(Xapian::Query("word"));
311 Xapian::MSet mset
= enquire
.get_mset(0, 10);
317 Xapian::WritableDatabase
db(dbpath
,
318 Xapian::DB_OPEN
|Xapian::DB_BACKEND_STUB
);
319 TEST_EQUAL(db
.get_doccount(), 0);
320 db
.add_document(Xapian::Document());
321 TEST_EQUAL(db
.get_doccount(), 1);
324 Xapian::WritableDatabase
db(dbpath
,
325 Xapian::DB_OPEN
|Xapian::DB_BACKEND_STUB
);
326 TEST_EQUAL(db
.get_doccount(), 0);
327 db
.add_document(Xapian::Document());
328 TEST_EQUAL(db
.get_doccount(), 1);
334 /// Test error running Database::check() on a stub database.
335 // Regression test - in 1.4.3 and earlier this threw
336 // Xapian::DatabaseError.
337 DEFINE_TESTCASE(stubdb8
, inmemory
) {
338 mkdir(".stub", 0755);
339 const char * dbpath
= ".stub/stubdb8";
340 ofstream
out(dbpath
);
346 Xapian::Database::check(dbpath
);
347 FAIL_TEST("Managed to check inmemory stub");
348 } catch (const Xapian::DatabaseOpeningError
& e
) {
349 // Check the message is appropriate.
350 TEST_STRINGS_EQUAL(e
.get_msg(),
351 "File is not a Xapian database or database table");
356 #if 0 // the "force error" mechanism is no longer in place...
357 class MyErrorHandler
: public Xapian::ErrorHandler
{
361 bool handle_error(Xapian::Error
& error
) {
363 tout
<< "Error handling caught: " << error
.get_description()
364 << ", count is now " << count
<< "\n";
368 MyErrorHandler() : count (0) {}
371 // tests error handler in multimatch().
372 DEFINE_TESTCASE(multierrhandler1
, backend
) {
373 MyErrorHandler myhandler
;
375 Xapian::Database
mydb2(get_database("apitest_simpledata"));
376 Xapian::Database
mydb3(get_database("apitest_simpledata2"));
378 for (int testcount
= 0; testcount
< 14; testcount
++) {
379 tout
<< "testcount=" << testcount
<< "\n";
380 Xapian::Database
mydb4(get_database("-e", "apitest_termorder"));
381 Xapian::Database
mydb5(get_network_database("apitest_termorder", 1));
382 Xapian::Database
mydb6(get_database("-e2", "apitest_termorder"));
383 Xapian::Database
mydb7(get_database("-e3", "apitest_simpledata"));
385 Xapian::Database dbs
;
388 dbs
.add_database(mydb2
);
389 dbs
.add_database(mydb3
);
390 dbs
.add_database(mydb4
);
393 dbs
.add_database(mydb4
);
394 dbs
.add_database(mydb2
);
395 dbs
.add_database(mydb3
);
398 dbs
.add_database(mydb3
);
399 dbs
.add_database(mydb4
);
400 dbs
.add_database(mydb2
);
403 dbs
.add_database(mydb2
);
404 dbs
.add_database(mydb3
);
405 dbs
.add_database(mydb5
);
409 dbs
.add_database(mydb5
);
410 dbs
.add_database(mydb2
);
411 dbs
.add_database(mydb3
);
415 dbs
.add_database(mydb3
);
416 dbs
.add_database(mydb5
);
417 dbs
.add_database(mydb2
);
421 dbs
.add_database(mydb2
);
422 dbs
.add_database(mydb3
);
423 dbs
.add_database(mydb6
);
426 dbs
.add_database(mydb6
);
427 dbs
.add_database(mydb2
);
428 dbs
.add_database(mydb3
);
431 dbs
.add_database(mydb3
);
432 dbs
.add_database(mydb6
);
433 dbs
.add_database(mydb2
);
436 dbs
.add_database(mydb2
);
437 dbs
.add_database(mydb3
);
438 dbs
.add_database(mydb7
);
441 dbs
.add_database(mydb7
);
442 dbs
.add_database(mydb2
);
443 dbs
.add_database(mydb3
);
446 dbs
.add_database(mydb3
);
447 dbs
.add_database(mydb7
);
448 dbs
.add_database(mydb2
);
451 dbs
.add_database(mydb2
);
452 dbs
.add_database(mydb6
);
453 dbs
.add_database(mydb7
);
456 dbs
.add_database(mydb2
);
457 dbs
.add_database(mydb7
);
458 dbs
.add_database(mydb6
);
461 tout
<< "db=" << dbs
<< "\n";
462 Xapian::Enquire
enquire(dbs
, &myhandler
);
465 Xapian::Query myquery
= query(Xapian::Query::OP_OR
, "inmemory", "word");
466 enquire
.set_weighting_scheme(Xapian::BoolWeight());
467 enquire
.set_query(myquery
);
469 tout
<< "query=" << myquery
<< "\n";
470 // retrieve the top ten results
471 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
474 case 0: case 3: case 6: case 9:
475 mset_expect_order(mymset
, 2, 4, 10);
477 case 1: case 4: case 7: case 10:
478 mset_expect_order(mymset
, 3, 5, 11);
480 case 2: case 5: case 8: case 11:
481 mset_expect_order(mymset
, 1, 6, 12);
485 mset_expect_order(mymset
, 4, 10);
489 TEST_EQUAL(myhandler
.count
, errcount
);
497 class GrepMatchDecider
: public Xapian::MatchDecider
{
500 explicit GrepMatchDecider(const string
& needle_
)
503 bool operator()(const Xapian::Document
&doc
) const {
504 // Note that this is not recommended usage of get_data()
505 return doc
.get_data().find(needle
) != string::npos
;
509 // Test Xapian::MatchDecider functor.
510 DEFINE_TESTCASE(matchdecider1
, backend
&& !remote
) {
511 Xapian::Database
db(get_database("apitest_simpledata"));
512 Xapian::Enquire
enquire(db
);
513 enquire
.set_query(Xapian::Query("this"));
515 GrepMatchDecider
myfunctor("This is");
517 Xapian::MSet mymset
= enquire
.get_mset(0, 100, 0, &myfunctor
);
519 vector
<bool> docid_checked(db
.get_lastdocid());
521 // Check that we get the expected number of matches, and that they
522 // satisfy the condition.
523 Xapian::MSetIterator i
= mymset
.begin();
524 TEST(i
!= mymset
.end());
525 TEST_EQUAL(mymset
.size(), 3);
526 TEST_EQUAL(mymset
.get_matches_lower_bound(), 3);
527 TEST_EQUAL(mymset
.get_matches_upper_bound(), 3);
528 TEST_EQUAL(mymset
.get_matches_estimated(), 3);
529 TEST_EQUAL(mymset
.get_uncollapsed_matches_lower_bound(), 3);
530 TEST_EQUAL(mymset
.get_uncollapsed_matches_upper_bound(), 3);
531 TEST_EQUAL(mymset
.get_uncollapsed_matches_estimated(), 3);
532 for ( ; i
!= mymset
.end(); ++i
) {
533 const Xapian::Document
doc(i
.get_document());
534 TEST(myfunctor(doc
));
535 docid_checked
[*i
] = true;
538 // Check that there are some documents which aren't accepted by the match
540 mymset
= enquire
.get_mset(0, 100);
541 TEST(mymset
.size() > 3);
543 // Check that the bounds are appropriate even if we don't ask for any
545 mymset
= enquire
.get_mset(0, 0, 0, &myfunctor
);
546 TEST_EQUAL(mymset
.size(), 0);
547 TEST_EQUAL(mymset
.get_matches_lower_bound(), 0);
548 TEST_EQUAL(mymset
.get_matches_upper_bound(), 6);
549 TEST_REL(mymset
.get_matches_estimated(),>,0);
550 TEST_REL(mymset
.get_matches_estimated(),<=,6);
551 TEST_EQUAL(mymset
.get_uncollapsed_matches_lower_bound(), 0);
552 TEST_EQUAL(mymset
.get_uncollapsed_matches_upper_bound(), 6);
553 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
554 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
556 // Check that the bounds are appropriate if we ask for only one hit.
557 // (Regression test - until SVN 10256, we didn't reduce the lower_bound
558 // appropriately, and returned 6 here.)
559 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
560 TEST_EQUAL(mymset
.size(), 1);
561 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
562 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
563 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
564 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
565 TEST_REL(mymset
.get_matches_estimated(),>,0);
566 TEST_REL(mymset
.get_matches_estimated(),<=,6);
567 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
568 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
569 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
570 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
571 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
572 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
574 // Check that the other documents don't satisfy the condition.
575 for (Xapian::docid did
= 1; did
< docid_checked
.size(); ++did
) {
576 if (!docid_checked
[did
]) {
577 TEST(!myfunctor(db
.get_document(did
)));
581 // Check that the bounds are appropriate if a collapse key is used.
582 // Use a value which is never set so we don't actually discard anything.
583 enquire
.set_collapse_key(99);
584 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
585 TEST_EQUAL(mymset
.size(), 1);
586 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
587 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
588 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
589 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
590 TEST_REL(mymset
.get_matches_estimated(),>,0);
591 TEST_REL(mymset
.get_matches_estimated(),<=,6);
592 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
593 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
594 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
595 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
596 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
597 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
599 // Check that the bounds are appropriate if a percentage cutoff is in
600 // use. Set a 1% threshold so we don't actually discard anything.
601 enquire
.set_collapse_key(Xapian::BAD_VALUENO
);
602 enquire
.set_cutoff(1);
603 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
604 TEST_EQUAL(mymset
.size(), 1);
605 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
606 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
607 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
608 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
609 TEST_REL(mymset
.get_matches_estimated(),>,0);
610 TEST_REL(mymset
.get_matches_estimated(),<=,6);
611 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
612 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
613 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
614 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
615 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
616 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
618 // And now with both a collapse key and percentage cutoff.
619 enquire
.set_collapse_key(99);
620 mymset
= enquire
.get_mset(0, 1, 0, &myfunctor
);
621 TEST_EQUAL(mymset
.size(), 1);
622 TEST_REL(mymset
.get_matches_lower_bound(),>=,1);
623 TEST_REL(mymset
.get_matches_lower_bound(),<=,3);
624 TEST_REL(mymset
.get_matches_upper_bound(),>=,3);
625 TEST_REL(mymset
.get_matches_upper_bound(),<=,6);
626 TEST_REL(mymset
.get_matches_estimated(),>,0);
627 TEST_REL(mymset
.get_matches_estimated(),<=,6);
628 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),>=,1);
629 TEST_REL(mymset
.get_uncollapsed_matches_lower_bound(),<=,3);
630 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),>=,3);
631 TEST_REL(mymset
.get_uncollapsed_matches_upper_bound(),<=,6);
632 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),>,0);
633 TEST_REL(mymset
.get_uncollapsed_matches_estimated(),<=,6);
638 // Test Xapian::MatchDecider functor used as a match spy.
639 DEFINE_TESTCASE(matchdecider2
, backend
&& !remote
) {
640 Xapian::Database
db(get_database("apitest_simpledata"));
641 Xapian::Enquire
enquire(db
);
642 enquire
.set_query(Xapian::Query("this"));
644 GrepMatchDecider
myfunctor("This is");
646 Xapian::MSet mymset
= enquire
.get_mset(0, 100, 0, NULL
, &myfunctor
);
648 vector
<bool> docid_checked(db
.get_lastdocid());
650 // Check that we get the expected number of matches, and that they
651 // satisfy the condition.
652 Xapian::MSetIterator i
= mymset
.begin();
653 TEST(i
!= mymset
.end());
654 TEST_EQUAL(mymset
.size(), 3);
655 for ( ; i
!= mymset
.end(); ++i
) {
656 const Xapian::Document
doc(i
.get_document());
657 TEST(myfunctor(doc
));
658 docid_checked
[*i
] = true;
661 // Check that the other documents don't satisfy the condition.
662 for (Xapian::docid did
= 1; did
< docid_checked
.size(); ++did
) {
663 if (!docid_checked
[did
]) {
664 TEST(!myfunctor(db
.get_document(did
)));
671 // Regression test for lower bound using functor, sorting and collapsing.
672 DEFINE_TESTCASE(matchdecider3
, backend
&& !remote
) {
673 Xapian::Database
db(get_database("etext"));
674 Xapian::Enquire
enquire(db
);
675 enquire
.set_query(Xapian::Query(""));
676 enquire
.set_collapse_key(12);
677 enquire
.set_sort_by_value(11, true);
679 GrepMatchDecider
myfunctor("We produce");
681 Xapian::MSet mset1
= enquire
.get_mset(0, 2, 0, NULL
, &myfunctor
);
682 Xapian::MSet mset2
= enquire
.get_mset(0, 1000, 0, NULL
, &myfunctor
);
684 // mset2 should contain all the hits, so the statistics should be exact.
685 TEST_EQUAL(mset2
.get_matches_estimated(), mset2
.size());
686 TEST_EQUAL(mset2
.get_matches_lower_bound(), mset2
.get_matches_estimated());
687 TEST_EQUAL(mset2
.get_matches_estimated(), mset2
.get_matches_upper_bound());
689 TEST_REL(mset2
.get_uncollapsed_matches_lower_bound(),<=,mset2
.get_uncollapsed_matches_estimated());
690 TEST_REL(mset2
.get_uncollapsed_matches_estimated(),<=,mset2
.get_uncollapsed_matches_upper_bound());
692 // Check that the lower bound in mset1 is not greater than the known
693 // number of hits. This failed until revision 10811.
694 TEST_REL(mset1
.get_matches_lower_bound(),<=,mset2
.size());
696 // Check that the bounds for mset1 make sense.
697 TEST_REL(mset1
.get_matches_lower_bound(),<=,mset1
.get_matches_estimated());
698 TEST_REL(mset1
.get_matches_estimated(),<=,mset1
.get_matches_upper_bound());
699 TEST_REL(mset1
.size(),<=,mset1
.get_matches_upper_bound());
701 TEST_REL(mset1
.get_uncollapsed_matches_lower_bound(),<=,mset1
.get_uncollapsed_matches_estimated());
702 TEST_REL(mset1
.get_uncollapsed_matches_estimated(),<=,mset1
.get_uncollapsed_matches_upper_bound());
704 // The uncollapsed match would match all documents but the one the
705 // matchdecider rejects.
706 TEST_REL(mset1
.get_uncollapsed_matches_upper_bound(),>=,db
.get_doccount() - 1);
707 TEST_REL(mset1
.get_uncollapsed_matches_upper_bound(),<=,db
.get_doccount());
708 TEST_REL(mset2
.get_uncollapsed_matches_upper_bound(),>=,db
.get_doccount() - 1);
709 TEST_REL(mset2
.get_uncollapsed_matches_upper_bound(),<=,db
.get_doccount());
714 // tests that mset iterators on msets compare correctly.
715 DEFINE_TESTCASE(msetiterator1
, backend
) {
716 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
717 enquire
.set_query(Xapian::Query("this"));
718 Xapian::MSet mymset
= enquire
.get_mset(0, 2);
720 Xapian::MSetIterator j
;
722 Xapian::MSetIterator k
= mymset
.end();
723 Xapian::MSetIterator
l(j
);
724 Xapian::MSetIterator
m(k
);
725 Xapian::MSetIterator n
= mymset
.begin();
726 Xapian::MSetIterator o
= mymset
.begin();
727 TEST_NOT_EQUAL(j
, k
);
728 TEST_NOT_EQUAL(l
, m
);
738 TEST_NOT_EQUAL(j
, k
);
739 TEST_NOT_EQUAL(k
, l
);
740 TEST_NOT_EQUAL(k
, m
);
741 TEST_NOT_EQUAL(k
, o
);
745 TEST_NOT_EQUAL(j
, k
);
746 TEST_NOT_EQUAL(k
, l
);
751 TEST_NOT_EQUAL(n
, l
);
753 TEST_NOT_EQUAL(n
, mymset
.begin());
754 TEST_EQUAL(n
, mymset
.end());
759 // tests that mset iterators on empty msets compare equal.
760 DEFINE_TESTCASE(msetiterator2
, backend
) {
761 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
762 enquire
.set_query(Xapian::Query("this"));
763 Xapian::MSet mymset
= enquire
.get_mset(0, 0);
765 Xapian::MSetIterator j
= mymset
.begin();
766 Xapian::MSetIterator k
= mymset
.end();
767 Xapian::MSetIterator
l(j
);
768 Xapian::MSetIterator
m(k
);
779 // tests that begin().get_document() works when first != 0
780 DEFINE_TESTCASE(msetiterator3
, backend
) {
781 Xapian::Database
mydb(get_database("apitest_simpledata"));
782 Xapian::Enquire
enquire(mydb
);
783 enquire
.set_query(Xapian::Query("this"));
785 Xapian::MSet mymset
= enquire
.get_mset(2, 10);
787 TEST(!mymset
.empty());
788 Xapian::Document
doc(mymset
.begin().get_document());
789 TEST(!doc
.get_data().empty());
794 // tests that eset iterators on empty esets compare equal.
795 DEFINE_TESTCASE(esetiterator1
, backend
) {
796 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
797 enquire
.set_query(Xapian::Query("this"));
799 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
800 TEST(mymset
.size() >= 2);
803 Xapian::MSetIterator i
= mymset
.begin();
804 myrset
.add_document(*i
);
805 myrset
.add_document(*(++i
));
807 Xapian::ESet myeset
= enquire
.get_eset(2, myrset
);
808 Xapian::ESetIterator j
;
810 Xapian::ESetIterator k
= myeset
.end();
811 Xapian::ESetIterator
l(j
);
812 Xapian::ESetIterator
m(k
);
813 Xapian::ESetIterator n
= myeset
.begin();
815 TEST_NOT_EQUAL(j
, k
);
816 TEST_NOT_EQUAL(l
, m
);
825 TEST_NOT_EQUAL(j
, k
);
826 TEST_NOT_EQUAL(k
, l
);
827 TEST_NOT_EQUAL(k
, m
);
829 TEST_NOT_EQUAL(j
, k
);
830 TEST_NOT_EQUAL(k
, l
);
835 TEST_NOT_EQUAL(n
, l
);
837 TEST_NOT_EQUAL(n
, myeset
.begin());
838 TEST_EQUAL(n
, myeset
.end());
843 // tests that eset iterators on empty esets compare equal.
844 DEFINE_TESTCASE(esetiterator2
, backend
) {
845 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
846 enquire
.set_query(Xapian::Query("this"));
848 Xapian::MSet mymset
= enquire
.get_mset(0, 10);
849 TEST(mymset
.size() >= 2);
852 Xapian::MSetIterator i
= mymset
.begin();
853 myrset
.add_document(*i
);
854 myrset
.add_document(*(++i
));
856 Xapian::ESet myeset
= enquire
.get_eset(0, myrset
);
857 Xapian::ESetIterator j
= myeset
.begin();
858 Xapian::ESetIterator k
= myeset
.end();
859 Xapian::ESetIterator
l(j
);
860 Xapian::ESetIterator
m(k
);
871 // tests the collapse-on-key
872 DEFINE_TESTCASE(collapsekey1
, backend
) {
873 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
874 enquire
.set_query(Xapian::Query("this"));
876 Xapian::MSet mymset1
= enquire
.get_mset(0, 100);
877 Xapian::doccount mymsize1
= mymset1
.size();
879 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
880 enquire
.set_collapse_key(value_no
);
881 Xapian::MSet mymset
= enquire
.get_mset(0, 100);
883 TEST_AND_EXPLAIN(mymsize1
> mymset
.size(),
884 "Had no fewer items when performing collapse: don't know whether it worked.");
886 map
<string
, Xapian::docid
> values
;
887 Xapian::MSetIterator i
= mymset
.begin();
888 for ( ; i
!= mymset
.end(); ++i
) {
889 string value
= i
.get_document().get_value(value_no
);
890 TEST(values
[value
] == 0 || value
.empty());
898 // tests that collapse-on-key modifies the predicted bounds for the number of
899 // matches appropriately.
900 DEFINE_TESTCASE(collapsekey2
, backend
) {
901 SKIP_TEST("Don't have a suitable database currently");
902 // FIXME: this needs an appropriate database creating, but that's quite
903 // subtle to do it seems.
904 Xapian::Enquire
enquire(get_database("apitest_simpledata2"));
905 enquire
.set_query(Xapian::Query("this"));
907 Xapian::MSet mset1
= enquire
.get_mset(0, 1);
909 // Test that if no duplicates are found, then the upper bound remains
910 // unchanged and the lower bound drops.
912 enquire
.set_query(Xapian::Query("this"));
913 Xapian::valueno value_no
= 3;
914 enquire
.set_collapse_key(value_no
);
915 Xapian::MSet mset
= enquire
.get_mset(0, 1);
917 TEST_REL(mset
.get_matches_lower_bound(),<,mset1
.get_matches_lower_bound());
918 TEST_EQUAL(mset
.get_matches_upper_bound(), mset1
.get_matches_upper_bound());
924 // tests that collapse-on-key modifies the predicted bounds for the number of
925 // matches appropriately.
926 DEFINE_TESTCASE(collapsekey3
, backend
) {
927 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
928 enquire
.set_query(Xapian::Query("this"));
930 Xapian::MSet mymset1
= enquire
.get_mset(0, 3);
932 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
933 enquire
.set_collapse_key(value_no
);
934 Xapian::MSet mymset
= enquire
.get_mset(0, 3);
936 TEST_AND_EXPLAIN(mymset1
.get_matches_lower_bound() > mymset
.get_matches_lower_bound(),
937 "Lower bound was not lower when performing collapse: don't know whether it worked.");
938 TEST_AND_EXPLAIN(mymset1
.get_matches_upper_bound() > mymset
.get_matches_upper_bound(),
939 "Upper bound was not lower when performing collapse: don't know whether it worked.");
941 map
<string
, Xapian::docid
> values
;
942 Xapian::MSetIterator i
= mymset
.begin();
943 for ( ; i
!= mymset
.end(); ++i
) {
944 string value
= i
.get_document().get_value(value_no
);
945 TEST(values
[value
] == 0 || value
.empty());
950 // Test that if the collapse value is always empty, then the upper bound
951 // remains unchanged, and the lower bound is the same or lower (it can be
952 // lower because the matcher counts the number of documents with empty
953 // collapse keys, but may have rejected a document because its weight is
954 // too low for the proto-MSet before it even looks at its collapse key).
956 Xapian::valueno value_no
= 1000;
957 enquire
.set_collapse_key(value_no
);
958 Xapian::MSet mymset
= enquire
.get_mset(0, 3);
960 TEST(mymset
.get_matches_lower_bound() <= mymset1
.get_matches_lower_bound());
961 TEST_EQUAL(mymset
.get_matches_upper_bound(), mymset1
.get_matches_upper_bound());
963 map
<string
, Xapian::docid
> values
;
964 Xapian::MSetIterator i
= mymset
.begin();
965 for ( ; i
!= mymset
.end(); ++i
) {
966 string value
= i
.get_document().get_value(value_no
);
967 TEST(values
[value
] == 0 || value
.empty());
975 // tests that collapse-on-key modifies the predicted bounds for the number of
976 // matches appropriately even when no results are requested.
977 DEFINE_TESTCASE(collapsekey4
, backend
) {
978 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
979 enquire
.set_query(Xapian::Query("this"));
981 Xapian::MSet mymset1
= enquire
.get_mset(0, 0);
983 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
984 enquire
.set_collapse_key(value_no
);
985 Xapian::MSet mymset
= enquire
.get_mset(0, 0);
987 TEST_AND_EXPLAIN(mymset
.get_matches_lower_bound() == 1,
988 "Lower bound was not 1 when performing collapse but not asking for any results.");
989 TEST_AND_EXPLAIN(mymset1
.get_matches_upper_bound() == mymset
.get_matches_upper_bound(),
990 "Upper bound was changed when performing collapse but not asking for any results.");
992 map
<string
, Xapian::docid
> values
;
993 Xapian::MSetIterator i
= mymset
.begin();
994 for ( ; i
!= mymset
.end(); ++i
) {
995 string value
= i
.get_document().get_value(value_no
);
996 TEST(values
[value
] == 0 || value
.empty());
1004 // test for keepalives
1005 DEFINE_TESTCASE(keepalive1
, remote
) {
1006 Xapian::Database
db(get_remote_database("apitest_simpledata", 5000));
1008 /* Test that keep-alives work */
1009 for (int i
= 0; i
< 10; ++i
) {
1013 Xapian::Enquire
enquire(db
);
1014 enquire
.set_query(Xapian::Query("word"));
1015 enquire
.get_mset(0, 10);
1017 /* Test that things break without keepalives */
1019 enquire
.set_query(Xapian::Query("word"));
1020 TEST_EXCEPTION(Xapian::NetworkError
,
1021 enquire
.get_mset(0, 10));
1026 // test that iterating through all terms in a database works.
1027 DEFINE_TESTCASE(allterms1
, backend
) {
1028 Xapian::Database
db(get_database("apitest_allterms"));
1029 Xapian::TermIterator ati
= db
.allterms_begin();
1030 TEST(ati
!= db
.allterms_end());
1031 TEST_EQUAL(*ati
, "one");
1032 TEST_EQUAL(ati
.get_termfreq(), 1);
1034 Xapian::TermIterator ati2
= ati
;
1037 TEST(ati
!= db
.allterms_end());
1039 tout
<< "*ati = '" << *ati
<< "'\n";
1040 tout
<< "*ati.length = '" << (*ati
).length() << "'\n";
1041 tout
<< "*ati == \"one\" = " << (*ati
== "one") << "\n";
1042 tout
<< "*ati[3] = " << ((*ati
)[3]) << "\n";
1043 tout
<< "*ati = '" << *ati
<< "'\n";
1045 TEST(*ati
== "three");
1046 TEST(ati
.get_termfreq() == 3);
1049 TEST(ati2
!= db
.allterms_end());
1050 TEST(*ati2
== "one");
1051 TEST(ati2
.get_termfreq() == 1);
1058 TEST(ati
!= db
.allterms_end());
1059 TEST(*ati
== "two");
1060 TEST(ati
.get_termfreq() == 2);
1063 TEST(ati2
!= db
.allterms_end());
1064 TEST(*ati2
== "three");
1065 TEST(ati2
.get_termfreq() == 3);
1069 TEST(ati
== db
.allterms_end());
1074 // test that iterating through all terms in two databases works.
1075 DEFINE_TESTCASE(allterms2
, backend
) {
1076 Xapian::Database db
;
1077 db
.add_database(get_database("apitest_allterms"));
1078 db
.add_database(get_database("apitest_allterms2"));
1079 Xapian::TermIterator ati
= db
.allterms_begin();
1081 TEST(ati
!= db
.allterms_end());
1082 TEST(*ati
== "five");
1083 TEST(ati
.get_termfreq() == 2);
1086 TEST(ati
!= db
.allterms_end());
1087 TEST(*ati
== "four");
1088 TEST(ati
.get_termfreq() == 1);
1091 TEST(ati
!= db
.allterms_end());
1092 TEST(*ati
== "one");
1093 TEST(ati
.get_termfreq() == 1);
1096 TEST(ati
!= db
.allterms_end());
1097 TEST(*ati
== "six");
1098 TEST(ati
.get_termfreq() == 3);
1101 TEST(ati
!= db
.allterms_end());
1102 TEST(*ati
== "three");
1103 TEST(ati
.get_termfreq() == 3);
1106 TEST(ati
!= db
.allterms_end());
1107 TEST(*ati
== "two");
1108 TEST(ati
.get_termfreq() == 2);
1111 TEST(ati
== db
.allterms_end());
1116 // test that skip_to sets at_end (regression test)
1117 DEFINE_TESTCASE(allterms3
, backend
) {
1118 Xapian::Database db
;
1119 db
.add_database(get_database("apitest_allterms"));
1120 Xapian::TermIterator ati
= db
.allterms_begin();
1122 ati
.skip_to(string("zzzzzz"));
1123 TEST(ati
== db
.allterms_end());
1128 // test that next ignores extra entries due to long posting lists being
1129 // chunked (regression test for quartz)
1130 DEFINE_TESTCASE(allterms4
, backend
) {
1131 // apitest_allterms4 contains 682 documents each containing just the word
1132 // "foo". 682 was the magic number which started to cause Quartz problems.
1133 Xapian::Database db
= get_database("apitest_allterms4");
1135 Xapian::TermIterator i
= db
.allterms_begin();
1136 TEST(i
!= db
.allterms_end());
1138 TEST(i
.get_termfreq() == 682);
1140 TEST(i
== db
.allterms_end());
1145 // test that skip_to with an exact match sets the current term (regression test
1147 DEFINE_TESTCASE(allterms5
, backend
) {
1148 Xapian::Database db
;
1149 db
.add_database(get_database("apitest_allterms"));
1150 Xapian::TermIterator ati
= db
.allterms_begin();
1151 ati
.skip_to("three");
1152 TEST(ati
!= db
.allterms_end());
1153 TEST_EQUAL(*ati
, "three");
1158 // test allterms iterators with prefixes
1159 DEFINE_TESTCASE(allterms6
, backend
) {
1160 Xapian::Database db
;
1161 db
.add_database(get_database("apitest_allterms"));
1162 db
.add_database(get_database("apitest_allterms2"));
1164 Xapian::TermIterator ati
= db
.allterms_begin("three");
1165 TEST(ati
!= db
.allterms_end("three"));
1166 TEST_EQUAL(*ati
, "three");
1167 ati
.skip_to("three");
1168 TEST(ati
!= db
.allterms_end("three"));
1169 TEST_EQUAL(*ati
, "three");
1171 TEST(ati
== db
.allterms_end("three"));
1173 ati
= db
.allterms_begin("thre");
1174 TEST(ati
!= db
.allterms_end("thre"));
1175 TEST_EQUAL(*ati
, "three");
1176 ati
.skip_to("three");
1177 TEST(ati
!= db
.allterms_end("thre"));
1178 TEST_EQUAL(*ati
, "three");
1180 TEST(ati
== db
.allterms_end("thre"));
1182 ati
= db
.allterms_begin("f");
1183 TEST(ati
!= db
.allterms_end("f"));
1184 TEST_EQUAL(*ati
, "five");
1185 TEST(ati
!= db
.allterms_end("f"));
1186 ati
.skip_to("three");
1187 TEST(ati
== db
.allterms_end("f"));
1189 ati
= db
.allterms_begin("f");
1190 TEST(ati
!= db
.allterms_end("f"));
1191 TEST_EQUAL(*ati
, "five");
1193 TEST(ati
!= db
.allterms_end("f"));
1194 TEST_EQUAL(*ati
, "four");
1196 TEST(ati
== db
.allterms_end("f"));
1198 ati
= db
.allterms_begin("absent");
1199 TEST(ati
== db
.allterms_end("absent"));
1204 // test that searching for a term with a special characters in it works
1205 DEFINE_TESTCASE(specialterms1
, backend
) {
1206 Xapian::Enquire
enquire(get_database("apitest_space"));
1207 Xapian::MSet mymset
;
1208 Xapian::doccount count
;
1209 Xapian::MSetIterator m
;
1210 Xapian::Stem
stemmer("english");
1212 enquire
.set_query(stemmer("new\nline"));
1213 mymset
= enquire
.get_mset(0, 10);
1214 TEST_MSET_SIZE(mymset
, 1);
1216 for (m
= mymset
.begin(); m
!= mymset
.end(); ++m
) ++count
;
1217 TEST_EQUAL(count
, 1);
1219 for (Xapian::valueno value_no
= 0; value_no
< 7; ++value_no
) {
1220 string value
= mymset
.begin().get_document().get_value(value_no
);
1221 TEST_NOT_EQUAL(value
, "");
1222 if (value_no
== 0) {
1223 TEST(value
.size() > 263);
1224 TEST_EQUAL(static_cast<unsigned char>(value
[262]), 255);
1225 for (int k
= 0; k
< 256; ++k
) {
1226 TEST_EQUAL(static_cast<unsigned char>(value
[k
+ 7]), k
);
1231 enquire
.set_query(stemmer(string("big\0zero", 8)));
1232 mymset
= enquire
.get_mset(0, 10);
1233 TEST_MSET_SIZE(mymset
, 1);
1235 for (m
= mymset
.begin(); m
!= mymset
.end(); ++m
) ++count
;
1236 TEST_EQUAL(count
, 1);
1241 // test that terms with a special characters in appear correctly when iterating
1243 DEFINE_TESTCASE(specialterms2
, backend
) {
1244 Xapian::Database
db(get_database("apitest_space"));
1246 // Check the terms are all as expected (after stemming) and that allterms
1247 // copes with iterating over them.
1248 Xapian::TermIterator t
;
1249 t
= db
.allterms_begin();
1250 TEST_EQUAL(*t
, "back\\slash"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1251 TEST_EQUAL(*t
, string("big\0zero", 8)); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1252 TEST_EQUAL(*t
, "new\nlin"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1253 TEST_EQUAL(*t
, "one\x01on"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1254 TEST_EQUAL(*t
, "space man"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1255 TEST_EQUAL(*t
, "tab\tbi"); ++t
; TEST_NOT_EQUAL(t
, db
.allterms_end());
1256 TEST_EQUAL(*t
, "tu\x02tu"); ++t
; TEST_EQUAL(t
, db
.allterms_end());
1258 // Now check that skip_to exactly a term containing a zero byte works.
1259 // This is a regression test for flint and quartz - an Assert() used to
1260 // fire in debug builds (the Assert was wrong - the actual code handled
1262 t
= db
.allterms_begin();
1263 t
.skip_to(string("big\0zero", 8));
1264 TEST_NOT_EQUAL(t
, db
.allterms_end());
1265 TEST_EQUAL(*t
, string("big\0zero", 8));
1270 // test that rsets behave correctly with multiDBs
1271 DEFINE_TESTCASE(rsetmultidb2
, backend
&& !multi
) {
1272 Xapian::Database
mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1273 Xapian::Database
mydb2(get_database("apitest_rset"));
1274 mydb2
.add_database(get_database("apitest_simpledata2"));
1276 Xapian::Enquire
enquire1(mydb1
);
1277 Xapian::Enquire
enquire2(mydb2
);
1279 Xapian::Query myquery
= query("is");
1281 enquire1
.set_query(myquery
);
1282 enquire2
.set_query(myquery
);
1284 Xapian::RSet myrset1
;
1285 Xapian::RSet myrset2
;
1286 myrset1
.add_document(4);
1287 myrset2
.add_document(2);
1289 Xapian::MSet mymset1a
= enquire1
.get_mset(0, 10);
1290 Xapian::MSet mymset1b
= enquire1
.get_mset(0, 10, &myrset1
);
1291 Xapian::MSet mymset2a
= enquire2
.get_mset(0, 10);
1292 Xapian::MSet mymset2b
= enquire2
.get_mset(0, 10, &myrset2
);
1294 mset_expect_order(mymset1a
, 4, 3);
1295 mset_expect_order(mymset1b
, 4, 3);
1296 mset_expect_order(mymset2a
, 2, 5);
1297 mset_expect_order(mymset2b
, 2, 5);
1299 TEST(mset_range_is_same_weights(mymset1a
, 0, mymset2a
, 0, 2));
1300 TEST(mset_range_is_same_weights(mymset1b
, 0, mymset2b
, 0, 2));
1301 TEST_NOT_EQUAL(mymset1a
, mymset1b
);
1302 TEST_NOT_EQUAL(mymset2a
, mymset2b
);
1307 // tests an expand across multiple databases
1308 DEFINE_TESTCASE(multiexpand1
, backend
&& !multi
) {
1309 Xapian::Database
mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1310 Xapian::Enquire
enquire1(mydb1
);
1312 Xapian::Database
mydb2(get_database("apitest_simpledata"));
1313 mydb2
.add_database(get_database("apitest_simpledata2"));
1314 Xapian::Enquire
enquire2(mydb2
);
1316 // make simple equivalent rsets, with a document from each database in each.
1319 rset1
.add_document(1);
1320 rset1
.add_document(7);
1321 rset2
.add_document(1);
1322 rset2
.add_document(2);
1324 // Retrieve all the ESet results in each of the three setups:
1326 // This is the single database one.
1327 Xapian::ESet eset1
= enquire1
.get_eset(1000, rset1
);
1329 // This is the multi database with approximation
1330 Xapian::ESet eset2
= enquire2
.get_eset(1000, rset2
);
1332 // This is the multi database without approximation
1333 Xapian::ESet eset3
= enquire2
.get_eset(1000, rset2
, Xapian::Enquire::USE_EXACT_TERMFREQ
);
1335 TEST_EQUAL(eset1
.size(), eset3
.size());
1337 Xapian::ESetIterator i
= eset1
.begin();
1338 Xapian::ESetIterator j
= eset3
.begin();
1339 while (i
!= eset1
.end() && j
!= eset3
.end()) {
1341 TEST_EQUAL(i
.get_weight(), j
.get_weight());
1345 TEST(i
== eset1
.end());
1346 TEST(j
== eset3
.end());
1348 bool eset1_eq_eset2
= true;
1351 while (i
!= eset1
.end() && j
!= eset2
.end()) {
1352 if (i
.get_weight() != j
.get_weight()) {
1353 eset1_eq_eset2
= false;
1359 TEST(!eset1_eq_eset2
);
1364 // tests that opening a non-existent postlist returns an empty list
1365 DEFINE_TESTCASE(postlist1
, backend
) {
1366 Xapian::Database
db(get_database("apitest_simpledata"));
1368 TEST_EQUAL(db
.postlist_begin("rosebud"), db
.postlist_end("rosebud"));
1370 string s
= "let_us_see_if_we_can_break_it_with_a_really_really_long_term.";
1371 for (int i
= 0; i
< 8; ++i
) {
1373 TEST_EQUAL(db
.postlist_begin(s
), db
.postlist_end(s
));
1376 // A regression test (no, really!)
1377 TEST_NOT_EQUAL(db
.postlist_begin("a"), db
.postlist_end("a"));
1382 // tests that a Xapian::PostingIterator works as an STL iterator
1383 DEFINE_TESTCASE(postlist2
, backend
) {
1384 Xapian::Database
db(get_database("apitest_simpledata"));
1385 Xapian::PostingIterator p
;
1386 p
= db
.postlist_begin("this");
1387 Xapian::PostingIterator pend
= db
.postlist_end("this");
1389 TEST(p
.get_description() != "PostingIterator()");
1391 // test operator= creates a copy which compares equal
1392 Xapian::PostingIterator p_copy
= p
;
1393 TEST_EQUAL(p
, p_copy
);
1395 TEST(p_copy
.get_description() != "PostingIterator()");
1397 // test copy constructor creates a copy which compares equal
1398 Xapian::PostingIterator
p_clone(p
);
1399 TEST_EQUAL(p
, p_clone
);
1401 TEST(p_clone
.get_description() != "PostingIterator()");
1403 vector
<Xapian::docid
> v(p
, pend
);
1405 p
= db
.postlist_begin("this");
1406 pend
= db
.postlist_end("this");
1407 vector
<Xapian::docid
>::const_iterator i
;
1408 for (i
= v
.begin(); i
!= v
.end(); ++i
) {
1409 TEST_NOT_EQUAL(p
, pend
);
1413 TEST_EQUAL(p
, pend
);
1415 TEST_STRINGS_EQUAL(p
.get_description(), "PostingIterator()");
1416 TEST_STRINGS_EQUAL(pend
.get_description(), "PostingIterator()");
1421 // tests that a Xapian::PostingIterator still works when the DB is deleted
1422 DEFINE_TESTCASE(postlist3
, backend
) {
1423 Xapian::PostingIterator u
;
1425 Xapian::Database
db_temp(get_database("apitest_simpledata"));
1426 u
= db_temp
.postlist_begin("this");
1429 Xapian::Database
db(get_database("apitest_simpledata"));
1430 Xapian::PostingIterator p
= db
.postlist_begin("this");
1431 Xapian::PostingIterator pend
= db
.postlist_end("this");
1442 DEFINE_TESTCASE(postlist4
, backend
) {
1443 Xapian::Database
db(get_database("apitest_simpledata"));
1444 Xapian::PostingIterator i
= db
.postlist_begin("this");
1446 i
.skip_to(999999999);
1447 TEST(i
== db
.postlist_end("this"));
1451 // tests long postlists
1452 DEFINE_TESTCASE(postlist5
, backend
) {
1453 Xapian::Database
db(get_database("apitest_manydocs"));
1454 TEST_EQUAL_DOUBLE(db
.get_avlength(), 4);
1455 Xapian::PostingIterator i
= db
.postlist_begin("this");
1457 while (i
!= db
.postlist_end("this")) {
1466 // tests document length in postlists
1467 DEFINE_TESTCASE(postlist6
, backend
) {
1468 Xapian::Database
db(get_database("apitest_simpledata"));
1469 Xapian::PostingIterator i
= db
.postlist_begin("this");
1470 TEST(i
!= db
.postlist_end("this"));
1471 while (i
!= db
.postlist_end("this")) {
1472 TEST_EQUAL(i
.get_doclength(), db
.get_doclength(*i
));
1473 TEST_EQUAL(i
.get_unique_terms(), db
.get_unique_terms(*i
));
1474 TEST_REL(i
.get_wdf(),<=,i
.get_doclength());
1475 TEST_REL(1,<=,i
.get_unique_terms());
1476 // The next two aren't necessarily true if there are terms with wdf=0
1477 // in the document, but that isn't the case here.
1478 TEST_REL(i
.get_unique_terms(),<=,i
.get_doclength());
1479 TEST_REL(i
.get_wdf() + i
.get_unique_terms() - 1,<=,i
.get_doclength());
1485 // tests collection frequency
1486 DEFINE_TESTCASE(collfreq1
, backend
) {
1487 Xapian::Database
db(get_database("apitest_simpledata"));
1489 TEST_EQUAL(db
.get_collection_freq("this"), 11);
1490 TEST_EQUAL(db
.get_collection_freq("first"), 1);
1491 TEST_EQUAL(db
.get_collection_freq("last"), 0);
1492 TEST_EQUAL(db
.get_collection_freq("word"), 9);
1494 Xapian::Database
db1(get_database("apitest_simpledata", "apitest_simpledata2"));
1495 Xapian::Database
db2(get_database("apitest_simpledata"));
1496 db2
.add_database(get_database("apitest_simpledata2"));
1498 TEST_EQUAL(db1
.get_collection_freq("this"), 15);
1499 TEST_EQUAL(db1
.get_collection_freq("first"), 1);
1500 TEST_EQUAL(db1
.get_collection_freq("last"), 0);
1501 TEST_EQUAL(db1
.get_collection_freq("word"), 11);
1502 TEST_EQUAL(db2
.get_collection_freq("this"), 15);
1503 TEST_EQUAL(db2
.get_collection_freq("first"), 1);
1504 TEST_EQUAL(db2
.get_collection_freq("last"), 0);
1505 TEST_EQUAL(db2
.get_collection_freq("word"), 11);
1510 // Regression test for split msets being incorrect when sorting
1511 DEFINE_TESTCASE(sortvalue1
, backend
) {
1512 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
1513 enquire
.set_query(Xapian::Query("this"));
1515 for (int pass
= 1; pass
<= 2; ++pass
) {
1516 for (Xapian::valueno value_no
= 1; value_no
< 7; ++value_no
) {
1517 tout
<< "Sorting on value " << value_no
<< endl
;
1518 enquire
.set_sort_by_value(value_no
, true);
1519 Xapian::MSet allbset
= enquire
.get_mset(0, 100);
1520 Xapian::MSet partbset1
= enquire
.get_mset(0, 3);
1521 Xapian::MSet partbset2
= enquire
.get_mset(3, 97);
1522 TEST_EQUAL(allbset
.size(), partbset1
.size() + partbset2
.size());
1526 Xapian::MSetIterator i
, j
;
1527 j
= allbset
.begin();
1528 for (i
= partbset1
.begin(); i
!= partbset1
.end(); ++i
) {
1529 tout
<< "Entry " << n
<< ": " << *i
<< " | " << *j
<< endl
;
1530 TEST(j
!= allbset
.end());
1531 if (*i
!= *j
) ok
= false;
1536 for (i
= partbset2
.begin(); i
!= partbset2
.end(); ++i
) {
1537 tout
<< "Entry " << n
<< ": " << *i
<< " | " << *j
<< endl
;
1538 TEST(j
!= allbset
.end());
1539 if (*i
!= *j
) ok
= false;
1543 TEST(j
== allbset
.end());
1545 FAIL_TEST("Split msets aren't consistent with unsplit");
1547 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1553 // consistency check match - vary mset size and check results agree.
1554 // consistency1 will run on the remote backend, but it's particularly slow
1555 // with that, and testing it there doesn't actually improve the test
1557 DEFINE_TESTCASE(consistency1
, backend
&& !remote
) {
1558 Xapian::Database
db(get_database("etext"));
1559 Xapian::Enquire
enquire(db
);
1560 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
, Xapian::Query("the"), Xapian::Query("sky")));
1561 Xapian::doccount lots
= 214;
1562 Xapian::MSet bigmset
= enquire
.get_mset(0, lots
);
1563 TEST_EQUAL(bigmset
.size(), lots
);
1565 for (Xapian::doccount start
= 0; start
< lots
; ++start
) {
1566 for (Xapian::doccount size
= 0; size
< lots
- start
; ++size
) {
1567 Xapian::MSet mset
= enquire
.get_mset(start
, size
);
1569 TEST_EQUAL(start
+ mset
.size(),
1570 min(start
+ size
, bigmset
.size()));
1572 // tout << start << mset.size() << bigmset.size() << endl;
1573 TEST(start
>= bigmset
.size());
1575 for (Xapian::doccount i
= 0; i
< mset
.size(); ++i
) {
1576 TEST_EQUAL(*mset
[i
], *bigmset
[start
+ i
]);
1577 TEST_EQUAL_DOUBLE(mset
[i
].get_weight(),
1578 bigmset
[start
+ i
].get_weight());
1582 } catch (const Xapian::NetworkTimeoutError
&) {
1583 // consistency1 is a long test - may timeout with the remote backend...
1584 SKIP_TEST("Test taking too long");
1589 // tests that specifying a nonexistent input file throws an exception.
1590 DEFINE_TESTCASE(chertdatabaseopeningerror1
, chert
) {
1591 #ifdef XAPIAN_HAS_CHERT_BACKEND
1592 mkdir(".chert", 0755);
1594 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1595 Xapian::Database(".chert/nosuchdirectory",
1596 Xapian::DB_BACKEND_CHERT
));
1597 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1598 Xapian::WritableDatabase(".chert/nosuchdirectory",
1599 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1601 mkdir(".chert/emptydirectory", 0700);
1602 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1603 Xapian::Database(".chert/emptydirectory",
1604 Xapian::DB_BACKEND_CHERT
));
1606 touch(".chert/somefile");
1607 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1608 Xapian::Database(".chert/somefile",
1609 Xapian::DB_BACKEND_CHERT
));
1610 TEST_EXCEPTION(Xapian::DatabaseOpeningError
,
1611 Xapian::WritableDatabase(".chert/somefile",
1612 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1613 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1614 Xapian::WritableDatabase(".chert/somefile",
1615 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
));
1616 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1617 Xapian::WritableDatabase(".chert/somefile",
1618 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
));
1619 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1620 Xapian::WritableDatabase(".chert/somefile",
1621 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
));
1627 /// Test opening of a chert database
1628 DEFINE_TESTCASE(chertdatabaseopen1
, chert
) {
1629 #ifdef XAPIAN_HAS_CHERT_BACKEND
1630 const string dbdir
= ".chert/test_chertdatabaseopen1";
1631 mkdir(".chert", 0755);
1635 Xapian::WritableDatabase
wdb(dbdir
,
1636 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
);
1637 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1638 Xapian::WritableDatabase(dbdir
,
1639 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
));
1640 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1645 Xapian::WritableDatabase
wdb(dbdir
,
1646 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
);
1647 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1648 Xapian::WritableDatabase(dbdir
,
1649 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
));
1650 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1655 Xapian::WritableDatabase
wdb(dbdir
,
1656 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
);
1657 TEST_EXCEPTION(Xapian::DatabaseLockError
,
1658 Xapian::WritableDatabase(dbdir
,
1659 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
));
1660 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1664 TEST_EXCEPTION(Xapian::DatabaseCreateError
,
1665 Xapian::WritableDatabase(dbdir
,
1666 Xapian::DB_CREATE
|Xapian::DB_BACKEND_CHERT
));
1667 Xapian::WritableDatabase
wdb(dbdir
,
1668 Xapian::DB_CREATE_OR_OVERWRITE
|Xapian::DB_BACKEND_CHERT
);
1669 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1673 Xapian::WritableDatabase
wdb(dbdir
,
1674 Xapian::DB_CREATE_OR_OPEN
|Xapian::DB_BACKEND_CHERT
);
1675 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1679 Xapian::WritableDatabase
wdb(dbdir
,
1680 Xapian::DB_OPEN
|Xapian::DB_BACKEND_CHERT
);
1681 Xapian::Database(dbdir
, Xapian::DB_BACKEND_CHERT
);
1688 // feature test for Enquire:
1689 // set_sort_by_value
1690 // set_sort_by_value_then_relevance
1691 // set_sort_by_relevance_then_value
1692 // Prior to 1.2.17 and 1.3.2, order8 and order9 were swapped, and
1693 // set_sort_by_relevance_then_value was buggy, so this testcase now serves as
1694 // a regression test for that bug.
1695 DEFINE_TESTCASE(sortrel1
, backend
) {
1696 Xapian::Enquire
enquire(get_database("apitest_sortrel"));
1697 enquire
.set_sort_by_value(1, true);
1698 enquire
.set_query(Xapian::Query("woman"));
1700 static const Xapian::docid order1
[] = { 1,2,3,4,5,6,7,8,9 };
1701 static const Xapian::docid order2
[] = { 2,1,3,6,5,4,7,9,8 };
1702 static const Xapian::docid order3
[] = { 3,2,1,6,5,4,9,8,7 };
1703 static const Xapian::docid order4
[] = { 7,8,9,4,5,6,1,2,3 };
1704 static const Xapian::docid order5
[] = { 9,8,7,6,5,4,3,2,1 };
1705 static const Xapian::docid order6
[] = { 7,9,8,6,5,4,2,1,3 };
1706 static const Xapian::docid order7
[] = { 7,9,8,6,5,4,2,1,3 };
1707 static const Xapian::docid order8
[] = { 2,6,7,1,5,9,3,4,8 };
1708 static const Xapian::docid order9
[] = { 7,6,2,9,5,1,8,4,3 };
1713 mset
= enquire
.get_mset(0, 10);
1714 TEST_EQUAL(mset
.size(), sizeof(order1
) / sizeof(Xapian::docid
));
1715 for (i
= 0; i
< sizeof(order1
) / sizeof(Xapian::docid
); ++i
) {
1716 TEST_EQUAL(*mset
[i
], order1
[i
]);
1719 enquire
.set_sort_by_value_then_relevance(1, true);
1721 mset
= enquire
.get_mset(0, 10);
1722 TEST_EQUAL(mset
.size(), sizeof(order2
) / sizeof(Xapian::docid
));
1723 for (i
= 0; i
< sizeof(order2
) / sizeof(Xapian::docid
); ++i
) {
1724 TEST_EQUAL(*mset
[i
], order2
[i
]);
1727 enquire
.set_sort_by_value(1, true);
1729 mset
= enquire
.get_mset(0, 10);
1730 TEST_EQUAL(mset
.size(), sizeof(order1
) / sizeof(Xapian::docid
));
1731 for (i
= 0; i
< sizeof(order1
) / sizeof(Xapian::docid
); ++i
) {
1732 TEST_EQUAL(*mset
[i
], order1
[i
]);
1735 enquire
.set_sort_by_value_then_relevance(1, true);
1736 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1738 mset
= enquire
.get_mset(0, 10);
1739 TEST_EQUAL(mset
.size(), sizeof(order2
) / sizeof(Xapian::docid
));
1740 for (i
= 0; i
< sizeof(order2
) / sizeof(Xapian::docid
); ++i
) {
1741 TEST_EQUAL(*mset
[i
], order2
[i
]);
1744 enquire
.set_sort_by_value(1, true);
1745 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1747 mset
= enquire
.get_mset(0, 10);
1748 TEST_EQUAL(mset
.size(), sizeof(order3
) / sizeof(Xapian::docid
));
1749 for (i
= 0; i
< sizeof(order3
) / sizeof(Xapian::docid
); ++i
) {
1750 TEST_EQUAL(*mset
[i
], order3
[i
]);
1753 enquire
.set_sort_by_value(1, false);
1754 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1755 mset
= enquire
.get_mset(0, 10);
1756 TEST_EQUAL(mset
.size(), sizeof(order4
) / sizeof(Xapian::docid
));
1757 for (i
= 0; i
< sizeof(order4
) / sizeof(Xapian::docid
); ++i
) {
1758 TEST_EQUAL(*mset
[i
], order4
[i
]);
1761 enquire
.set_sort_by_value(1, false);
1762 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1763 mset
= enquire
.get_mset(0, 10);
1764 TEST_EQUAL(mset
.size(), sizeof(order5
) / sizeof(Xapian::docid
));
1765 for (i
= 0; i
< sizeof(order5
) / sizeof(Xapian::docid
); ++i
) {
1766 TEST_EQUAL(*mset
[i
], order5
[i
]);
1769 enquire
.set_sort_by_value_then_relevance(1, false);
1770 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1771 mset
= enquire
.get_mset(0, 10);
1772 TEST_EQUAL(mset
.size(), sizeof(order6
) / sizeof(Xapian::docid
));
1773 for (i
= 0; i
< sizeof(order6
) / sizeof(Xapian::docid
); ++i
) {
1774 TEST_EQUAL(*mset
[i
], order6
[i
]);
1777 enquire
.set_sort_by_value_then_relevance(1, false);
1778 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1779 mset
= enquire
.get_mset(0, 10);
1780 TEST_EQUAL(mset
.size(), sizeof(order7
) / sizeof(Xapian::docid
));
1781 for (i
= 0; i
< sizeof(order7
) / sizeof(Xapian::docid
); ++i
) {
1782 TEST_EQUAL(*mset
[i
], order7
[i
]);
1785 enquire
.set_sort_by_relevance_then_value(1, true);
1786 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1787 mset
= enquire
.get_mset(0, 10);
1788 TEST_EQUAL(mset
.size(), sizeof(order8
) / sizeof(Xapian::docid
));
1789 for (i
= 0; i
< sizeof(order8
) / sizeof(Xapian::docid
); ++i
) {
1790 TEST_EQUAL(*mset
[i
], order8
[i
]);
1793 enquire
.set_sort_by_relevance_then_value(1, true);
1794 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1795 mset
= enquire
.get_mset(0, 10);
1796 TEST_EQUAL(mset
.size(), sizeof(order8
) / sizeof(Xapian::docid
));
1797 for (i
= 0; i
< sizeof(order8
) / sizeof(Xapian::docid
); ++i
) {
1798 TEST_EQUAL(*mset
[i
], order8
[i
]);
1801 enquire
.set_sort_by_relevance_then_value(1, false);
1802 enquire
.set_docid_order(Xapian::Enquire::ASCENDING
);
1803 mset
= enquire
.get_mset(0, 10);
1804 TEST_EQUAL(mset
.size(), sizeof(order9
) / sizeof(Xapian::docid
));
1805 for (i
= 0; i
< sizeof(order9
) / sizeof(Xapian::docid
); ++i
) {
1806 TEST_EQUAL(*mset
[i
], order9
[i
]);
1809 enquire
.set_sort_by_relevance_then_value(1, false);
1810 enquire
.set_docid_order(Xapian::Enquire::DESCENDING
);
1811 mset
= enquire
.get_mset(0, 10);
1812 TEST_EQUAL(mset
.size(), sizeof(order9
) / sizeof(Xapian::docid
));
1813 for (i
= 0; i
< sizeof(order9
) / sizeof(Xapian::docid
); ++i
) {
1814 TEST_EQUAL(*mset
[i
], order9
[i
]);
1820 // Test network stats and local stats give the same results.
1821 DEFINE_TESTCASE(netstats1
, remote
) {
1822 BackendManagerLocal local_manager
;
1823 local_manager
.set_datadir(test_driver::get_srcdir() + "/testdata/");
1825 static const char * const words
[] = { "paragraph", "word" };
1826 Xapian::Query
query(Xapian::Query::OP_OR
, words
, words
+ 2);
1827 const size_t MSET_SIZE
= 10;
1830 rset
.add_document(4);
1831 rset
.add_document(9);
1833 Xapian::MSet mset_alllocal
;
1835 Xapian::Database db
;
1836 db
.add_database(local_manager
.get_database("apitest_simpledata"));
1837 db
.add_database(local_manager
.get_database("apitest_simpledata2"));
1839 Xapian::Enquire
enq(db
);
1840 enq
.set_query(query
);
1841 mset_alllocal
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1845 Xapian::Database db
;
1846 db
.add_database(local_manager
.get_database("apitest_simpledata"));
1847 db
.add_database(get_database("apitest_simpledata2"));
1849 Xapian::Enquire
enq(db
);
1850 enq
.set_query(query
);
1851 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1852 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1853 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1854 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1855 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1856 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1857 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1861 Xapian::Database db
;
1862 db
.add_database(get_database("apitest_simpledata"));
1863 db
.add_database(local_manager
.get_database("apitest_simpledata2"));
1865 Xapian::Enquire
enq(db
);
1866 enq
.set_query(query
);
1867 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1868 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1869 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1870 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1871 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1872 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1873 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1877 Xapian::Database db
;
1878 db
.add_database(get_database("apitest_simpledata"));
1879 db
.add_database(get_database("apitest_simpledata2"));
1881 Xapian::Enquire
enq(db
);
1882 enq
.set_query(query
);
1883 Xapian::MSet mset
= enq
.get_mset(0, MSET_SIZE
, &rset
);
1884 TEST_EQUAL(mset
.get_matches_lower_bound(), mset_alllocal
.get_matches_lower_bound());
1885 TEST_EQUAL(mset
.get_matches_upper_bound(), mset_alllocal
.get_matches_upper_bound());
1886 TEST_EQUAL(mset
.get_matches_estimated(), mset_alllocal
.get_matches_estimated());
1887 TEST_EQUAL(mset
.get_max_attained(), mset_alllocal
.get_max_attained());
1888 TEST_EQUAL(mset
.size(), mset_alllocal
.size());
1889 TEST(mset_range_is_same(mset
, 0, mset_alllocal
, 0, mset
.size()));
1895 // Coordinate matching - scores 1 for each matching term
1896 class MyWeight
: public Xapian::Weight
{
1897 double scale_factor
;
1900 MyWeight
* clone() const {
1901 return new MyWeight
;
1903 void init(double factor
) {
1904 scale_factor
= factor
;
1908 std::string
name() const { return "MyWeight"; }
1909 string
serialise() const { return string(); }
1910 MyWeight
* unserialise(const string
&) const { return new MyWeight
; }
1911 double get_sumpart(Xapian::termcount
, Xapian::termcount
, Xapian::termcount
) const {
1912 return scale_factor
;
1914 double get_maxpart() const { return scale_factor
; }
1916 double get_sumextra(Xapian::termcount
, Xapian::termcount
) const { return 0; }
1917 double get_maxextra() const { return 0; }
1920 // tests user weighting scheme.
1921 // Would work with remote if we registered the weighting scheme.
1922 // FIXME: do this so we also test that functionality...
1923 DEFINE_TESTCASE(userweight1
, backend
&& !remote
) {
1924 Xapian::Enquire
enquire(get_database("apitest_simpledata"));
1925 enquire
.set_weighting_scheme(MyWeight());
1926 static const char * const query
[] = {
1927 "this", "line", "paragraph", "rubbish"
1929 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
, query
,
1930 query
+ sizeof(query
) / sizeof(query
[0])));
1931 Xapian::MSet mymset1
= enquire
.get_mset(0, 100);
1932 // MyWeight scores 1 for each matching term, so the weight should equal
1933 // the number of matching terms.
1934 for (Xapian::MSetIterator i
= mymset1
.begin(); i
!= mymset1
.end(); ++i
) {
1935 Xapian::termcount matching_terms
= 0;
1936 Xapian::TermIterator t
= enquire
.get_matching_terms_begin(i
);
1937 while (t
!= enquire
.get_matching_terms_end(i
)) {
1941 TEST_EQUAL(i
.get_weight(), matching_terms
);
1947 // tests MatchAll queries
1948 // This is a regression test, which failed with assertion failures in
1949 // revision 9094. Also check that the results aren't ranked by relevance
1950 // (regression test for bug fixed in 1.0.9).
1951 DEFINE_TESTCASE(matchall1
, backend
) {
1952 Xapian::Database
db(get_database("apitest_simpledata"));
1953 Xapian::Enquire
enquire(db
);
1954 enquire
.set_query(Xapian::Query::MatchAll
);
1955 Xapian::MSet mset
= enquire
.get_mset(0, 10);
1956 TEST_EQUAL(mset
.get_matches_lower_bound(), db
.get_doccount());
1957 TEST_EQUAL(mset
.get_uncollapsed_matches_lower_bound(), db
.get_doccount());
1959 enquire
.set_query(Xapian::Query(Xapian::Query::OP_OR
,
1960 Xapian::Query("nosuchterm"),
1961 Xapian::Query::MatchAll
));
1962 mset
= enquire
.get_mset(0, 10);
1963 TEST_EQUAL(mset
.get_matches_lower_bound(), db
.get_doccount());
1964 TEST_EQUAL(mset
.get_uncollapsed_matches_lower_bound(), db
.get_doccount());
1966 // Check that the results aren't ranked by relevance (fixed in 1.0.9).
1967 TEST(mset
.size() > 1);
1968 TEST_EQUAL(mset
[mset
.size() - 1].get_weight(), 0);
1969 TEST_EQUAL(*mset
[0], 1);
1970 TEST_EQUAL(*mset
[mset
.size() - 1], mset
.size());
1975 // Test using a ValueSetMatchDecider
1976 DEFINE_TESTCASE(valuesetmatchdecider2
, backend
&& !remote
) {
1977 Xapian::Database
db(get_database("apitest_phrase"));
1978 Xapian::Enquire
enq(db
);
1979 enq
.set_query(Xapian::Query("leav"));
1981 Xapian::ValueSetMatchDecider
vsmd1(1, true);
1982 vsmd1
.add_value("n");
1983 Xapian::ValueSetMatchDecider
vsmd2(1, false);
1984 vsmd2
.add_value("n");
1986 Xapian::MSet mymset
= enq
.get_mset(0, 20);
1987 mset_expect_order(mymset
, 8, 6, 4, 5, 7, 10, 12, 11, 13, 9, 14);
1988 mymset
= enq
.get_mset(0, 20, 0, NULL
, &vsmd1
);
1989 mset_expect_order(mymset
, 6, 12);
1990 mymset
= enq
.get_mset(0, 20, 0, NULL
, &vsmd2
);
1991 mset_expect_order(mymset
, 8, 4, 5, 7, 10, 11, 13, 9, 14);