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 
00274         if (spc == string::npos) break;
00275         i = spc + 1;
00276     }
00277 
00278     // Check that we get an exception for a bogus language name.
00279     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Stem stemmer("bogus"));
00280 
00281     // Stem("") should give an object which doesn't change any input.
00282     Xapian::Stem stem_nothing = Xapian::Stem("");
00283 
00284     return true;
00285 }
00286 
00287 // Some simple tests of the built in weighting schemes.
00288 DEFINE_TESTCASE(weight1, !backend) {
00289     Xapian::Weight * wt;
00290 
00291     Xapian::BoolWeight boolweight;
00292     TEST_EQUAL(boolweight.name(), "Bool");
00293     wt = Xapian::BoolWeight().unserialise(boolweight.serialise());
00294     TEST_EQUAL(boolweight.serialise(), wt->serialise());
00295     delete wt;
00296 
00297     Xapian::TradWeight tradweight_dflt;
00298     Xapian::TradWeight tradweight(1.0);
00299     TEST_EQUAL(tradweight.name(), "Trad");
00300     TEST_EQUAL(tradweight_dflt.serialise(), tradweight.serialise());
00301     wt = Xapian::TradWeight().unserialise(tradweight.serialise());
00302     TEST_EQUAL(tradweight.serialise(), wt->serialise());
00303     delete wt;
00304 
00305     Xapian::TradWeight tradweight2(2.0);
00306     TEST_NOT_EQUAL(tradweight.serialise(), tradweight2.serialise());
00307 
00308     Xapian::BM25Weight bm25weight_dflt;
00309     Xapian::BM25Weight bm25weight(1, 0, 1, 0.5, 0.5);
00310     TEST_EQUAL(bm25weight.name(), "BM25");
00311     TEST_EQUAL(bm25weight_dflt.serialise(), bm25weight.serialise());
00312     wt = Xapian::BM25Weight().unserialise(bm25weight.serialise());
00313     TEST_EQUAL(bm25weight.serialise(), wt->serialise());
00314     delete wt;
00315 
00316     Xapian::BM25Weight bm25weight2(1, 0.5, 1, 0.5, 0.5);
00317     TEST_NOT_EQUAL(bm25weight.serialise(), bm25weight2.serialise());
00318 
00319     return true;
00320 }
00321 
00322 // Regression test.
00323 DEFINE_TESTCASE(nosuchdb1, !backend) {
00324     // This is a "nodb" test because it doesn't test a particular backend.
00325     TEST_EXCEPTION(Xapian::DatabaseOpeningError,
00326                    Xapian::Database db("NOsuChdaTabASe"));
00327     return true;
00328 }
00329 
00330 // Feature tests for value manipulations.
00331 DEFINE_TESTCASE(addvalue1, !backend) {
00332     // Regression test for add_value on an existing value (bug#82).
00333     Xapian::Document doc;
00334     doc.add_value(1, "original");
00335     doc.add_value(1, "replacement");
00336     TEST_EQUAL(doc.get_value(1), "replacement");
00337 
00338     doc.add_value(2, "too");
00339     doc.add_value(3, "free");
00340     doc.add_value(4, "for");
00341 
00342     doc.remove_value(2);
00343     doc.remove_value(4);
00344     TEST_EQUAL(doc.get_value(0), "");
00345     TEST_EQUAL(doc.get_value(1), "replacement");
00346     TEST_EQUAL(doc.get_value(2), "");
00347     TEST_EQUAL(doc.get_value(3), "free");
00348     TEST_EQUAL(doc.get_value(4), "");
00349 
00350     return true;
00351 }
00352 
00353 // tests that the collapsing on termpos optimisation gives correct query length
00354 DEFINE_TESTCASE(poscollapse2, !backend) {
00355     Xapian::Query q(Xapian::Query::OP_OR, Xapian::Query("this", 1, 1), Xapian::Query("this", 1, 1));
00356     TEST_EQUAL(q.get_length(), 2);
00357     return true;
00358 }
00359 
00360 // regression test of querying an uninitialised database: should report an
00361 // error; used to segfault with 1.0.0.
00362 DEFINE_TESTCASE(uninitdb1, !backend) {
00363     Xapian::Database db;
00364     TEST_EXCEPTION(Xapian::InvalidArgumentError,
00365                    Xapian::Enquire enq(db));
00366     return true;
00367 }
00368 
00369 // Test a scaleweight query applied to a match nothing query
00370 DEFINE_TESTCASE(scaleweight3, !backend) {
00371     Xapian::Query matchnothing(Xapian::Query::MatchNothing);
00372     Xapian::Query query(Xapian::Query::OP_SCALE_WEIGHT, matchnothing, 3.0);
00373     TEST_EQUAL(query.get_description(), "Xapian::Query()");
00374     return true;
00375 }
00376 
00377 // Test that scaling by a weight close to 1 is optimised away.
00378 DEFINE_TESTCASE(scaleweight4, !backend) {
00379     // Factor is a double which, when multiplied by its reciprocal, doesn't
00380     // give exactly 1.0
00381     double factor = 179.76931348623157e306;
00382     double nearly1 = factor * (1.0 / factor);
00383 
00384     TEST_NOT_EQUAL(nearly1, 1.0);
00385     Xapian::Query foo("foo");
00386     Xapian::Query foo_nearly1(Xapian::Query::OP_SCALE_WEIGHT, foo, nearly1);
00387     TEST_EQUAL(foo_nearly1.get_description(), "Xapian::Query(foo)");
00388 
00389     return true;
00390 }
00391 
00392 // Regression test - RSet::get_description() gave a malformed answer in 1.0.7.
00393 DEFINE_TESTCASE(rset4, !backend) {
00394     Xapian::RSet rset;
00395     rset.add_document(1);
00396     // In 1.0.7 this gave: RSet(RSet(RSet::Internal(, 1))
00397     TEST_STRINGS_EQUAL(rset.get_description(), "RSet(RSet::Internal(1))");
00398     return true;
00399 }
00400 
00401 // Check that Query(OP_VALUE_GE, 0, "") -> Query::MatchAll.
00402 DEFINE_TESTCASE(opvaluege1, !backend) {
00403     Xapian::Query query(Xapian::Query::OP_VALUE_GE, 0, "");
00404     TEST_STRINGS_EQUAL(query.get_description(), Xapian::Query::MatchAll.get_description());
00405     return true;
00406 }
00407 
00409 DEFINE_TESTCASE(nearsubqueries1, !backend) {
00410     Xapian::Query a_or_b(Xapian::Query::OP_OR,
00411                          Xapian::Query("a"),
00412                          Xapian::Query("b"));
00413     TEST_EXCEPTION(Xapian::UnimplementedError,
00414                    Xapian::Query near(Xapian::Query::OP_NEAR, a_or_b, a_or_b));
00415     return true;
00416 }

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