tests/api_db.cc

Go to the documentation of this file.
00001 /* api_db.cc: tests which need a backend
00002  *
00003  * Copyright 1999,2000,2001 BrightStation PLC
00004  * Copyright 2002 Ananova Ltd
00005  * Copyright 2002,2003,2004,2005,2006,2007 Olly Betts
00006  * Copyright 2006,2007 Lemur Consulting Ltd
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of the
00011  * License, or (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00021  * USA
00022  */
00023 
00024 #include <config.h>
00025 
00026 #include "api_db.h"
00027 
00028 #include <algorithm>
00029 #include <fstream>
00030 #include <map>
00031 #include <string>
00032 #include <vector>
00033 
00034 // We have to use the deprecated Quartz::open() method.
00035 #define XAPIAN_DEPRECATED(D) D
00036 #include <xapian.h>
00037 
00038 #include "backendmanager.h"
00039 #include "backendmanager_local.h"
00040 #include "testsuite.h"
00041 #include "testutils.h"
00042 #include "unixcmds.h"
00043 #include "utils.h"
00044 
00045 #include "apitest.h"
00046 
00047 #include <list>
00048 
00049 using namespace std;
00050 
00051 static Xapian::Query
00052 query(const string &t)
00053 {
00054     return Xapian::Query(Xapian::Stem("english")(t));
00055 }
00056 
00057 // #######################################################################
00058 // # Tests start here
00059 
00060 // tests Xapian::Database::get_termfreq() and Xapian::Database::term_exists()
00061 DEFINE_TESTCASE(termstats, backend) {
00062     Xapian::Database db(get_database("apitest_simpledata"));
00063 
00064     TEST(!db.term_exists("corn"));
00065     TEST_EQUAL(db.get_termfreq("corn"), 0);
00066     TEST(db.term_exists("banana"));
00067     TEST_EQUAL(db.get_termfreq("banana"), 1);
00068     TEST(db.term_exists("paragraph"));
00069     TEST_EQUAL(db.get_termfreq("paragraph"), 5);
00070 
00071     return true;
00072 }
00073 
00074 // check that stubdbs work
00075 DEFINE_TESTCASE(stubdb1, flint) {
00076     {
00077         // Create the database needed; this is why we require the flint backend.
00078         (void) get_database("apitest_simpledata");
00079     }
00080     ofstream out("stubdb1");
00081     TEST(out.is_open());
00082     // FIXME: not very reliable...
00083     out << "remote :" << BackendManager::get_xapian_progsrv_command()
00084         << " .flint/db=apitest_simpledata\n";
00085     out.close();
00086 
00087     {
00088         Xapian::Database db = Xapian::Auto::open_stub("stubdb1");
00089         Xapian::Enquire enquire(db);
00090         enquire.set_query(Xapian::Query("word"));
00091         enquire.get_mset(0, 10);
00092     }
00093     {
00094         Xapian::Database db("stubdb1");
00095         Xapian::Enquire enquire(db);
00096         enquire.set_query(Xapian::Query("word"));
00097         enquire.get_mset(0, 10);
00098     }
00099 
00100     unlink("stubdb1");
00101 
00102     return true;
00103 }
00104 
00105 #if 0 // the "force error" mechanism is no longer in place...
00106 class MyErrorHandler : public Xapian::ErrorHandler {
00107     public:
00108         int count;
00109 
00110         bool handle_error(Xapian::Error & error) {
00111             ++count;
00112             tout << "Error handling caught: " << error.get_description()
00113                  << ", count is now " << count << "\n";
00114             return true;
00115         }
00116 
00117         MyErrorHandler() : count (0) {}
00118 };
00119 
00120 // tests error handler in multimatch().
00121 //DEFINE_TESTCASE(multierrhandler1, backend) {
00122     MyErrorHandler myhandler;
00123 
00124     Xapian::Database mydb2(get_database("apitest_simpledata"));
00125     Xapian::Database mydb3(get_database("apitest_simpledata2"));
00126     int errcount = 1;
00127     for (int testcount = 0; testcount < 14; testcount ++) {
00128         tout << "testcount=" << testcount << "\n";
00129         Xapian::Database mydb4(get_database("-e", "apitest_termorder"));
00130         Xapian::Database mydb5(get_network_database("apitest_termorder", 1));
00131         Xapian::Database mydb6(get_database("-e2", "apitest_termorder"));
00132         Xapian::Database mydb7(get_database("-e3", "apitest_simpledata"));
00133 
00134         Xapian::Database dbs;
00135         switch (testcount) {
00136             case 0:
00137                 dbs.add_database(mydb2);
00138                 dbs.add_database(mydb3);
00139                 dbs.add_database(mydb4);
00140                 break;
00141             case 1:
00142                 dbs.add_database(mydb4);
00143                 dbs.add_database(mydb2);
00144                 dbs.add_database(mydb3);
00145                 break;
00146             case 2:
00147                 dbs.add_database(mydb3);
00148                 dbs.add_database(mydb4);
00149                 dbs.add_database(mydb2);
00150                 break;
00151             case 3:
00152                 dbs.add_database(mydb2);
00153                 dbs.add_database(mydb3);
00154                 dbs.add_database(mydb5);
00155                 sleep(1);
00156                 break;
00157             case 4:
00158                 dbs.add_database(mydb5);
00159                 dbs.add_database(mydb2);
00160                 dbs.add_database(mydb3);
00161                 sleep(1);
00162                 break;
00163             case 5:
00164                 dbs.add_database(mydb3);
00165                 dbs.add_database(mydb5);
00166                 dbs.add_database(mydb2);
00167                 sleep(1);
00168                 break;
00169             case 6:
00170                 dbs.add_database(mydb2);
00171                 dbs.add_database(mydb3);
00172                 dbs.add_database(mydb6);
00173                 break;
00174             case 7:
00175                 dbs.add_database(mydb6);
00176                 dbs.add_database(mydb2);
00177                 dbs.add_database(mydb3);
00178                 break;
00179             case 8:
00180                 dbs.add_database(mydb3);
00181                 dbs.add_database(mydb6);
00182                 dbs.add_database(mydb2);
00183                 break;
00184             case 9:
00185                 dbs.add_database(mydb2);
00186                 dbs.add_database(mydb3);
00187                 dbs.add_database(mydb7);
00188                 break;
00189             case 10:
00190                 dbs.add_database(mydb7);
00191                 dbs.add_database(mydb2);
00192                 dbs.add_database(mydb3);
00193                 break;
00194             case 11:
00195                 dbs.add_database(mydb3);
00196                 dbs.add_database(mydb7);
00197                 dbs.add_database(mydb2);
00198                 break;
00199             case 12:
00200                 dbs.add_database(mydb2);
00201                 dbs.add_database(mydb6);
00202                 dbs.add_database(mydb7);
00203                 break;
00204             case 13:
00205                 dbs.add_database(mydb2);
00206                 dbs.add_database(mydb7);
00207                 dbs.add_database(mydb6);
00208                 break;
00209         }
00210         tout << "db=" << dbs << "\n";
00211         Xapian::Enquire enquire(dbs, &myhandler);
00212 
00213         // make a query
00214         Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
00215         enquire.set_weighting_scheme(Xapian::BoolWeight());
00216         enquire.set_query(myquery);
00217 
00218         tout << "query=" << myquery << "\n";
00219         // retrieve the top ten results
00220         Xapian::MSet mymset = enquire.get_mset(0, 10);
00221 
00222         switch (testcount) {
00223             case 0: case 3: case 6: case 9:
00224                 mset_expect_order(mymset, 2, 4, 10);
00225                 break;
00226             case 1: case 4: case 7: case 10:
00227                 mset_expect_order(mymset, 3, 5, 11);
00228                 break;
00229             case 2: case 5: case 8: case 11:
00230                 mset_expect_order(mymset, 1, 6, 12);
00231                 break;
00232             case 12:
00233             case 13:
00234                 mset_expect_order(mymset, 4, 10);
00235                 errcount += 1;
00236                 break;
00237         }
00238         TEST_EQUAL(myhandler.count, errcount);
00239         errcount += 1;
00240     }
00241 
00242     return true;
00243 }
00244 #endif
00245 
00246 class myMatchDecider : public Xapian::MatchDecider {
00247     public:
00248         bool operator()(const Xapian::Document &doc) const {
00249             // Note that this is not recommended usage of get_data()
00250             return doc.get_data().find("This is") != string::npos;
00251         }
00252 };
00253 
00254 // Test Xapian::MatchDecider functor.
00255 DEFINE_TESTCASE(matchfunctor1, backend && !remote) {
00256     Xapian::Database db(get_database("apitest_simpledata"));
00257     Xapian::Enquire enquire(db);
00258     enquire.set_query(Xapian::Query("this"));
00259 
00260     myMatchDecider myfunctor;
00261 
00262     Xapian::MSet mymset = enquire.get_mset(0, 100, 0, &myfunctor);
00263 
00264     vector<bool> docid_checked(db.get_lastdocid());
00265 
00266     // Check that we get the expected number of matches, and that they
00267     // satisfy the condition.
00268     Xapian::MSetIterator i = mymset.begin();
00269     TEST(i != mymset.end());
00270     TEST_EQUAL(mymset.size(), 3);
00271     TEST_EQUAL(mymset.get_matches_lower_bound(), 3);
00272     TEST_EQUAL(mymset.get_matches_upper_bound(), 3);
00273     TEST_EQUAL(mymset.get_matches_estimated(), 3);
00274     for ( ; i != mymset.end(); ++i) {
00275         const Xapian::Document doc(i.get_document());
00276         TEST(myfunctor(doc));
00277         docid_checked[*i] = true;
00278     }
00279 
00280     // Check that there are some documents which aren't accepted by the match
00281     // decider.
00282     mymset = enquire.get_mset(0, 100);
00283     TEST(mymset.size() > 3);
00284 
00285     // Check that the bounds are appropriate even if we don't ask for any
00286     // actual matches.
00287     mymset = enquire.get_mset(0, 0, 0, &myfunctor);
00288     TEST_EQUAL(mymset.size(), 0);
00289     TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
00290     TEST_EQUAL(mymset.get_matches_upper_bound(), 6);
00291     TEST(mymset.get_matches_estimated() > 0);
00292     TEST(mymset.get_matches_estimated() <= 6);
00293 
00294     // Check that the bounds are appropriate if we ask for only one hit.
00295     // (Regression test - until SVN 10256, we didn't reduce the lower_bound
00296     // appropriately, and returned 6 here.)
00297     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
00298     TEST_EQUAL(mymset.size(), 1);
00299     TEST(mymset.get_matches_lower_bound() >= 1);
00300     TEST(mymset.get_matches_lower_bound() <= 3);
00301     TEST(mymset.get_matches_upper_bound() >= 3);
00302     TEST(mymset.get_matches_upper_bound() <= 6);
00303     TEST(mymset.get_matches_estimated() > 0);
00304     TEST(mymset.get_matches_estimated() <= 6);
00305 
00306     // Check that the other documents don't satisfy the condition.
00307     for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
00308         if (!docid_checked[did]) {
00309             TEST(!myfunctor(db.get_document(did)));
00310         }
00311     }
00312 
00313     // Check that the bounds are appropriate if a collapse key is used.
00314     // Use a value which is never set so we don't actually discard anything.
00315     enquire.set_collapse_key(99);
00316     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
00317     TEST_EQUAL(mymset.size(), 1);
00318     TEST(mymset.get_matches_lower_bound() >= 1);
00319     TEST(mymset.get_matches_lower_bound() <= 3);
00320     TEST(mymset.get_matches_upper_bound() >= 3);
00321     TEST(mymset.get_matches_upper_bound() <= 6);
00322     TEST(mymset.get_matches_estimated() > 0);
00323     TEST(mymset.get_matches_estimated() <= 6);
00324 
00325     // Check that the bounds are appropriate if a percentage cutoff is in
00326     // use.  Set a 1% threshold so we don't actually discard anything.
00327     enquire.set_collapse_key(Xapian::BAD_VALUENO);
00328     enquire.set_cutoff(1);
00329     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
00330     TEST_EQUAL(mymset.size(), 1);
00331     TEST(mymset.get_matches_lower_bound() >= 1);
00332     TEST(mymset.get_matches_lower_bound() <= 3);
00333     TEST(mymset.get_matches_upper_bound() >= 3);
00334     TEST(mymset.get_matches_upper_bound() <= 6);
00335     TEST(mymset.get_matches_estimated() > 0);
00336     TEST(mymset.get_matches_estimated() <= 6);
00337 
00338     // And now with both a collapse key and percentage cutoff.
00339     enquire.set_collapse_key(99);
00340     mymset = enquire.get_mset(0, 1, 0, &myfunctor);
00341     TEST_EQUAL(mymset.size(), 1);
00342     TEST(mymset.get_matches_lower_bound() >= 1);
00343     TEST(mymset.get_matches_lower_bound() <= 3);
00344     TEST(mymset.get_matches_upper_bound() >= 3);
00345     TEST(mymset.get_matches_upper_bound() <= 6);
00346     TEST(mymset.get_matches_estimated() > 0);
00347     TEST(mymset.get_matches_estimated() <= 6);
00348 
00349     return true;
00350 }
00351 
00352 // Test Xapian::MatchDecider functor used as a match spy.
00353 DEFINE_TESTCASE(matchfunctor2, backend && !remote) {
00354     Xapian::Database db(get_database("apitest_simpledata"));
00355     Xapian::Enquire enquire(db);
00356     enquire.set_query(Xapian::Query("this"));
00357 
00358     myMatchDecider myfunctor;
00359 
00360     Xapian::MSet mymset = enquire.get_mset(0, 100, 0, NULL, &myfunctor);
00361 
00362     vector<bool> docid_checked(db.get_lastdocid());
00363 
00364     // Check that we get the expected number of matches, and that they
00365     // satisfy the condition.
00366     Xapian::MSetIterator i = mymset.begin();
00367     TEST(i != mymset.end());
00368     TEST_EQUAL(mymset.size(), 3);
00369     for ( ; i != mymset.end(); ++i) {
00370         const Xapian::Document doc(i.get_document());
00371         TEST(myfunctor(doc));
00372         docid_checked[*i] = true;
00373     }
00374 
00375     // Check that the other documents don't satisfy the condition.
00376     for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
00377         if (!docid_checked[did]) {
00378             TEST(!myfunctor(db.get_document(did)));
00379         }
00380     }
00381 
00382     return true;
00383 }
00384 
00385 class myMatchDecider2 : public Xapian::MatchDecider {
00386     public:
00387         bool operator()(const Xapian::Document &doc) const {
00388             // Note that this is not recommended usage of get_data()
00389             return doc.get_data().find("We produce") == string::npos;
00390         }
00391 };
00392 
00393 
00394 // Regression test for lower bound using functor, sorting and collapsing.
00395 DEFINE_TESTCASE(matchfunctor3, backend) {
00396     Xapian::Database db(get_database("etext"));
00397     Xapian::Enquire enquire(db);
00398     enquire.set_query(Xapian::Query(""));
00399     enquire.set_collapse_key(12);
00400     enquire.set_sort_by_value(11);
00401 
00402     myMatchDecider2 myfunctor;
00403 
00404     Xapian::MSet mymset1 = enquire.get_mset(0, 2, 0, NULL, &myfunctor);
00405     Xapian::MSet mymset2 = enquire.get_mset(0, 1000, 0, NULL, &myfunctor);
00406 
00407     // mymset2 should contain all the hits, so the statistics should be exact.
00408     TEST_EQUAL(mymset2.get_matches_estimated(),
00409                mymset2.size());
00410     TEST_EQUAL(mymset2.get_matches_lower_bound(),
00411                mymset2.get_matches_estimated());
00412     TEST_EQUAL(mymset2.get_matches_estimated(),
00413                mymset2.get_matches_upper_bound());
00414 
00415     // Check that the lower bound in mymset1 is not greater than the known
00416     // number of hits.  This failed until revision 10811.
00417     TEST_LESSER_OR_EQUAL(mymset1.get_matches_lower_bound(),
00418                          mymset2.size());
00419 
00420     // Check that the bounds for mymset1 make sense
00421     TEST_LESSER_OR_EQUAL(mymset1.get_matches_lower_bound(), mymset1.get_matches_estimated());
00422     TEST_LESSER_OR_EQUAL(mymset1.size(), mymset1.get_matches_upper_bound());
00423     TEST_LESSER_OR_EQUAL(mymset1.get_matches_estimated(), mymset1.get_matches_upper_bound());
00424 
00425     return true;
00426 }
00427 
00428 // tests that mset iterators on msets compare correctly.
00429 DEFINE_TESTCASE(msetiterator1, backend) {
00430     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00431     enquire.set_query(Xapian::Query("this"));
00432     Xapian::MSet mymset = enquire.get_mset(0, 2);
00433 
00434     Xapian::MSetIterator j;
00435     j = mymset.begin();
00436     Xapian::MSetIterator k = mymset.end();
00437     Xapian::MSetIterator l(j);
00438     Xapian::MSetIterator m(k);
00439     Xapian::MSetIterator n = mymset.begin();
00440     Xapian::MSetIterator o = mymset.begin();
00441     TEST_NOT_EQUAL(j, k);
00442     TEST_NOT_EQUAL(l, m);
00443     TEST_EQUAL(k, m);
00444     TEST_EQUAL(j, l);
00445     TEST_EQUAL(j, j);
00446     TEST_EQUAL(k, k);
00447 
00448     k = j;
00449     TEST_EQUAL(j, k);
00450     TEST_EQUAL(j, o);
00451     k++;
00452     TEST_NOT_EQUAL(j, k);
00453     TEST_NOT_EQUAL(k, l);
00454     TEST_NOT_EQUAL(k, m);
00455     TEST_NOT_EQUAL(k, o);
00456     o++;
00457     TEST_EQUAL(k, o);
00458     k++;
00459     TEST_NOT_EQUAL(j, k);
00460     TEST_NOT_EQUAL(k, l);
00461     TEST_EQUAL(k, m);
00462     TEST_EQUAL(n, l);
00463 
00464     n = m;
00465     TEST_NOT_EQUAL(n, l);
00466     TEST_EQUAL(n, m);
00467     TEST_NOT_EQUAL(n, mymset.begin());
00468     TEST_EQUAL(n, mymset.end());
00469 
00470     return true;
00471 }
00472 
00473 // tests that mset iterators on empty msets compare equal.
00474 DEFINE_TESTCASE(msetiterator2, backend) {
00475     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00476     enquire.set_query(Xapian::Query("this"));
00477     Xapian::MSet mymset = enquire.get_mset(0, 0);
00478 
00479     Xapian::MSetIterator j = mymset.begin();
00480     Xapian::MSetIterator k = mymset.end();
00481     Xapian::MSetIterator l(j);
00482     Xapian::MSetIterator m(k);
00483     TEST_EQUAL(j, k);
00484     TEST_EQUAL(l, m);
00485     TEST_EQUAL(k, m);
00486     TEST_EQUAL(j, l);
00487     TEST_EQUAL(j, j);
00488     TEST_EQUAL(k, k);
00489 
00490     return true;
00491 }
00492 
00493 // tests that begin().get_document() works when first != 0
00494 DEFINE_TESTCASE(msetiterator3, backend) {
00495     Xapian::Database mydb(get_database("apitest_simpledata"));
00496     Xapian::Enquire enquire(mydb);
00497     enquire.set_query(Xapian::Query("this"));
00498 
00499     Xapian::MSet mymset = enquire.get_mset(2, 10);
00500 
00501     TEST(!mymset.empty());
00502     Xapian::Document doc(mymset.begin().get_document());
00503     TEST(!doc.get_data().empty());
00504 
00505     return true;
00506 }
00507 
00508 // tests that eset iterators on empty esets compare equal.
00509 DEFINE_TESTCASE(esetiterator1, backend) {
00510     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00511     enquire.set_query(Xapian::Query("this"));
00512 
00513     Xapian::MSet mymset = enquire.get_mset(0, 10);
00514     TEST(mymset.size() >= 2);
00515 
00516     Xapian::RSet myrset;
00517     Xapian::MSetIterator i = mymset.begin();
00518     myrset.add_document(*i);
00519     myrset.add_document(*(++i));
00520 
00521     Xapian::ESet myeset = enquire.get_eset(2, myrset);
00522     Xapian::ESetIterator j;
00523     j = myeset.begin();
00524     Xapian::ESetIterator k = myeset.end();
00525     Xapian::ESetIterator l(j);
00526     Xapian::ESetIterator m(k);
00527     Xapian::ESetIterator n = myeset.begin();
00528 
00529     TEST_NOT_EQUAL(j, k);
00530     TEST_NOT_EQUAL(l, m);
00531     TEST_EQUAL(k, m);
00532     TEST_EQUAL(j, l);
00533     TEST_EQUAL(j, j);
00534     TEST_EQUAL(k, k);
00535 
00536     k = j;
00537     TEST_EQUAL(j, k);
00538     k++;
00539     TEST_NOT_EQUAL(j, k);
00540     TEST_NOT_EQUAL(k, l);
00541     TEST_NOT_EQUAL(k, m);
00542     k++;
00543     TEST_NOT_EQUAL(j, k);
00544     TEST_NOT_EQUAL(k, l);
00545     TEST_EQUAL(k, m);
00546     TEST_EQUAL(n, l);
00547 
00548     n = m;
00549     TEST_NOT_EQUAL(n, l);
00550     TEST_EQUAL(n, m);
00551     TEST_NOT_EQUAL(n, myeset.begin());
00552     TEST_EQUAL(n, myeset.end());
00553 
00554     return true;
00555 }
00556 
00557 // tests that eset iterators on empty esets compare equal.
00558 DEFINE_TESTCASE(esetiterator2, backend) {
00559     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00560     enquire.set_query(Xapian::Query("this"));
00561 
00562     Xapian::MSet mymset = enquire.get_mset(0, 10);
00563     TEST(mymset.size() >= 2);
00564 
00565     Xapian::RSet myrset;
00566     Xapian::MSetIterator i = mymset.begin();
00567     myrset.add_document(*i);
00568     myrset.add_document(*(++i));
00569 
00570     Xapian::ESet myeset = enquire.get_eset(0, myrset);
00571     Xapian::ESetIterator j = myeset.begin();
00572     Xapian::ESetIterator k = myeset.end();
00573     Xapian::ESetIterator l(j);
00574     Xapian::ESetIterator m(k);
00575     TEST_EQUAL(j, k);
00576     TEST_EQUAL(l, m);
00577     TEST_EQUAL(k, m);
00578     TEST_EQUAL(j, l);
00579     TEST_EQUAL(j, j);
00580     TEST_EQUAL(k, k);
00581 
00582     return true;
00583 }
00584 
00585 // tests the collapse-on-key
00586 DEFINE_TESTCASE(collapsekey1, backend) {
00587     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00588     enquire.set_query(Xapian::Query("this"));
00589 
00590     Xapian::MSet mymset1 = enquire.get_mset(0, 100);
00591     Xapian::doccount mymsize1 = mymset1.size();
00592 
00593     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
00594         enquire.set_collapse_key(value_no);
00595         Xapian::MSet mymset = enquire.get_mset(0, 100);
00596 
00597         TEST_AND_EXPLAIN(mymsize1 > mymset.size(),
00598                          "Had no fewer items when performing collapse: don't know whether it worked.");
00599 
00600         map<string, Xapian::docid> values;
00601         Xapian::MSetIterator i = mymset.begin();
00602         for ( ; i != mymset.end(); ++i) {
00603             string value = i.get_document().get_value(value_no);
00604             TEST(values[value] == 0 || value.empty());
00605             values[value] = *i;
00606         }
00607     }
00608 
00609     return true;
00610 }
00611 
00612 // tests that collapse-on-key modifies the predicted bounds for the number of
00613 // matches appropriately.
00614 DEFINE_TESTCASE(collapsekey2, backend) {
00615     SKIP_TEST("Don't have a suitable database currently");
00616     // FIXME: this needs an appropriate database creating, but that's quite
00617     // subtle to do it seems.
00618     Xapian::Enquire enquire(get_database("apitest_simpledata2"));
00619     enquire.set_query(Xapian::Query("this"));
00620 
00621     Xapian::MSet mymset1 = enquire.get_mset(0, 1);
00622 
00623     // Test that if no duplicates are found, then the upper bound remains
00624     // unchanged and the lower bound drops.
00625     {
00626         enquire.set_query(Xapian::Query("this"));
00627         Xapian::valueno value_no = 3;
00628         enquire.set_collapse_key(value_no);
00629         Xapian::MSet mymset = enquire.get_mset(0, 1);
00630 
00631         TEST(mymset.get_matches_lower_bound() < mymset1.get_matches_lower_bound());
00632         TEST_EQUAL(mymset.get_matches_upper_bound(), mymset1.get_matches_upper_bound());
00633     }
00634 
00635     return true;
00636 }
00637 
00638 // tests that collapse-on-key modifies the predicted bounds for the number of
00639 // matches appropriately.
00640 DEFINE_TESTCASE(collapsekey3, backend) {
00641     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00642     enquire.set_query(Xapian::Query("this"));
00643 
00644     Xapian::MSet mymset1 = enquire.get_mset(0, 3);
00645 
00646     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
00647         enquire.set_collapse_key(value_no);
00648         Xapian::MSet mymset = enquire.get_mset(0, 3);
00649 
00650         TEST_AND_EXPLAIN(mymset1.get_matches_lower_bound() > mymset.get_matches_lower_bound(),
00651                          "Lower bound was not lower when performing collapse: don't know whether it worked.");
00652         TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() > mymset.get_matches_upper_bound(),
00653                          "Upper bound was not lower when performing collapse: don't know whether it worked.");
00654 
00655         map<string, Xapian::docid> values;
00656         Xapian::MSetIterator i = mymset.begin();
00657         for ( ; i != mymset.end(); ++i) {
00658             string value = i.get_document().get_value(value_no);
00659             TEST(values[value] == 0 || value.empty());
00660             values[value] = *i;
00661         }
00662     }
00663 
00664     // Test that if the collapse value is always empty, then the upper bound
00665     // remains unchanged, and the lower bound is the same or lower (it can be
00666     // lower because the matcher counts the number of documents with empty
00667     // collapse keys, but may have rejected a document because its weight is
00668     // too low for the proto-MSet before it even looks at its collapse key).
00669     {
00670         Xapian::valueno value_no = 1000;
00671         enquire.set_collapse_key(value_no);
00672         Xapian::MSet mymset = enquire.get_mset(0, 3);
00673 
00674         TEST(mymset.get_matches_lower_bound() <= mymset1.get_matches_lower_bound());
00675         TEST_EQUAL(mymset.get_matches_upper_bound(), mymset1.get_matches_upper_bound());
00676 
00677         map<string, Xapian::docid> values;
00678         Xapian::MSetIterator i = mymset.begin();
00679         for ( ; i != mymset.end(); ++i) {
00680             string value = i.get_document().get_value(value_no);
00681             TEST(values[value] == 0 || value.empty());
00682             values[value] = *i;
00683         }
00684     }
00685 
00686     return true;
00687 }
00688 
00689 // tests that collapse-on-key modifies the predicted bounds for the number of
00690 // matches appropriately even when no results are requested.
00691 DEFINE_TESTCASE(collapsekey4, backend) {
00692     Xapian::Enquire enquire(get_database("apitest_simpledata"));
00693     enquire.set_query(Xapian::Query("this"));
00694 
00695     Xapian::MSet mymset1 = enquire.get_mset(0, 0);
00696 
00697     for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
00698         enquire.set_collapse_key(value_no);
00699         Xapian::MSet mymset = enquire.get_mset(0, 0);
00700 
00701         TEST_AND_EXPLAIN(mymset.get_matches_lower_bound() == 1,
00702                          "Lower bound was not 1 when performing collapse but not asking for any results.");
00703         TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() == mymset.get_matches_upper_bound(),
00704                          "Upper bound was changed when performing collapse but not asking for any results.");
00705 
00706         map<string, Xapian::docid> values;
00707         Xapian::MSetIterator i = mymset.begin();
00708         for ( ; i != mymset.end(); ++i) {
00709             string value = i.get_document().get_value(value_no);
00710             TEST(values[value] == 0 || value.empty());
00711             values[value] = *i;
00712         }
00713     }
00714 
00715     return true;
00716 }
00717 
00718 // test for keepalives
00719 DEFINE_TESTCASE(keepalive1, remote) {
00720     Xapian::Database db(get_remote_database("apitest_simpledata", 5000));
00721 
00722     /* Test that keep-alives work */
00723     for (int i = 0; i < 10; ++i) {
00724         sleep(2);
00725         db.keep_alive();
00726     }
00727     Xapian::Enquire enquire(db);
00728     enquire.set_query(Xapian::Query("word"));
00729     enquire.get_mset(0, 10);
00730 
00731     /* Test that things break without keepalives */
00732     sleep(10);
00733     enquire.set_query(Xapian::Query("word"));
00734     TEST_EXCEPTION(Xapian::NetworkError,
00735                    enquire.get_mset(0, 10));
00736 
00737     return true;
00738 }
00739 
00740 // test that iterating through all terms in a database works.
00741 DEFINE_TESTCASE(allterms1, backend) {
00742     Xapian::Database db(get_database("apitest_allterms"));
00743     Xapian::TermIterator ati = db.allterms_begin();
00744     TEST(ati != db.allterms_end());
00745     TEST_EQUAL(*ati, "one");
00746     TEST_EQUAL(ati.get_termfreq(), 1);
00747 
00748     Xapian::TermIterator ati2 = ati;
00749 
00750     ati++;
00751     TEST(ati != db.allterms_end());
00752     if (verbose) {
00753         tout << "*ati = `" << *ati << "'\n";
00754         tout << "*ati.length = `" << (*ati).length() << "'\n";
00755         tout << "*ati == \"one\" = " << (*ati == "one") << "\n";
00756         tout << "*ati[3] = " << ((*ati)[3]) << "\n";
00757         tout << "*ati = `" << *ati << "'\n";
00758     }
00759     TEST(*ati == "three");
00760     TEST(ati.get_termfreq() == 3);
00761 
00762 #if 0
00763     TEST(ati2 != db.allterms_end());
00764     TEST(*ati2 == "one");
00765     TEST(ati2.get_termfreq() == 1);
00766 #endif
00767 
00768     ++ati;
00769 #if 0
00770     ++ati2;
00771 #endif
00772     TEST(ati != db.allterms_end());
00773     TEST(*ati == "two");
00774     TEST(ati.get_termfreq() == 2);
00775 
00776 #if 0
00777     TEST(ati2 != db.allterms_end());
00778     TEST(*ati2 == "three");
00779     TEST(ati2.get_termfreq() == 3);
00780 #endif
00781 
00782     ati++;
00783     TEST(ati == db.allterms_end());
00784 
00785     return true;
00786 }
00787 
00788 // test that iterating through all terms in two databases works.
00789 DEFINE_TESTCASE(allterms2, backend) {
00790     Xapian::Database db;
00791     db.add_database(get_database("apitest_allterms"));
00792     db.add_database(get_database("apitest_allterms2"));
00793     Xapian::TermIterator ati = db.allterms_begin();
00794 
00795     TEST(ati != db.allterms_end());
00796     TEST(*ati == "five");
00797     TEST(ati.get_termfreq() == 2);
00798     ati++;
00799 
00800     TEST(ati != db.allterms_end());
00801     TEST(*ati == "four");
00802     TEST(ati.get_termfreq() == 1);
00803 
00804     ati++;
00805     TEST(ati != db.allterms_end());
00806     TEST(*ati == "one");
00807     TEST(ati.get_termfreq() == 1);
00808 
00809     ++ati;
00810     TEST(ati != db.allterms_end());
00811     TEST(*ati == "six");
00812     TEST(ati.get_termfreq() == 3);
00813 
00814     ati++;
00815     TEST(ati != db.allterms_end());
00816     TEST(*ati == "three");
00817     TEST(ati.get_termfreq() == 3);
00818 
00819     ati++;
00820     TEST(ati != db.allterms_end());
00821     TEST(*ati == "two");
00822     TEST(ati.get_termfreq() == 2);
00823 
00824     ati++;
00825     TEST(ati == db.allterms_end());
00826 
00827     return true;
00828 }
00829 
00830 // test that skip_to sets at_end (regression test)
00831 DEFINE_TESTCASE(allterms3, backend) {
00832     Xapian::Database db;
00833     db.add_database(get_database("apitest_allterms"));
00834     Xapian::TermIterator ati = db.allterms_begin();
00835 
00836     ati.skip_to(string("zzzzzz"));
00837     TEST(ati == db.allterms_end());
00838 
00839     return true;
00840 }
00841 
00842 // test that next ignores extra entries due to long posting lists being
00843 // chunked (regression test for quartz)
00844 DEFINE_TESTCASE(allterms4, backend) {
00845     // apitest_allterms4 contains 682 documents each containing just the word
00846     // "foo".  682 was the magic number which started to cause Quartz problems.
00847     Xapian::Database db = get_database("apitest_allterms4");
00848 
00849     Xapian::TermIterator i = db.allterms_begin();
00850     TEST(i != db.allterms_end());
00851     TEST(*i == "foo");
00852     TEST(i.get_termfreq() == 682);
00853     ++i;
00854     TEST(i == db.allterms_end());
00855 
00856     return true;
00857 }
00858 
00859 // test that skip_to with an exact match sets the current term (regression test
00860 // for quartz)
00861 DEFINE_TESTCASE(allterms5, backend) {
00862     Xapian::Database db;
00863     db.add_database(get_database("apitest_allterms"));
00864     Xapian::TermIterator ati = db.allterms_begin();
00865     ati.skip_to("three");
00866     TEST(ati != db.allterms_end());
00867     TEST_EQUAL(*ati, "three");
00868 
00869     return true;
00870 }
00871 
00872 // test allterms iterators with prefixes
00873 DEFINE_TESTCASE(allterms6, backend) {
00874     Xapian::Database db;
00875     db.add_database(get_database("apitest_allterms"));
00876     db.add_database(get_database("apitest_allterms2"));
00877 
00878     Xapian::TermIterator ati = db.allterms_begin("three");
00879     TEST(ati != db.allterms_end("three"));
00880     TEST_EQUAL(*ati, "three");
00881     ati.skip_to("three");
00882     TEST(ati != db.allterms_end("three"));
00883     TEST_EQUAL(*ati, "three");
00884     ati++;
00885     TEST(ati == db.allterms_end("three"));
00886 
00887     ati = db.allterms_begin("thre");
00888     TEST(ati != db.allterms_end("thre"));
00889     TEST_EQUAL(*ati, "three");
00890     ati.skip_to("three");
00891     TEST(ati != db.allterms_end("thre"));
00892     TEST_EQUAL(*ati, "three");
00893     ati++;
00894     TEST(ati == db.allterms_end("thre"));
00895 
00896     ati = db.allterms_begin("f");
00897     TEST(ati != db.allterms_end("f"));
00898     TEST_EQUAL(*ati, "five");
00899     TEST(ati != db.allterms_end("f"));
00900     ati.skip_to("three");
00901     TEST(ati == db.allterms_end("f"));
00902 
00903     ati = db.allterms_begin("f");
00904     TEST(ati != db.allterms_end("f"));
00905     TEST_EQUAL(*ati, "five");
00906     ati++;
00907     TEST(ati != db.allterms_end("f"));
00908     TEST_EQUAL(*ati, "four");
00909     ati++;
00910     TEST(ati == db.allterms_end("f"));
00911 
00912     ati = db.allterms_begin("absent");
00913     TEST(ati == db.allterms_end("absent"));
00914 
00915     return true;
00916 }
00917 
00918 // test that searching for a term with a special characters in it works
00919 DEFINE_TESTCASE(specialterms1, backend) {
00920     Xapian::Enquire enquire(get_database("apitest_space"));
00921     Xapian::MSet mymset;
00922     Xapian::doccount count;
00923     Xapian::MSetIterator m;
00924     Xapian::Stem stemmer("english");
00925 
00926     enquire.set_query(stemmer("new\nline"));
00927     mymset = enquire.get_mset(0, 10);
00928     TEST_MSET_SIZE(mymset, 1);
00929     count = 0;
00930     for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
00931     TEST_EQUAL(count, 1);
00932 
00933     for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
00934         string value = mymset.begin().get_document().get_value(value_no);
00935         TEST_NOT_EQUAL(value, "");
00936         if (value_no == 0) {
00937             TEST(value.size() > 263);
00938             TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
00939             for (int k = 0; k < 256; k++) {
00940                 TEST_EQUAL(static_cast<unsigned char>(value[k+7]), k);
00941             }
00942         }
00943     }
00944 
00945     enquire.set_query(stemmer(string("big\0zero", 8)));
00946     mymset = enquire.get_mset(0, 10);
00947     TEST_MSET_SIZE(mymset, 1);
00948     count = 0;
00949     for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
00950     TEST_EQUAL(count, 1);
00951 
00952     return true;
00953 }
00954 
00955 // test that terms with a special characters in appear correctly when iterating allterms
00956 DEFINE_TESTCASE(specialterms2, backend) {
00957     Xapian::Database db(get_database("apitest_space"));
00958 
00959     // Check the terms are all as expected (after stemming) and that allterms
00960     // copes with iterating over them.
00961     Xapian::TermIterator t;
00962     t = db.allterms_begin();
00963     TEST_EQUAL(*t, "back\\slash"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00964     TEST_EQUAL(*t, string("big\0zero", 8)); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00965     TEST_EQUAL(*t, "new\nlin"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00966     TEST_EQUAL(*t, "one\x01on"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00967     TEST_EQUAL(*t, "space man"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00968     TEST_EQUAL(*t, "tab\tbi"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
00969     TEST_EQUAL(*t, "tu\x02tu"); ++t; TEST_EQUAL(t, db.allterms_end());
00970 
00971     // Now check that skip_to exactly a term containing a zero byte works.
00972     // This is a regression test for flint and quartz - an Assert() used to
00973     // fire in debug builds (the Assert was wrong - the actual code handled
00974     // this OK).
00975     t = db.allterms_begin();
00976     t.skip_to(string("big\0zero", 8));
00977     TEST_NOT_EQUAL(t, db.allterms_end());
00978     TEST_EQUAL(*t, string("big\0zero", 8));
00979 
00980     return true;
00981 }
00982 
00983 // test that rsets behave correctly with multiDBs
00984 DEFINE_TESTCASE(rsetmultidb2, backend && !multi) {
00985     Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
00986     Xapian::Database mydb2(get_database("apitest_rset"));
00987     mydb2.add_database(get_database("apitest_simpledata2"));
00988 
00989     Xapian::Enquire enquire1(mydb1);
00990     Xapian::Enquire enquire2(mydb2);
00991 
00992     Xapian::Query myquery = query("is");
00993 
00994     enquire1.set_query(myquery);
00995     enquire2.set_query(myquery);
00996 
00997     Xapian::RSet myrset1;
00998     Xapian::RSet myrset2;
00999     myrset1.add_document(4);
01000     myrset2.add_document(2);
01001 
01002     Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
01003     Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
01004     Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
01005     Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
01006 
01007     mset_expect_order(mymset1a, 4, 3);
01008     mset_expect_order(mymset1b, 4, 3);
01009     mset_expect_order(mymset2a, 2, 5);
01010     mset_expect_order(mymset2b, 2, 5);
01011 
01012     TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
01013     TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
01014     TEST_NOT_EQUAL(mymset1a, mymset1b);
01015     TEST_NOT_EQUAL(mymset2a, mymset2b);
01016 
01017     return true;
01018 }
01019 
01020 // tests an expand across multiple databases
01021 DEFINE_TESTCASE(multiexpand1, backend && !multi) {
01022     Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
01023     Xapian::Enquire enquire1(mydb1);
01024 
01025     Xapian::Database mydb2(get_database("apitest_simpledata"));
01026     mydb2.add_database(get_database("apitest_simpledata2"));
01027     Xapian::Enquire enquire2(mydb2);
01028 
01029     // make simple equivalent rsets, with a document from each database in each.
01030     Xapian::RSet rset1;
01031     Xapian::RSet rset2;
01032     rset1.add_document(1);
01033     rset1.add_document(7);
01034     rset2.add_document(1);
01035     rset2.add_document(2);
01036 
01037     // retrieve the top ten results from each method of accessing
01038     // multiple text files
01039 
01040     // This is the single database one.
01041     Xapian::ESet eset1 = enquire1.get_eset(1000, rset1);
01042 
01043     // This is the multi database with approximation
01044     Xapian::ESet eset2 = enquire2.get_eset(1000, rset2);
01045 
01046     // This is the multi database without approximation
01047     Xapian::ESet eset3 = enquire2.get_eset(1000, rset2, Xapian::Enquire::USE_EXACT_TERMFREQ);
01048 
01049     TEST_EQUAL(eset1.size(), eset2.size());
01050     TEST_EQUAL(eset1.size(), eset3.size());
01051 
01052     Xapian::ESetIterator i = eset1.begin();
01053     Xapian::ESetIterator j = eset2.begin();
01054     Xapian::ESetIterator k = eset3.begin();
01055     bool all_iwts_equal_jwts = true;
01056     while (i != eset1.end() && j != eset2.end() && k != eset3.end()) {
01057         if (i.get_weight() != j.get_weight()) all_iwts_equal_jwts = false;
01058         TEST_EQUAL(i.get_weight(), k.get_weight());
01059         TEST_EQUAL(*i, *k);
01060         ++i;
01061         ++j;
01062         ++k;
01063     }
01064     TEST(i == eset1.end());
01065     TEST(j == eset2.end());
01066     TEST(k == eset3.end());
01067     TEST(!all_iwts_equal_jwts);
01068     return true;
01069 }
01070 
01071 // tests that opening a non-existent postlist returns an empty list
01072 DEFINE_TESTCASE(postlist1, backend) {
01073     Xapian::Database db(get_database("apitest_simpledata"));
01074 
01075     TEST_EQUAL(db.postlist_begin("rosebud"), db.postlist_end("rosebud"));
01076 
01077     string s = "let_us_see_if_we_can_break_it_with_a_really_really_long_term.";
01078     for (int i = 0; i < 8; ++i) {
01079         s += s;
01080         TEST_EQUAL(db.postlist_begin(s), db.postlist_end(s));
01081     }
01082 
01083     // A regression test (no, really!)
01084     TEST_NOT_EQUAL(db.postlist_begin("a"), db.postlist_end("a"));
01085 
01086     return true;
01087 }
01088 
01089 // tests that a Xapian::PostingIterator works as an STL iterator
01090 DEFINE_TESTCASE(postlist2, backend) {
01091     Xapian::Database db(get_database("apitest_simpledata"));
01092     Xapian::PostingIterator p;
01093     p = db.postlist_begin("this");
01094     Xapian::PostingIterator pend = db.postlist_end("this");
01095 
01096     // test operator= creates a copy which compares equal
01097     Xapian::PostingIterator p_copy = p;
01098     TEST_EQUAL(p, p_copy);
01099 
01100     // test copy constructor creates a copy which compares equal
01101     Xapian::PostingIterator p_clone(p);
01102     TEST_EQUAL(p, p_clone);
01103 
01104     vector<Xapian::docid> v(p, pend);
01105 
01106     p = db.postlist_begin("this");
01107     pend = db.postlist_end("this");
01108     vector<Xapian::docid>::const_iterator i;
01109     for (i = v.begin(); i != v.end(); i++) {
01110         TEST_NOT_EQUAL(p, pend);
01111         TEST_EQUAL(*i, *p);
01112         p++;
01113     }
01114     TEST_EQUAL(p, pend);
01115     return true;
01116 }
01117 
01118 // tests that a Xapian::PostingIterator still works when the DB is deleted
01119 DEFINE_TESTCASE(postlist3, backend) {
01120     Xapian::PostingIterator u;
01121     {
01122         Xapian::Database db_temp(get_database("apitest_simpledata"));
01123         u = db_temp.postlist_begin("this");
01124     }
01125 
01126     Xapian::Database db(get_database("apitest_simpledata"));
01127     Xapian::PostingIterator p = db.postlist_begin("this");
01128     Xapian::PostingIterator pend = db.postlist_end("this");
01129 
01130     while (p != pend) {
01131         TEST_EQUAL(*p, *u);
01132         p++;
01133         u++;
01134     }
01135     return true;
01136 }
01137 
01138 // tests skip_to
01139 DEFINE_TESTCASE(postlist4, backend) {
01140     Xapian::Database db(get_database("apitest_simpledata"));
01141     Xapian::PostingIterator i = db.postlist_begin("this");
01142     i.skip_to(1);
01143     i.skip_to(999999999);
01144     TEST(i == db.postlist_end("this"));
01145     return true;
01146 }
01147 
01148 // tests long postlists
01149 DEFINE_TESTCASE(postlist5, backend) {
01150     Xapian::Database db(get_database("apitest_manydocs"));
01151     // Allow for databases which don't support length
01152     if (db.get_avlength() != 1)
01153         TEST_EQUAL_DOUBLE(db.get_avlength(), 4);
01154     Xapian::PostingIterator i = db.postlist_begin("this");
01155     unsigned int j = 1;
01156     while (i != db.postlist_end("this")) {
01157         TEST_EQUAL(*i, j);
01158         i++;
01159         j++;
01160     }
01161     TEST_EQUAL(j, 513);
01162     return true;
01163 }
01164 
01165 // tests document length in postlists
01166 DEFINE_TESTCASE(postlist6, backend) {
01167     Xapian::Database db(get_database("apitest_simpledata"));
01168     Xapian::PostingIterator i = db.postlist_begin("this");
01169     TEST(i != db.postlist_end("this"));
01170     while (i != db.postlist_end("this")) {
01171         TEST_EQUAL(i.get_doclength(), db.get_doclength(*i));
01172         i++;
01173     }
01174     return true;
01175 }
01176 
01177 // tests collection frequency
01178 DEFINE_TESTCASE(collfreq1, backend) {
01179     Xapian::Database db(get_database("apitest_simpledata"));
01180 
01181     TEST_EQUAL(db.get_collection_freq("this"), 11);
01182     TEST_EQUAL(db.get_collection_freq("first"), 1);
01183     TEST_EQUAL(db.get_collection_freq("last"), 0);
01184     TEST_EQUAL(db.get_collection_freq("word"), 9);
01185 
01186     Xapian::Database db1(get_database("apitest_simpledata", "apitest_simpledata2"));
01187     Xapian::Database db2(get_database("apitest_simpledata"));
01188     db2.add_database(get_database("apitest_simpledata2"));
01189 
01190     TEST_EQUAL(db1.get_collection_freq("this"), 15);
01191     TEST_EQUAL(db1.get_collection_freq("first"), 1);
01192     TEST_EQUAL(db1.get_collection_freq("last"), 0);
01193     TEST_EQUAL(db1.get_collection_freq("word"), 11);
01194     TEST_EQUAL(db2.get_collection_freq("this"), 15);
01195     TEST_EQUAL(db2.get_collection_freq("first"), 1);
01196     TEST_EQUAL(db2.get_collection_freq("last"), 0);
01197     TEST_EQUAL(db2.get_collection_freq("word"), 11);
01198 
01199     return true;
01200 }
01201 
01202 // Regression test for split msets being incorrect when sorting
01203 DEFINE_TESTCASE(sortvalue1, backend) {
01204     Xapian::Enquire enquire(get_database("apitest_simpledata"));
01205     enquire.set_query(Xapian::Query("this"));
01206 
01207     for (int pass = 1; pass <= 2; ++pass) {
01208         for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
01209             tout << "Sorting on value " << value_no << endl;
01210             enquire.set_sort_by_value(value_no);
01211             Xapian::MSet allbset = enquire.get_mset(0, 100);
01212             Xapian::MSet partbset1 = enquire.get_mset(0, 3);
01213             Xapian::MSet partbset2 = enquire.get_mset(3, 97);
01214             TEST_EQUAL(allbset.size(), partbset1.size() + partbset2.size());
01215 
01216             bool ok = true;
01217             int n = 0;
01218             Xapian::MSetIterator i, j;
01219             j = allbset.begin();
01220             for (i = partbset1.begin(); i != partbset1.end(); ++i) {
01221                 tout << "Entry " << n << ": " << *i << " | " << *j << endl;
01222                 TEST(j != allbset.end());
01223                 if (*i != *j) ok = false;
01224                 ++j;
01225                 ++n;
01226             }
01227             tout << "===\n";
01228             for (i = partbset2.begin(); i != partbset2.end(); ++i) {
01229                 tout << "Entry " << n << ": " << *i << " | " << *j << endl;
01230                 TEST(j != allbset.end());
01231                 if (*i != *j) ok = false;
01232                 ++j;
01233                 ++n;
01234             }
01235             TEST(j == allbset.end());
01236             if (!ok)
01237                 FAIL_TEST("Split msets aren't consistent with unsplit");
01238         }
01239         enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01240     }
01241 
01242     return true;
01243 }
01244 
01245 // consistency check match - vary mset size and check results agree.
01246 // consistency1 will run on the remote backend, but it's particularly slow
01247 // with that, and testing it there doesn't actually improve the test
01248 // coverage really.
01249 DEFINE_TESTCASE(consistency1, backend && !remote) {
01250     Xapian::Database db(get_database("etext"));
01251     Xapian::Enquire enquire(db);
01252     enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, Xapian::Query("the"), Xapian::Query("sky")));
01253     Xapian::doccount lots = 214;
01254     Xapian::MSet bigmset = enquire.get_mset(0, lots);
01255     TEST_EQUAL(bigmset.size(), lots);
01256     try {
01257         for (Xapian::doccount start = 0; start < lots; ++start) {
01258             for (Xapian::doccount size = 0; size < lots - start; ++size) {
01259                 Xapian::MSet mset = enquire.get_mset(start, size);
01260                 if (mset.size()) {
01261                     TEST_EQUAL(start + mset.size(),
01262                                min(start + size, bigmset.size()));
01263                 } else if (size) {
01264 //              tout << start << mset.size() << bigmset.size() << endl;
01265                     TEST(start >= bigmset.size());
01266                 }
01267                 for (Xapian::doccount i = 0; i < mset.size(); ++i) {
01268                     TEST_EQUAL(*mset[i], *bigmset[start + i]);
01269                     TEST_EQUAL_DOUBLE(mset[i].get_weight(),
01270                                       bigmset[start + i].get_weight());
01271                 }
01272             }
01273         }
01274     }
01275     catch (const Xapian::NetworkTimeoutError &) {
01276         // consistency1 is a long test - may timeout with the remote backend...
01277         SKIP_TEST("Test taking too long");
01278     }
01279     return true;
01280 }
01281 
01282 // tests that specifying a nonexistent input file throws an exception.
01283 DEFINE_TESTCASE(quartzdatabaseopeningerror1, quartz) {
01284     mkdir(".quartz", 0755);
01285 
01286     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01287                    Xapian::Quartz::open(".quartz/nosuchdirectory"));
01288     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01289                    Xapian::Quartz::open(".quartz/nosuchdirectory", Xapian::DB_OPEN));
01290 
01291     mkdir(".quartz/emptydirectory", 0700);
01292     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01293                    Xapian::Quartz::open(".quartz/emptydirectory"));
01294 
01295     touch(".quartz/somefile");
01296     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01297         Xapian::Quartz::open(".quartz/somefile"));
01298     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01299         Xapian::Quartz::open(".quartz/somefile", Xapian::DB_OPEN));
01300     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01301         Xapian::Quartz::open(".quartz/somefile", Xapian::DB_CREATE));
01302     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01303         Xapian::Quartz::open(".quartz/somefile", Xapian::DB_CREATE_OR_OPEN));
01304     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01305         Xapian::Quartz::open(".quartz/somefile", Xapian::DB_CREATE_OR_OVERWRITE));
01306 
01307     return true;
01308 }
01309 
01311 DEFINE_TESTCASE(quartzdatabaseopen1, quartz) {
01312     const char * dbdir = ".quartz/test_quartzdatabaseopen1";
01313     mkdir(".quartz", 0755);
01314 
01315     {
01316         rm_rf(dbdir);
01317         Xapian::WritableDatabase wdb =
01318             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE);
01319         TEST_EXCEPTION(Xapian::DatabaseLockError,
01320             Xapian::Quartz::open(dbdir, Xapian::DB_OPEN));
01321         Xapian::Quartz::open(dbdir);
01322     }
01323 
01324     {
01325         rm_rf(dbdir);
01326         mkdir(dbdir, 0700);
01327         Xapian::WritableDatabase wdb =
01328             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE);
01329         TEST_EXCEPTION(Xapian::DatabaseLockError,
01330             Xapian::Quartz::open(dbdir, Xapian::DB_OPEN));
01331         Xapian::Quartz::open(dbdir);
01332     }
01333 
01334     {
01335         rm_rf(dbdir);
01336         Xapian::WritableDatabase wdb =
01337             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
01338         TEST_EXCEPTION(Xapian::DatabaseLockError,
01339             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE));
01340         Xapian::Quartz::open(dbdir);
01341     }
01342 
01343     {
01344         rm_rf(dbdir);
01345         Xapian::WritableDatabase wdb =
01346             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01347         TEST_EXCEPTION(Xapian::DatabaseLockError,
01348             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OPEN));
01349         Xapian::Quartz::open(dbdir);
01350     }
01351 
01352     {
01353         TEST_EXCEPTION(Xapian::DatabaseCreateError,
01354             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE));
01355         Xapian::WritableDatabase wdb =
01356             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01357         Xapian::Quartz::open(dbdir);
01358     }
01359 
01360     {
01361         Xapian::WritableDatabase wdb =
01362             Xapian::Quartz::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
01363         Xapian::Quartz::open(dbdir);
01364     }
01365 
01366     {
01367         Xapian::WritableDatabase wdb =
01368             Xapian::Quartz::open(dbdir, Xapian::DB_OPEN);
01369         Xapian::Quartz::open(dbdir);
01370     }
01371 
01372     return true;
01373 }
01374 
01375 // tests that specifying a nonexistent input file throws an exception.
01376 DEFINE_TESTCASE(flintdatabaseopeningerror1, flint) {
01377     mkdir(".flint", 0755);
01378 
01379     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01380                    Xapian::Flint::open(".flint/nosuchdirectory"));
01381     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01382                    Xapian::Flint::open(".flint/nosuchdirectory", Xapian::DB_OPEN));
01383 
01384     mkdir(".flint/emptydirectory", 0700);
01385     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01386                    Xapian::Flint::open(".flint/emptydirectory"));
01387 
01388     touch(".flint/somefile");
01389     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01390                    Xapian::Flint::open(".flint/somefile"));
01391     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
01392                    Xapian::Flint::open(".flint/somefile", Xapian::DB_OPEN));
01393     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01394                    Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE));
01395     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01396                    Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE_OR_OPEN));
01397     TEST_EXCEPTION(Xapian::DatabaseCreateError,
01398                    Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE_OR_OVERWRITE));
01399 
01400     return true;
01401 }
01402 
01404 DEFINE_TESTCASE(flintdatabaseformaterror1, flint) {
01405     string dbdir = test_driver::get_srcdir();
01406     dbdir += "/testdata/flint-0.9.9";
01407 
01408     // We should get a version error when we try and open the database for
01409     // reading now.
01410     TEST_EXCEPTION(Xapian::DatabaseVersionError,
01411                    Xapian::Database db(dbdir));
01412 
01413     // Also test when explicitly opening as a flint database.
01414     TEST_EXCEPTION(Xapian::DatabaseVersionError,
01415                    (void)Xapian::Flint::open(dbdir));
01416 
01417     // Clean up the "flintlock" file that we will have created while trying
01418     // to open the database.
01419     unlink((dbdir + "/flintlock").c_str());
01420 
01421     return true;
01422 }
01423 
01425 // Xapian::DB_CREATE_OR_OVERWRITE.
01426 DEFINE_TESTCASE(flintdatabaseformaterror2, flint) {
01427     string flint099 = test_driver::get_srcdir();
01428     flint099 += "/testdata/flint-0.9.9";
01429 
01430     mkdir(".flint", 0755);
01431     string dbdir = ".flint/test_flintdatabaseformaterror2";
01432 
01433     rm_rf(dbdir);
01434     cp_R(flint099, dbdir);
01435 
01436     (void)Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01437 
01438     rm_rf(dbdir);
01439     cp_R(flint099, dbdir);
01440 
01441     // Also test when explicitly opening as a flint database.
01442     (void)Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01443 
01444     return true;
01445 }
01446 
01447 // regression test for not releasing lock on error.
01448 DEFINE_TESTCASE(flintdatabaseformaterror3, flint) {
01449     string flint099 = test_driver::get_srcdir();
01450     flint099 += "/testdata/flint-0.9.9";
01451 
01452     mkdir(".flint", 0755);
01453     string dbdir = ".flint/test_flintdatabaseformaterror3";
01454 
01455     rm_rf(dbdir);
01456     cp_R(flint099, dbdir);
01457 
01458     TEST_EXCEPTION(Xapian::DatabaseVersionError,
01459                    Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OPEN));
01460 
01461     // This used to throw a DatabaseLockError: "Unable to acquire database
01462     // write lock on .flint/formatdb: already locked"
01463     Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01464 
01465     return true;
01466 }
01467 
01468 // Test that 1.0.2 and later can open 1.0.1 databases.
01469 DEFINE_TESTCASE(flintbackwardcompat1, flint) {
01470     string flint101 = test_driver::get_srcdir();
01471     flint101 += "/testdata/flint-1.0.1";
01472 
01473     mkdir(".flint", 0755);
01474     string dbdir = ".flint/test_flintbackwardcompat1";
01475 
01476     rm_rf(dbdir);
01477     cp_R(flint101, dbdir);
01478 
01479     // Check we can open the older format for reading.
01480     {
01481         Xapian::Database db(dbdir);
01482         TEST_EQUAL(db.get_doccount(), 0);
01483     }
01484 
01485     // Check we can open the older format for update.
01486     {
01487         Xapian::WritableDatabase db(dbdir, Xapian::DB_OPEN);
01488         TEST_EQUAL(db.get_doccount(), 0);
01489     }
01490 
01491     return true;
01492 }
01493 
01494 // Test that 1.0.3 and later can open 1.0.2 databases.
01495 DEFINE_TESTCASE(flintbackwardcompat2, flint) {
01496     string flint102 = test_driver::get_srcdir();
01497     flint102 += "/testdata/flint-1.0.2";
01498 
01499     mkdir(".flint", 0755);
01500     string dbdir = ".flint/test_flintbackwardcompat2";
01501 
01502     rm_rf(dbdir);
01503     cp_R(flint102, dbdir);
01504 
01505     // Check we can open the older format for reading.
01506     {
01507         Xapian::Database db(dbdir);
01508         TEST_EQUAL(db.get_doccount(), 0);
01509     }
01510 
01511     // Check we can open the older format for update.
01512     {
01513         Xapian::WritableDatabase db(dbdir, Xapian::DB_OPEN);
01514         TEST_EQUAL(db.get_doccount(), 0);
01515     }
01516 
01517     return true;
01518 }
01519 
01521 DEFINE_TESTCASE(flintdatabaseopen1, flint) {
01522     const string dbdir = ".flint/test_flintdatabaseopen1";
01523     mkdir(".flint", 0755);
01524 
01525     {
01526         rm_rf(dbdir);
01527         Xapian::WritableDatabase wdb =
01528             Xapian::Flint::open(dbdir, Xapian::DB_CREATE);
01529         TEST_EXCEPTION(Xapian::DatabaseLockError,
01530             Xapian::Flint::open(dbdir, Xapian::DB_OPEN));
01531         Xapian::Flint::open(dbdir);
01532     }
01533 
01534     {
01535         rm_rf(dbdir);
01536         Xapian::WritableDatabase wdb =
01537             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
01538         TEST_EXCEPTION(Xapian::DatabaseLockError,
01539             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE));
01540         Xapian::Flint::open(dbdir);
01541     }
01542 
01543     {
01544         rm_rf(dbdir);
01545         Xapian::WritableDatabase wdb =
01546             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01547         TEST_EXCEPTION(Xapian::DatabaseLockError,
01548             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN));
01549         Xapian::Flint::open(dbdir);
01550     }
01551 
01552     {
01553         TEST_EXCEPTION(Xapian::DatabaseCreateError,
01554             Xapian::Flint::open(dbdir, Xapian::DB_CREATE));
01555         Xapian::WritableDatabase wdb =
01556             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
01557         Xapian::Flint::open(dbdir);
01558     }
01559 
01560     {
01561         Xapian::WritableDatabase wdb =
01562             Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
01563         Xapian::Flint::open(dbdir);
01564     }
01565 
01566     {
01567         Xapian::WritableDatabase wdb =
01568             Xapian::Flint::open(dbdir, Xapian::DB_OPEN);
01569         Xapian::Flint::open(dbdir);
01570     }
01571 
01572     return true;
01573 }
01574 
01575 // feature test for Enquire:
01576 // set_sort_by_value
01577 // set_sort_by_value_then_relevance
01578 // set_sort_by_relevance_then_value
01579 DEFINE_TESTCASE(sortrel1, backend) {
01580     Xapian::Enquire enquire(get_database("apitest_sortrel"));
01581     enquire.set_sort_by_value(1);
01582     enquire.set_query(Xapian::Query("woman"));
01583 
01584     const Xapian::docid order1[] = { 1,2,3,4,5,6,7,8,9 };
01585     const Xapian::docid order2[] = { 2,1,3,6,5,4,7,9,8 };
01586     const Xapian::docid order3[] = { 3,2,1,6,5,4,9,8,7 };
01587     const Xapian::docid order4[] = { 7,8,9,4,5,6,1,2,3 };
01588     const Xapian::docid order5[] = { 9,8,7,6,5,4,3,2,1 };
01589     const Xapian::docid order6[] = { 7,9,8,6,5,4,2,1,3 };
01590     const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 };
01591     const Xapian::docid order8[] = { 7,6,2,9,5,1,8,4,3 };
01592     const Xapian::docid order9[] = { 2,6,7,1,5,9,3,4,8 };
01593 
01594     Xapian::MSet mset;
01595     size_t i;
01596 
01597     mset = enquire.get_mset(0, 10);
01598     TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
01599     for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
01600         TEST_EQUAL(*mset[i], order1[i]);
01601     }
01602 
01603     enquire.set_sort_by_value_then_relevance(1);
01604 
01605     mset = enquire.get_mset(0, 10);
01606     TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
01607     for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
01608         TEST_EQUAL(*mset[i], order2[i]);
01609     }
01610 
01611     enquire.set_sort_by_value(1);
01612 
01613     mset = enquire.get_mset(0, 10);
01614     TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
01615     for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
01616         TEST_EQUAL(*mset[i], order1[i]);
01617     }
01618 
01619     enquire.set_sort_by_value_then_relevance(1);
01620     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01621 
01622     mset = enquire.get_mset(0, 10);
01623     TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
01624     for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
01625         TEST_EQUAL(*mset[i], order2[i]);
01626     }
01627 
01628     enquire.set_sort_by_value(1);
01629     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01630 
01631     mset = enquire.get_mset(0, 10);
01632     TEST_EQUAL(mset.size(), sizeof(order3) / sizeof(Xapian::docid));
01633     for (i = 0; i < sizeof(order3) / sizeof(Xapian::docid); ++i) {
01634         TEST_EQUAL(*mset[i], order3[i]);
01635     }
01636 
01637     enquire.set_sort_by_value(1, false);
01638     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
01639     mset = enquire.get_mset(0, 10);
01640     TEST_EQUAL(mset.size(), sizeof(order4) / sizeof(Xapian::docid));
01641     for (i = 0; i < sizeof(order4) / sizeof(Xapian::docid); ++i) {
01642         TEST_EQUAL(*mset[i], order4[i]);
01643     }
01644 
01645     enquire.set_sort_by_value(1, false);
01646     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01647     mset = enquire.get_mset(0, 10);
01648     TEST_EQUAL(mset.size(), sizeof(order5) / sizeof(Xapian::docid));
01649     for (i = 0; i < sizeof(order5) / sizeof(Xapian::docid); ++i) {
01650         TEST_EQUAL(*mset[i], order5[i]);
01651     }
01652 
01653     enquire.set_sort_by_value_then_relevance(1, false);
01654     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
01655     mset = enquire.get_mset(0, 10);
01656     TEST_EQUAL(mset.size(), sizeof(order6) / sizeof(Xapian::docid));
01657     for (i = 0; i < sizeof(order6) / sizeof(Xapian::docid); ++i) {
01658         TEST_EQUAL(*mset[i], order6[i]);
01659     }
01660 
01661     enquire.set_sort_by_value_then_relevance(1, false);
01662     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01663     mset = enquire.get_mset(0, 10);
01664     TEST_EQUAL(mset.size(), sizeof(order7) / sizeof(Xapian::docid));
01665     for (i = 0; i < sizeof(order7) / sizeof(Xapian::docid); ++i) {
01666         TEST_EQUAL(*mset[i], order7[i]);
01667     }
01668 
01669     enquire.set_sort_by_relevance_then_value(1);
01670     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
01671     mset = enquire.get_mset(0, 10);
01672     TEST_EQUAL(mset.size(), sizeof(order8) / sizeof(Xapian::docid));
01673     for (i = 0; i < sizeof(order8) / sizeof(Xapian::docid); ++i) {
01674         TEST_EQUAL(*mset[i], order8[i]);
01675     }
01676 
01677     enquire.set_sort_by_relevance_then_value(1);
01678     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01679     mset = enquire.get_mset(0, 10);
01680     TEST_EQUAL(mset.size(), sizeof(order8) / sizeof(Xapian::docid));
01681     for (i = 0; i < sizeof(order8) / sizeof(Xapian::docid); ++i) {
01682         TEST_EQUAL(*mset[i], order8[i]);
01683     }
01684 
01685     enquire.set_sort_by_relevance_then_value(1, false);
01686     enquire.set_docid_order(Xapian::Enquire::ASCENDING);
01687     mset = enquire.get_mset(0, 10);
01688     TEST_EQUAL(mset.size(), sizeof(order9) / sizeof(Xapian::docid));
01689     for (i = 0; i < sizeof(order9) / sizeof(Xapian::docid); ++i) {
01690         TEST_EQUAL(*mset[i], order9[i]);
01691     }
01692 
01693     enquire.set_sort_by_relevance_then_value(1, false);
01694     enquire.set_docid_order(Xapian::Enquire::DESCENDING);
01695     mset = enquire.get_mset(0, 10);
01696     TEST_EQUAL(mset.size(), sizeof(order9) / sizeof(Xapian::docid));
01697     for (i = 0; i < sizeof(order9) / sizeof(Xapian::docid); ++i) {
01698         TEST_EQUAL(*mset[i], order9[i]);
01699     }
01700 
01701     return true;
01702 }
01703 
01704 // Test network stats and local stats give the same results.
01705 DEFINE_TESTCASE(netstats1, remote) {
01706     BackendManagerLocal local_manager;
01707     local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
01708 
01709     const char * words[] = { "paragraph", "word" };
01710     Xapian::Query query(Xapian::Query::OP_OR, words, words + 2);
01711     const size_t MSET_SIZE = 10;
01712 
01713     Xapian::RSet rset;
01714     rset.add_document(4);
01715     rset.add_document(9);
01716 
01717     Xapian::MSet mset_alllocal;
01718     {
01719         Xapian::Database db;
01720         db.add_database(local_manager.get_database("apitest_simpledata"));
01721         db.add_database(local_manager.get_database("apitest_simpledata2"));
01722 
01723         Xapian::Enquire enq(db);
01724         enq.set_query(query);
01725         mset_alllocal = enq.get_mset(0, MSET_SIZE, &rset);
01726     }
01727 
01728     {
01729         Xapian::Database db;
01730         db.add_database(local_manager.get_database("apitest_simpledata"));
01731         db.add_database(get_database("apitest_simpledata2"));
01732 
01733         Xapian::Enquire enq(db);
01734         enq.set_query(query);
01735         Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
01736         TEST_EQUAL(mset, mset_alllocal);
01737     }
01738 
01739     {
01740         Xapian::Database db;
01741         db.add_database(get_database("apitest_simpledata"));
01742         db.add_database(local_manager.get_database("apitest_simpledata2"));
01743 
01744         Xapian::Enquire enq(db);
01745         enq.set_query(query);
01746         Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
01747         TEST_EQUAL(mset, mset_alllocal);
01748     }
01749 
01750     {
01751         Xapian::Database db;
01752         db.add_database(get_database("apitest_simpledata"));
01753         db.add_database(get_database("apitest_simpledata2"));
01754 
01755         Xapian::Enquire enq(db);
01756         enq.set_query(query);
01757         Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
01758         TEST_EQUAL(mset, mset_alllocal);
01759     }
01760 
01761     return true;
01762 }
01763 
01764 // Coordinate matching - scores 1 for each matching term
01765 class MyWeight : public Xapian::Weight {
01766     public:
01767         MyWeight * clone() const {
01768             return new MyWeight;
01769         }
01770         MyWeight() { }
01771         ~MyWeight() { }
01772         std::string name() const { return "Coord"; }
01773         std::string serialise() const { return ""; }
01774         MyWeight * unserialise(const std::string & /*s*/) const {
01775             return new MyWeight;
01776         }
01777         Xapian::weight get_sumpart(Xapian::termcount /*wdf*/, Xapian::doclength /*len*/) const { return 1; }
01778         Xapian::weight get_maxpart() const { return 1; }
01779 
01780         Xapian::weight get_sumextra(Xapian::doclength /*len*/) const { return 0; }
01781         Xapian::weight get_maxextra() const { return 0; }
01782 
01783         bool get_sumpart_needs_doclength() const { return false; }
01784 };
01785 
01786 // tests user weighting scheme.
01787 // Would work with remote if we registered the weighting scheme.
01788 // FIXME: do this so we also test that functionality...
01789 DEFINE_TESTCASE(userweight1, backend && !remote) {
01790     Xapian::Enquire enquire(get_database("apitest_simpledata"));
01791     enquire.set_weighting_scheme(MyWeight());
01792     const char * query[] = { "this", "line", "paragraph", "rubbish" };
01793     enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, query,
01794                                     query + sizeof(query) / sizeof(query[0])));
01795     Xapian::MSet mymset1 = enquire.get_mset(0, 100);
01796     // MyWeight scores 1 for each matching term, so the weight should equal
01797     // the number of matching terms.
01798     for (Xapian::MSetIterator i = mymset1.begin(); i != mymset1.end(); ++i) {
01799         Xapian::termcount matching_terms = 0;
01800         Xapian::TermIterator t = enquire.get_matching_terms_begin(i);
01801         while (t != enquire.get_matching_terms_end(i)) {
01802             ++matching_terms;
01803             ++t;
01804         }
01805         TEST_EQUAL(i.get_weight(), matching_terms);
01806     }
01807 
01808     return true;
01809 }
01810 
01811 // tests MatchAll queries
01812 // This is a regression test, which failed with assertion failures in
01813 // revision 9094.  Also check that the results aren't ranked by relevance
01814 // (regression test for bug fixed in 1.0.9).
01815 DEFINE_TESTCASE(matchall1, backend) {
01816     Xapian::Database db(get_database("apitest_simpledata"));
01817     Xapian::Enquire enquire(db);
01818     enquire.set_query(Xapian::Query::MatchAll);
01819     Xapian::MSet mset = enquire.get_mset(0, 10);
01820     TEST_EQUAL(mset.get_matches_lower_bound(), db.get_doccount());
01821 
01822 
01823     enquire.set_query(Xapian::Query(Xapian::Query::OP_OR,
01824                                     Xapian::Query("nosuchterm"),
01825                                     Xapian::Query::MatchAll));
01826     mset = enquire.get_mset(0, 10);
01827     TEST_EQUAL(mset.get_matches_lower_bound(), db.get_doccount());
01828 
01829     // Check that the results aren't ranked by relevance (fixed in 1.0.9).
01830     TEST(mset.size() > 1);
01831     TEST_EQUAL(mset[mset.size() - 1].get_weight(), 0);
01832     TEST_EQUAL(*mset[0], 1);
01833     TEST_EQUAL(*mset[mset.size() - 1], mset.size());
01834  
01835     return true;
01836 }

Documentation for Xapian (version 1.0.10).
Generated on 24 Dec 2008 by Doxygen 1.5.2.