tests/api_nodb.cc

Go to the documentation of this file.
00001 /* api_nodb.cc: tests which don't use any of the backends
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 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_nodb.h"
00027 
00028 #include <string>
00029 #include <vector>
00030 #include "autoptr.h"
00031 
00032 #include <xapian.h>
00033 
00034 #include "apitest.h"
00035 #include "testsuite.h"
00036 #include "testutils.h"
00037 #include "utils.h"
00038 
00039 #include <list>
00040 
00041 using namespace std;
00042 
00043 // always succeeds
00044 DEFINE_TESTCASE(trivial1, !backend) {
00045     return true;
00046 }
00047 
00048 // tests that get_query_terms() returns the terms in the right order
00049 DEFINE_TESTCASE(getqterms1, !backend) {
00050     list<string> answers_list;
00051     answers_list.push_back("one");
00052     answers_list.push_back("two");
00053     answers_list.push_back("three");
00054     answers_list.push_back("four");
00055 
00056     Xapian::Query myquery(Xapian::Query::OP_OR,
00057             Xapian::Query(Xapian::Query::OP_AND,
00058                     Xapian::Query("one", 1, 1),
00059                     Xapian::Query("three", 1, 3)),
00060             Xapian::Query(Xapian::Query::OP_OR,
00061                     Xapian::Query("four", 1, 4),
00062                     Xapian::Query("two", 1, 2)));
00063 
00064     list<string> list1;
00065     {
00066         Xapian::TermIterator t;
00067         for (t = myquery.get_terms_begin(); t != myquery.get_terms_end(); ++t)
00068             list1.push_back(*t);
00069     }
00070     TEST(list1 == answers_list);
00071     list<string> list2(myquery.get_terms_begin(), myquery.get_terms_end());
00072     TEST(list2 == answers_list);
00073     return true;
00074 }
00075 
00076 // tests that get_query_terms() doesn't SEGV on an empty query
00077 // (regression test for bug in 0.9.0)
00078 DEFINE_TESTCASE(getqterms2, !backend) {
00079     Xapian::Query empty_query;
00080     TEST_EQUAL(empty_query.get_terms_begin(), empty_query.get_terms_end());
00081     return true;
00082 }
00083 
00084 // tests that empty queries work correctly
00085 DEFINE_TESTCASE(emptyquery2, !backend) {
00086     // test that Query::empty() is true for an empty query.
00087     TEST(Xapian::Query().empty());
00088     // test that an empty query has length 0
00089     TEST(Xapian::Query().get_length() == 0);
00090     vector<Xapian::Query> v;
00091     TEST(Xapian::Query(Xapian::Query::OP_OR, v.begin(), v.end()).empty());
00092     TEST(Xapian::Query(Xapian::Query::OP_OR, v.begin(), v.end()).get_length() == 0);
00093     return true;
00094 }
00095 
00097 DEFINE_TESTCASE(emptyquery3, !backend) {
00098     static const Xapian::Query::op ops[] = {
00099         Xapian::Query::OP_AND,
00100         Xapian::Query::OP_OR,
00101         Xapian::Query::OP_XOR,
00102         Xapian::Query::OP_AND_MAYBE,
00103         Xapian::Query::OP_AND_NOT
00104     };
00105 
00106     for (size_t i = 0; i < sizeof(ops) / sizeof(ops[0]); ++i) {
00107         tout << "Testing op #" << i << endl;
00108         Xapian::Query empty;
00109         Xapian::Query q("test");
00110         Xapian::Query qcombine(ops[i], empty, q);
00111         tout << qcombine.get_description() << endl;
00112         Xapian::Query qcombine2(ops[i], q, empty);
00113         tout << qcombine2.get_description() << endl;
00114     }
00115 
00116     return true;
00117 }
00118 
00119 // tests that query lengths are calculated correctly
00120 DEFINE_TESTCASE(querylen1, !backend) {
00121     // test that a simple query has the right length
00122     Xapian::Query myquery;
00123     myquery = Xapian::Query(Xapian::Query::OP_OR,
00124                       Xapian::Query("foo"),
00125                       Xapian::Query("bar"));
00126     myquery = Xapian::Query(Xapian::Query::OP_AND,
00127                       myquery,
00128                       Xapian::Query(Xapian::Query::OP_OR,
00129                               Xapian::Query("wibble"),
00130                               Xapian::Query("spoon")));
00131 
00132     TEST_EQUAL(myquery.get_length(), 4);
00133     TEST(!myquery.empty());
00134     return true;
00135 }
00136 
00137 // tests that query lengths are calculated correctly
00138 DEFINE_TESTCASE(querylen2, !backend) {
00139     // test with an even bigger and strange query
00140     string terms[3] = {
00141         "foo",
00142         "bar",
00143         "baz"
00144     };
00145     Xapian::Query queries[3] = {
00146         Xapian::Query("wibble"),
00147         Xapian::Query("wobble"),
00148         Xapian::Query(Xapian::Query::OP_OR, string("jelly"), string("belly"))
00149     };
00150 
00151     Xapian::Query myquery;
00152     vector<string> v1(terms, terms + 3);
00153     vector<Xapian::Query> v2(queries, queries + 3);
00154     vector<Xapian::Query *> v3;
00155     AutoPtr<Xapian::Query> dynquery1(new Xapian::Query(Xapian::Query::OP_AND,
00156                                            string("ball"),
00157                                            string("club")));
00158     AutoPtr<Xapian::Query> dynquery2(new Xapian::Query("ring"));
00159     v3.push_back(dynquery1.get());
00160     v3.push_back(dynquery2.get());
00161 
00162     Xapian::Query myq1 = Xapian::Query(Xapian::Query::OP_AND, v1.begin(), v1.end());
00163     tout << "myq1=" << myq1 << "\n";
00164     TEST_EQUAL(myq1.get_length(), 3);
00165 
00166     Xapian::Query myq2_1 = Xapian::Query(Xapian::Query::OP_OR, v2.begin(), v2.end());
00167     tout << "myq2_1=" << myq2_1 << "\n";
00168     TEST_EQUAL(myq2_1.get_length(), 4);
00169 
00170     Xapian::Query myq2_2 = Xapian::Query(Xapian::Query::OP_AND, v3.begin(), v3.end());
00171     tout << "myq2_2=" << myq2_2 << "\n";
00172     TEST_EQUAL(myq2_2.get_length(), 3);
00173 
00174     Xapian::Query myq2 = Xapian::Query(Xapian::Query::OP_OR, myq2_1, myq2_2);
00175     tout << "myq2=" << myq2 << "\n";
00176     TEST_EQUAL(myq2.get_length(), 7);
00177 
00178     myquery = Xapian::Query(Xapian::Query::OP_OR, myq1, myq2);
00179     tout << "myquery=" << myquery << "\n";
00180     TEST_EQUAL(myquery.get_length(), 10);
00181 
00182     return true;
00183 }
00184 
00185 // tests that queries validate correctly
00186 DEFINE_TESTCASE(queryvalid1, !backend) {
00187     vector<Xapian::Query> v1;
00188     // Need two arguments
00189     TEST_EXCEPTION(Xapian::InvalidArgumentError,
00190                    Xapian::Query(Xapian::Query::OP_AND_NOT, v1.begin(), v1.end()));
00191     tout << "ANDNOT () checked" << endl;
00192     v1.push_back(Xapian::Query("bad"));
00193     TEST_EXCEPTION(Xapian::InvalidArgumentError,
00194                    Xapian::Query(Xapian::Query::OP_AND_NOT, v1.begin(), v1.end()));
00195     tout << "ANDNOT (\"bad\") checked" << endl;
00196     v1.clear();
00197     v1.push_back(Xapian::Query());
00198     TEST_EXCEPTION(Xapian::InvalidArgumentError,
00199                    Xapian::Query(Xapian::Query::OP_AND_NOT, v1.begin(), v1.end()));
00200     tout << "ANDNOT (Xapian::Query()) checked" << endl;
00201     Xapian::Query q2(Xapian::Query::OP_XOR, Xapian::Query("foo"), Xapian::Query("bar"));
00202     tout << "XOR (\"foo\", \"bar\") checked" << endl;
00203     return true;
00204 }
00205 
00206 // tests that collapsing of queries includes subqueries
00207 DEFINE_TESTCASE(subqcollapse1, !backend) {
00208     Xapian::Query queries1[3] = {
00209         Xapian::Query("wibble"),
00210         Xapian::Query("wobble"),
00211         Xapian::Query(Xapian::Query::OP_OR, string("jelly"), string("belly"))
00212     };
00213 
00214     Xapian::Query queries2[3] = {
00215         Xapian::Query(Xapian::Query::OP_AND, string("jelly"), string("belly")),
00216         Xapian::Query("wibble"),
00217         Xapian::Query("wobble")
00218     };
00219 
00220     vector<Xapian::Query> vec1(queries1, queries1 + 3);
00221     Xapian::Query myquery1(Xapian::Query::OP_OR, vec1.begin(), vec1.end());
00222     TEST_EQUAL(myquery1.get_description(),
00223                "Xapian::Query((wibble OR wobble OR jelly OR belly))");
00224 
00225     vector<Xapian::Query> vec2(queries2, queries2 + 3);
00226     Xapian::Query myquery2(Xapian::Query::OP_AND, vec2.begin(), vec2.end());
00227     TEST_EQUAL(myquery2.get_description(),
00228                "Xapian::Query((jelly AND belly AND wibble AND wobble))");
00229 
00230     return true;
00231 }
00232 
00233 // test behaviour when creating a query from an empty vector
00234 DEFINE_TESTCASE(emptyquerypart1, !backend) {
00235     vector<string> emptyterms;
00236     Xapian::Query query(Xapian::Query::OP_OR, emptyterms.begin(), emptyterms.end());
00237     TEST(Xapian::Query(Xapian::Query::OP_AND, query, Xapian::Query("x")).empty());
00238     TEST(Xapian::Query(Xapian::Query::OP_AND, query, Xapian::Query("x")).get_length() == 0);
00239     TEST(!Xapian::Query(Xapian::Query::OP_OR, query, Xapian::Query("x")).empty());
00240     TEST(Xapian::Query(Xapian::Query::OP_OR, query, Xapian::Query("x")).get_length() == 1);
00241     return true;
00242 }
00243 
00244 DEFINE_TESTCASE(singlesubq1, !backend) {
00245     vector<string> oneterm;
00246     oneterm.push_back("solo");
00247     Xapian::Query q_eliteset(Xapian::Query::OP_ELITE_SET, oneterm.begin(), oneterm.end(), 1);
00248     Xapian::Query q_near(Xapian::Query::OP_NEAR, oneterm.begin(), oneterm.end(), 1);
00249     Xapian::Query q_phrase(Xapian::Query::OP_PHRASE, oneterm.begin(), oneterm.end(), 1);
00250     return true;
00251 }
00252 
00253 DEFINE_TESTCASE(stemlangs1, !backend) {
00254     string langs = Xapian::Stem::get_available_languages();
00255     tout << "available languages '" << langs << "'" << endl;
00256     TEST(!langs.empty());
00257 
00258     // Also test the language codes.
00259     langs += " da nl en fi fr de hu it no pt ro ru es sv tr";
00260 
00261     string::size_type i = 0;
00262     while (true) {
00263         string::size_type spc = langs.find(' ', i);
00264         // The only spaces in langs should be a single one between each pair
00265         // of language names.
00266         TEST_NOT_EQUAL(i, spc);
00267 
00268         // Try making a stemmer for this language.  We should be able to create
00269         // it without an exception being thrown.
00270         string language = langs.substr(i, spc - i);
00271         tout << "checking language code '" << language << "' works" << endl;
00272         Xapian::Stem stemmer(language);
00273         if (language.size() > 2) {
00274             string expected("Xapian::Stem(");
00275             expected += language;
00276             expected += ')';
00277             TEST_EQUAL(stemmer.get_description(), expected);
00278         }
00279 
00280         if (spc == string::npos) break;
00281         i = spc + 1;
00282     }
00283 
00284     // Check that we get an exception for a bogus language name.
00285     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Stem stemmer("bogus"));
00286 
00287     // Stem("") should give an object which doesn't change any input.
00288     Xapian::Stem stem_nothing = Xapian::Stem("");
00289 
00290     return true;
00291 }
00292 
00293 // Some simple tests of the built in weighting schemes.
00294 DEFINE_TESTCASE(weight1, !backend) {
00295     Xapian::Weight * wt;
00296 
00297     Xapian::BoolWeight boolweight;
00298     TEST_EQUAL(boolweight.name(), "Bool");
00299     wt = Xapian::BoolWeight().unserialise(boolweight.serialise());
00300     TEST_EQUAL(boolweight.serialise(), wt->serialise());
00301     delete wt;
00302 
00303     Xapian::TradWeight tradweight_dflt;
00304     Xapian::TradWeight tradweight(1.0);
00305     TEST_EQUAL(tradweight.name(), "Trad");
00306     TEST_EQUAL(tradweight_dflt.serialise(), tradweight.serialise());
00307     wt = Xapian::TradWeight().unserialise(tradweight.serialise());
00308     TEST_EQUAL(tradweight.serialise(), wt->serialise());
00309     delete wt;
00310 
00311     Xapian::TradWeight tradweight2(2.0);
00312     TEST_NOT_EQUAL(tradweight.serialise(), tradweight2.serialise());
00313 
00314     Xapian::BM25Weight bm25weight_dflt;
00315     Xapian::BM25Weight bm25weight(1, 0, 1, 0.5, 0.5);
00316     TEST_EQUAL(bm25weight.name(), "BM25");
00317     TEST_EQUAL(bm25weight_dflt.serialise(), bm25weight.serialise());
00318     wt = Xapian::BM25Weight().unserialise(bm25weight.serialise());
00319     TEST_EQUAL(bm25weight.serialise(), wt->serialise());
00320     delete wt;
00321 
00322     Xapian::BM25Weight bm25weight2(1, 0.5, 1, 0.5, 0.5);
00323     TEST_NOT_EQUAL(bm25weight.serialise(), bm25weight2.serialise());
00324 
00325     return true;
00326 }
00327 
00328 // Regression test.
00329 DEFINE_TESTCASE(nosuchdb1, !backend) {
00330     // This is a "nodb" test because it doesn't test a particular backend.
00331     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
00332                    Xapian::Database db("NOsuChdaTabASe"));
00333     return true;
00334 }
00335 
00336 // Feature tests for value manipulations.
00337 DEFINE_TESTCASE(addvalue1, !backend) {
00338     // Regression test for add_value on an existing value (bug#82).
00339     Xapian::Document doc;
00340     doc.add_value(1, "original");
00341     doc.add_value(1, "replacement");
00342     TEST_EQUAL(doc.get_value(1), "replacement");
00343 
00344     doc.add_value(2, "too");
00345     doc.add_value(3, "free");
00346     doc.add_value(4, "for");
00347 
00348     doc.remove_value(2);
00349     doc.remove_value(4);
00350     TEST_EQUAL(doc.get_value(0), "");
00351     TEST_EQUAL(doc.get_value(1), "replacement");
00352     TEST_EQUAL(doc.get_value(2), "");
00353     TEST_EQUAL(doc.get_value(3), "free");
00354     TEST_EQUAL(doc.get_value(4), "");
00355 
00356     return true;
00357 }
00358 
00359 // tests that the collapsing on termpos optimisation gives correct query length
00360 DEFINE_TESTCASE(poscollapse2, !backend) {
00361     Xapian::Query q(Xapian::Query::OP_OR, Xapian::Query("this", 1, 1), Xapian::Query("this", 1, 1));
00362     TEST_EQUAL(q.get_length(), 2);
00363     return true;
00364 }
00365 
00366 // regression test of querying an uninitialised database: should report an
00367 // error; used to segfault with 1.0.0.
00368 DEFINE_TESTCASE(uninitdb1, !backend) {
00369     Xapian::Database db;
00370     TEST_EXCEPTION(Xapian::InvalidArgumentError,
00371                    Xapian::Enquire enq(db));
00372     return true;
00373 }
00374 
00375 // Test a scaleweight query applied to a match nothing query
00376 DEFINE_TESTCASE(scaleweight3, !backend) {
00377     Xapian::Query matchnothing(Xapian::Query::MatchNothing);
00378     Xapian::Query query(Xapian::Query::OP_SCALE_WEIGHT, matchnothing, 3.0);
00379     TEST_EQUAL(query.get_description(), "Xapian::Query()");
00380     return true;
00381 }
00382 
00383 // Test that scaling by a weight close to 1 is optimised away.
00384 DEFINE_TESTCASE(scaleweight4, !backend) {
00385     // Factor is a double which, when multiplied by its reciprocal, doesn't
00386     // give exactly 1.0
00387     double factor = 179.76931348623157e306;
00388     volatile double recip = 1.0 / factor;
00389     double nearly1 = factor * recip;
00390 
00391     TEST_NOT_EQUAL(nearly1, 1.0);
00392     Xapian::Query foo("foo");
00393     Xapian::Query foo_nearly1(Xapian::Query::OP_SCALE_WEIGHT, foo, nearly1);
00394     TEST_EQUAL(foo_nearly1.get_description(), "Xapian::Query(foo)");
00395 
00396     return true;
00397 }
00398 
00399 // Regression test - RSet::get_description() gave a malformed answer in 1.0.7.
00400 DEFINE_TESTCASE(rset4, !backend) {
00401     Xapian::RSet rset;
00402     rset.add_document(1);
00403     // In 1.0.7 this gave: RSet(RSet(RSet::Internal(, 1))
00404     TEST_STRINGS_EQUAL(rset.get_description(), "RSet(RSet::Internal(1))");
00405     return true;
00406 }
00407 
00408 // Check that Query(OP_VALUE_GE, 0, "") -> Query::MatchAll.
00409 DEFINE_TESTCASE(opvaluege1, !backend) {
00410     Xapian::Query query(Xapian::Query::OP_VALUE_GE, 0, "");
00411     TEST_STRINGS_EQUAL(query.get_description(), Xapian::Query::MatchAll.get_description());
00412     return true;
00413 }

Documentation for Xapian (version 1.0.20).
Generated on 28 Apr 2010 by Doxygen 1.5.2.