tests/api_wrdb.cc

Go to the documentation of this file.
00001 /* api_wrdb.cc: tests which need a writable backend
00002  *
00003  * Copyright 1999,2000,2001 BrightStation PLC
00004  * Copyright 2001 Hein Ragas
00005  * Copyright 2002 Ananova Ltd
00006  * Copyright 2002,2003,2004,2005,2006,2007 Olly Betts
00007  * Copyright 2006 Richard Boulton
00008  * Copyright 2007 Lemur Consulting Ltd
00009  *
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
00023  * USA
00024  */
00025 
00026 #include <config.h>
00027 
00028 #include "api_wrdb.h"
00029 
00030 #include <xapian.h>
00031 
00032 #include "backendmanager.h" // For XAPIAN_BIN_PATH.
00033 #include "omtime.h"
00034 #include "testsuite.h"
00035 #include "testutils.h"
00036 #include "utils.h"
00037 #include "unixcmds.h"
00038 
00039 #include "apitest.h"
00040 
00041 #include <algorithm>
00042 #include <cmath>
00043 #include <cstdlib>
00044 #include <list>
00045 #include <map>
00046 #include <string>
00047 
00048 using namespace std;
00049 
00050 // #######################################################################
00051 // # Tests start here
00052 
00053 // test that indexing a term more than once at the same position increases
00054 // the wdf
00055 DEFINE_TESTCASE(adddoc1, writable) {
00056     Xapian::WritableDatabase db = get_writable_database();
00057 
00058     Xapian::Document doc1, doc2, doc3;
00059 
00060     // doc1 should come top, but if term "foo" gets wdf of 1, doc2 will beat it
00061     // doc3 should beat both
00062     // Note: all docs have same length
00063     doc1.set_data(string("tom"));
00064     doc1.add_posting("foo", 1);
00065     doc1.add_posting("foo", 1);
00066     doc1.add_posting("foo", 1);
00067     doc1.add_posting("bar", 3);
00068     doc1.add_posting("bar", 4);
00069     db.add_document(doc1);
00070 
00071     doc2.set_data(string("dick"));
00072     doc2.add_posting("foo", 1);
00073     doc2.add_posting("foo", 2);
00074     doc2.add_posting("bar", 3);
00075     doc2.add_posting("bar", 3);
00076     doc2.add_posting("bar", 3);
00077     db.add_document(doc2);
00078 
00079     doc3.set_data(string("harry"));
00080     doc3.add_posting("foo", 1);
00081     doc3.add_posting("foo", 1);
00082     doc3.add_posting("foo", 2);
00083     doc3.add_posting("foo", 2);
00084     doc3.add_posting("bar", 3);
00085     db.add_document(doc3);
00086 
00087     Xapian::Query query("foo");
00088 
00089     Xapian::Enquire enq(db);
00090     enq.set_query(query);
00091 
00092     Xapian::MSet mset = enq.get_mset(0, 10);
00093 
00094     mset_expect_order(mset, 3, 1, 2);
00095 
00096     return true;
00097 }
00098 
00099 // test that removing a posting and removing a term works
00100 DEFINE_TESTCASE(adddoc2, writable) {
00101     Xapian::WritableDatabase db = get_writable_database();
00102 
00103     Xapian::Document doc1;
00104 
00105     doc1.add_posting("foo", 1);
00106     doc1.add_posting("foo", 1);
00107     doc1.add_posting("foo", 2);
00108     doc1.add_posting("foo", 2);
00109     doc1.add_posting("bar", 3);
00110     doc1.add_posting("gone", 1);
00111     // Quartz had a bug handling a term >= 128 characters longer than the
00112     // preceding term in the sort order - this is "foo" + 130 "X"s
00113     doc1.add_posting("fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 1);
00114     Xapian::docid did;
00115 
00116     Xapian::Document doc2 = db.get_document(did = db.add_document(doc1));
00117     TEST_EQUAL(did, 1);
00118 
00119     Xapian::TermIterator iter1 = doc1.termlist_begin();
00120     Xapian::TermIterator iter2 = doc2.termlist_begin();
00121     TEST(iter1 != doc1.termlist_end());
00122     TEST(iter2 != doc2.termlist_end());
00123     TEST_EQUAL(*iter1, "bar");
00124     TEST_EQUAL(*iter2, *iter1);
00125     TEST_EQUAL(iter1.get_wdf(), 1);
00126     TEST_EQUAL(iter2.get_wdf(), 1);
00127     //TEST_EQUAL(iter1.get_termfreq(), 0);
00128     TEST_EQUAL(iter2.get_termfreq(), 1);
00129 
00130     iter1++;
00131     iter2++;
00132     TEST(iter1 != doc1.termlist_end());
00133     TEST(iter2 != doc2.termlist_end());
00134     TEST_EQUAL(*iter1, "foo");
00135     TEST_EQUAL(*iter2, *iter1);
00136     TEST_EQUAL(iter1.get_wdf(), 4);
00137     TEST_EQUAL(iter2.get_wdf(), 4);
00138     //TEST_EQUAL(iter1.get_termfreq(), 0);
00139     TEST_EQUAL(iter2.get_termfreq(), 1);
00140 
00141     iter1++;
00142     iter2++;
00143     TEST(iter1 != doc1.termlist_end());
00144     TEST(iter2 != doc2.termlist_end());
00145     TEST_EQUAL(*iter1, "fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
00146     TEST_EQUAL(*iter2, *iter1);
00147     TEST_EQUAL(iter1.get_wdf(), 1);
00148     TEST_EQUAL(iter2.get_wdf(), 1);
00149     // assertion fails in debug build! TEST_EQUAL(iter1.get_termfreq(), 0);
00150     TEST_EQUAL(iter2.get_termfreq(), 1);
00151 
00152     iter1++;
00153     iter2++;
00154     TEST(iter1 != doc1.termlist_end());
00155     TEST(iter2 != doc2.termlist_end());
00156     TEST_EQUAL(*iter1, "gone");
00157     TEST_EQUAL(*iter2, *iter1);
00158     TEST_EQUAL(iter1.get_wdf(), 1);
00159     TEST_EQUAL(iter2.get_wdf(), 1);
00160     // assertion fails in debug build! TEST_EQUAL(iter1.get_termfreq(), 0);
00161     TEST_EQUAL(iter2.get_termfreq(), 1);
00162 
00163     iter1++;
00164     iter2++;
00165     TEST(iter1 == doc1.termlist_end());
00166     TEST(iter2 == doc2.termlist_end());
00167 
00168     doc2.remove_posting("foo", 1, 5);
00169     doc2.add_term("bat", 0);
00170     doc2.add_term("bar", 8);
00171     doc2.add_term("bag", 0);
00172     doc2.remove_term("gone");
00173     doc2.remove_term("fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
00174 
00175     // Should have (doc,wdf) pairs: (bag,0)(bar,9)(bat,0)(foo,0)
00176     // positionlists (bag,none)(bar,3)(bat,none)(foo,2)
00177 
00178     iter2 = doc2.termlist_begin();
00179     TEST(iter2 != doc2.termlist_end());
00180     TEST_EQUAL(*iter2, "bag");
00181     //TEST_EQUAL(iter2.get_termfreq(), 0);
00182     iter2++;
00183     TEST(iter2 != doc2.termlist_end());
00184     TEST_EQUAL(*iter2, "bar");
00185     //TEST_EQUAL(iter2.get_termfreq(), 0);
00186     iter2++;
00187     TEST(iter2 != doc2.termlist_end());
00188     TEST_EQUAL(*iter2, "bat");
00189     //TEST_EQUAL(iter2.get_termfreq(), 0);
00190     iter2++;
00191     TEST(iter2 != doc2.termlist_end());
00192     TEST_EQUAL(*iter2, "foo");
00193     //TEST_EQUAL(iter2.get_termfreq(), 0);
00194     iter2++;
00195     TEST(iter2 == doc2.termlist_end());
00196 
00197     doc1 = db.get_document(did = db.add_document(doc2));
00198     TEST_EQUAL(did, 2);
00199 
00200     iter1 = doc1.termlist_begin();
00201     iter2 = doc2.termlist_begin();
00202     TEST(iter1 != doc1.termlist_end());
00203     TEST(iter2 != doc2.termlist_end());
00204     TEST_EQUAL(*iter1, "bag");
00205     TEST_EQUAL(*iter2, *iter1);
00206     TEST_EQUAL(iter1.get_wdf(), 0);
00207     TEST_EQUAL(iter2.get_wdf(), 0);
00208     TEST_EQUAL(iter1.get_termfreq(), 1);
00209     //TEST_EQUAL(iter2.get_termfreq(), 0);
00210     TEST(iter1.positionlist_begin() == iter1.positionlist_end());
00211     TEST(iter2.positionlist_begin() == iter2.positionlist_end());
00212 
00213     iter1++;
00214     iter2++;
00215     TEST(iter1 != doc1.termlist_end());
00216     TEST(iter2 != doc2.termlist_end());
00217     TEST_EQUAL(*iter1, "bar");
00218     TEST_EQUAL(*iter2, *iter1);
00219     TEST_EQUAL(iter1.get_wdf(), 9);
00220     TEST_EQUAL(iter2.get_wdf(), 9);
00221     TEST_EQUAL(iter1.get_termfreq(), 2);
00222     //TEST_EQUAL(iter2.get_termfreq(), 0);
00223 
00224     Xapian::PositionIterator pi1;
00225     pi1 = iter1.positionlist_begin();
00226     Xapian::PositionIterator pi2 = iter2.positionlist_begin();
00227     TEST_EQUAL(*pi1, 3); pi1++;
00228     TEST_EQUAL(*pi2, 3); pi2++;
00229     TEST(pi1 == iter1.positionlist_end());
00230     TEST(pi2 == iter2.positionlist_end());
00231 
00232     iter1++;
00233     iter2++;
00234     TEST(iter1 != doc1.termlist_end());
00235     TEST(iter2 != doc2.termlist_end());
00236     TEST_EQUAL(*iter1, "bat");
00237     TEST_EQUAL(*iter2, *iter1);
00238     TEST_EQUAL(iter1.get_wdf(), 0);
00239     TEST_EQUAL(iter2.get_wdf(), 0);
00240     TEST_EQUAL(iter1.get_termfreq(), 1);
00241     //TEST_EQUAL(iter2.get_termfreq(), 0);
00242     TEST(iter1.positionlist_begin() == iter1.positionlist_end());
00243     TEST(iter2.positionlist_begin() == iter2.positionlist_end());
00244 
00245     iter1++;
00246     iter2++;
00247     TEST(iter1 != doc1.termlist_end());
00248     TEST(iter2 != doc2.termlist_end());
00249     TEST_EQUAL(*iter1, "foo");
00250     TEST_EQUAL(*iter2, *iter1);
00251     TEST_EQUAL(iter1.get_wdf(), 0);
00252     TEST_EQUAL(iter2.get_wdf(), 0);
00253     TEST_EQUAL(iter1.get_termfreq(), 2);
00254     //TEST_EQUAL(iter2.get_termfreq(), 0);
00255 
00256     Xapian::PositionIterator temp1 = iter1.positionlist_begin();
00257     pi1 = temp1;
00258     Xapian::PositionIterator temp2 = iter2.positionlist_begin();
00259     pi2 = temp2;
00260     TEST_EQUAL(*pi1, 2); pi1++;
00261     TEST_EQUAL(*pi2, 2); pi2++;
00262     TEST(pi1 == iter1.positionlist_end());
00263     TEST(pi2 == iter2.positionlist_end());
00264 
00265     iter1++;
00266     iter2++;
00267     TEST(iter1 == doc1.termlist_end());
00268     TEST(iter2 == doc2.termlist_end());
00269 
00270     return true;
00271 }
00272 
00273 // test that adding lots of documents works, and doesn't leak memory
00274 // REGRESSION FIXED:2003-09-07
00275 DEFINE_TESTCASE(adddoc3, writable) {
00276     Xapian::WritableDatabase db = get_writable_database();
00277 
00278     for (Xapian::doccount i = 0; i < 2100; ++i) {
00279         Xapian::Document doc;
00280         for (Xapian::termcount t = 0; t < 100; ++t) {
00281             string term("foo");
00282             term += char(t ^ 70 ^ i);
00283             doc.add_posting(term, t);
00284         }
00285         db.add_document(doc);
00286     }
00287     return true;
00288 }
00289 
00290 // We want to test that a termlist starting with a 48 character long term works
00291 // OK since this value currently requires special handling in flint for
00292 // historical reasons!)  Also test all other term lengths while we're at it.
00293 DEFINE_TESTCASE(adddoc4, writable) {
00294     Xapian::WritableDatabase db = get_writable_database();
00295 
00296     for (Xapian::doccount i = 1; i <= 240; ++i) {
00297         Xapian::Document doc;
00298         string term(i, 'X');
00299         doc.add_term(term);
00300         db.add_document(doc);
00301     }
00302     db.add_document(Xapian::Document());
00303     db.flush();
00304 
00305     for (Xapian::doccount i = 1; i <= 240; ++i) {
00306         Xapian::Document doc = db.get_document(i);
00307         Xapian::TermIterator t = doc.termlist_begin();
00308         TEST(t != doc.termlist_end());
00309         TEST_EQUAL((*t).size(), i);
00310         ++t;
00311         TEST(t == doc.termlist_end());
00312     }
00313 
00314     // And test a document with no terms.
00315     Xapian::Document doc = db.get_document(241);
00316     TEST(doc.termlist_begin() == doc.termlist_end());
00317 
00318     return true;
00319 }
00320 
00321 // Test adding a document, and checking that it got added correctly.
00322 // This testcase used to be adddoc2 in quartztest.
00323 DEFINE_TESTCASE(adddoc5, writable) {
00324     // Inmemory doesn't support get_writable_database_as_database().
00325     SKIP_TEST_FOR_BACKEND("inmemory");
00326 
00327     Xapian::docid did;
00328     Xapian::Document document_in;
00329     document_in.set_data("Foobar rising");
00330     document_in.add_value(7, "Value7");
00331     document_in.add_value(13, "Value13");
00332     document_in.add_posting("foobar", 1);
00333     document_in.add_posting("rising", 2);
00334     document_in.add_posting("foobar", 3);
00335 
00336     Xapian::Document document_in2;
00337     document_in2.set_data("Foobar falling");
00338     document_in2.add_posting("foobar", 1);
00339     document_in2.add_posting("falling", 2);
00340     {
00341         Xapian::WritableDatabase database(get_writable_database());
00342 
00343         TEST_EQUAL(database.get_doccount(), 0);
00344         TEST_EQUAL(database.get_avlength(), 0);
00345 
00346         did = database.add_document(document_in);
00347         TEST_EQUAL(database.get_doccount(), 1);
00348         TEST_EQUAL(database.get_avlength(), 3);
00349 
00350         TEST_EQUAL(database.get_termfreq("foobar"), 1);
00351         TEST_EQUAL(database.get_collection_freq("foobar"), 2);
00352         TEST_EQUAL(database.get_termfreq("rising"), 1);
00353         TEST_EQUAL(database.get_collection_freq("rising"), 1);
00354         TEST_EQUAL(database.get_termfreq("falling"), 0);
00355         TEST_EQUAL(database.get_collection_freq("falling"), 0);
00356 
00357         Xapian::docid did2 = database.add_document(document_in2);
00358         TEST_EQUAL(database.get_doccount(), 2);
00359         TEST_NOT_EQUAL(did, did2);
00360         TEST_EQUAL(database.get_avlength(), 5.0/2.0);
00361 
00362         TEST_EQUAL(database.get_termfreq("foobar"), 2);
00363         TEST_EQUAL(database.get_collection_freq("foobar"), 3);
00364         TEST_EQUAL(database.get_termfreq("rising"), 1);
00365         TEST_EQUAL(database.get_collection_freq("rising"), 1);
00366         TEST_EQUAL(database.get_termfreq("falling"), 1);
00367         TEST_EQUAL(database.get_collection_freq("falling"), 1);
00368 
00369         database.delete_document(did);
00370         TEST_EQUAL(database.get_doccount(), 1);
00371         TEST_EQUAL(database.get_avlength(), 2);
00372 
00373         TEST_EQUAL(database.get_termfreq("foobar"), 1);
00374         TEST_EQUAL(database.get_collection_freq("foobar"), 1);
00375         TEST_EQUAL(database.get_termfreq("rising"), 0);
00376         TEST_EQUAL(database.get_collection_freq("rising"), 0);
00377         TEST_EQUAL(database.get_termfreq("falling"), 1);
00378         TEST_EQUAL(database.get_collection_freq("falling"), 1);
00379 
00380         did = database.add_document(document_in);
00381         TEST_EQUAL(database.get_doccount(), 2);
00382         TEST_EQUAL(database.get_avlength(), 5.0/2.0);
00383 
00384         TEST_EQUAL(database.get_termfreq("foobar"), 2);
00385         TEST_EQUAL(database.get_collection_freq("foobar"), 3);
00386         TEST_EQUAL(database.get_termfreq("rising"), 1);
00387         TEST_EQUAL(database.get_collection_freq("rising"), 1);
00388         TEST_EQUAL(database.get_termfreq("falling"), 1);
00389         TEST_EQUAL(database.get_collection_freq("falling"), 1);
00390     }
00391 
00392     {
00393         Xapian::Database database(get_writable_database_as_database());
00394         Xapian::Document document_out = database.get_document(did);
00395 
00396         TEST_EQUAL(document_in.get_data(), document_out.get_data());
00397 
00398         {
00399             Xapian::ValueIterator i(document_in.values_begin());
00400             Xapian::ValueIterator j(document_out.values_begin());
00401             for (; i != document_in.values_end(); i++, j++) {
00402                 TEST_NOT_EQUAL(j, document_out.values_end());
00403                 TEST_EQUAL(*i, *j);
00404                 TEST_EQUAL(i.get_valueno(), j.get_valueno());
00405             }
00406             TEST_EQUAL(j, document_out.values_end());
00407         }
00408 
00409         {
00410             // Regression test for bug fixed in 1.0.5 - values_begin() didn't
00411             // ensure that values had been read.  However, values_end() did
00412             // (and so did values_count()) so this wasn't generally an issue
00413             // but it shouldn't happen anyway.
00414             Xapian::Document doc_tmp = database.get_document(did);
00415             Xapian::ValueIterator i = document_in.values_begin();
00416             Xapian::ValueIterator j = doc_tmp.values_begin();
00417             TEST_EQUAL(*i, *j);
00418         }
00419 
00420         {
00421             Xapian::TermIterator i(document_in.termlist_begin());
00422             Xapian::TermIterator j(document_out.termlist_begin());
00423             for (; i != document_in.termlist_end(); i++, j++) {
00424                 TEST_NOT_EQUAL(j, document_out.termlist_end());
00425                 TEST_EQUAL(*i, *j);
00426                 TEST_EQUAL(i.get_wdf(), j.get_wdf());
00427                 TEST_EXCEPTION(Xapian::InvalidOperationError,
00428                                (void)i.get_termfreq());
00429                 TEST_NOT_EQUAL(0, j.get_termfreq());
00430                 if (*i == "foobar") {
00431                     // termfreq of foobar is 2
00432                     TEST_EQUAL(2, j.get_termfreq());
00433                 } else {
00434                     // termfreq of rising is 1
00435                     TEST_EQUAL(*i, "rising");
00436                     TEST_EQUAL(1, j.get_termfreq());
00437                 }
00438                 Xapian::PositionIterator k(i.positionlist_begin());
00439                 Xapian::PositionIterator l(j.positionlist_begin());
00440                 for (; k != i.positionlist_end(); k++, l++) {
00441                     TEST_NOT_EQUAL(l, j.positionlist_end());
00442                     TEST_EQUAL(*k, *l);
00443                 }
00444                 TEST_EQUAL(l, j.positionlist_end());
00445             }
00446             TEST_EQUAL(j, document_out.termlist_end());
00447         }
00448     }
00449 
00450     return true;
00451 }
00452 
00453 // Test adding a document, and checking that it got added correctly.
00454 // This testcase used to be adddoc3 in quartztest.
00455 DEFINE_TESTCASE(adddoc6, writable) {
00456     // Inmemory doesn't support get_writable_database_again().
00457     SKIP_TEST_FOR_BACKEND("inmemory");
00458 
00459     Xapian::docid did;
00460     Xapian::Document document_in;
00461     document_in.set_data("Foobar rising");
00462     document_in.add_value(7, "Value7");
00463     document_in.add_value(13, "Value13");
00464     document_in.add_posting("foo", 1);
00465     document_in.add_posting("bar", 2);
00466 
00467     {
00468         Xapian::WritableDatabase database(get_writable_database());
00469 
00470         did = database.add_document(document_in);
00471         TEST_EQUAL(did, 1);
00472         TEST_EQUAL(database.get_doccount(), 1);
00473         TEST_EQUAL(database.get_avlength(), 2);
00474     }
00475 
00476     {
00477         Xapian::WritableDatabase database(get_writable_database_again());
00478 
00479         document_in.remove_term("foo");
00480         document_in.add_posting("baz", 1);
00481 
00482         database.replace_document(1, document_in);
00483 
00484         database.delete_document(1);
00485 
00486         TEST_EQUAL(database.get_doccount(), 0);
00487         TEST_EQUAL(database.get_avlength(), 0);
00488         TEST_EQUAL(database.get_termfreq("foo"), 0);
00489         TEST_EQUAL(database.get_collection_freq("foo"), 0);
00490         TEST_EQUAL(database.get_termfreq("bar"), 0);
00491         TEST_EQUAL(database.get_collection_freq("bar"), 0);
00492         TEST_EQUAL(database.get_termfreq("baz"), 0);
00493         TEST_EQUAL(database.get_collection_freq("baz"), 0);
00494     }
00495 
00496     return true;
00497 }
00498 
00499 // tests that database destructors flush if it isn't done explicitly
00500 DEFINE_TESTCASE(implicitendsession1, writable) {
00501     Xapian::WritableDatabase db = get_writable_database();
00502 
00503     Xapian::Document doc;
00504 
00505     doc.set_data(string("top secret"));
00506     doc.add_posting("cia", 1);
00507     doc.add_posting("nsa", 2);
00508     doc.add_posting("fbi", 3);
00509     db.add_document(doc);
00510 
00511     return true;
00512 }
00513 
00514 // tests that assignment of Xapian::Database and Xapian::WritableDatabase work as expected
00515 DEFINE_TESTCASE(databaseassign1, writable) {
00516     Xapian::WritableDatabase wdb = get_writable_database();
00517     Xapian::Database db = get_database("");
00518     Xapian::Database actually_wdb = wdb;
00519     Xapian::WritableDatabase w1(wdb);
00520     w1 = wdb;
00521     Xapian::Database d1(wdb);
00522     Xapian::Database d2(actually_wdb);
00523     d2 = wdb;
00524     d2 = actually_wdb;
00525     wdb = wdb; // check assign to itself works
00526     db = db; // check assign to itself works
00527     return true;
00528 }
00529 
00530 // tests that deletion and updating of documents works as expected
00531 DEFINE_TESTCASE(deldoc1, writable) {
00532     Xapian::WritableDatabase db = get_writable_database();
00533 
00534     Xapian::Document doc1;
00535 
00536     doc1.add_posting("foo", 1);
00537     doc1.add_posting("foo", 1);
00538     doc1.add_posting("foo", 2);
00539     doc1.add_posting("foo", 2);
00540     doc1.add_posting("bar", 3);
00541     doc1.add_posting("gone", 1);
00542 
00543     Xapian::docid did = db.add_document(doc1);
00544     TEST_EQUAL(did, 1);
00545 
00546     doc1.remove_term("gone");
00547 
00548     did = db.add_document(doc1);
00549     TEST_EQUAL(did, 2);
00550 
00551     doc1.add_term("new", 1);
00552     did = db.add_document(doc1);
00553     TEST_EQUAL(did, 3);
00554 
00555     db.delete_document(1);
00556 
00557     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
00558 
00559     doc1 = db.get_document(2);
00560     doc1.remove_term("foo");
00561     doc1.add_term("fwing");
00562     db.replace_document(2, doc1);
00563 
00564     Xapian::Document doc2 = db.get_document(2);
00565     Xapian::TermIterator tit = doc2.termlist_begin();
00566     TEST_NOT_EQUAL(tit, doc2.termlist_end());
00567     TEST_EQUAL(*tit, "bar");
00568     tit++;
00569     TEST_NOT_EQUAL(tit, doc2.termlist_end());
00570     TEST_EQUAL(*tit, "fwing");
00571     tit++;
00572     TEST_EQUAL(tit, doc2.termlist_end());
00573 
00574     return true;
00575 }
00576 
00577 // tests that deletion and updating of documents works as expected
00578 DEFINE_TESTCASE(deldoc2, writable) {
00579     Xapian::WritableDatabase db = get_writable_database();
00580 
00581     Xapian::Document doc1;
00582 
00583     doc1.add_posting("one", 1);
00584     doc1.add_posting("two", 2);
00585     doc1.add_posting("two", 3);
00586     Xapian::docid did;
00587 
00588     did = db.add_document(doc1);
00589     TEST_EQUAL(did, 1);
00590 
00591     doc1.remove_term("one");
00592     doc1.add_posting("three", 4);
00593 
00594     did = db.add_document(doc1);
00595     TEST_EQUAL(did, 2);
00596 
00597     doc1.add_posting("one", 7);
00598     doc1.remove_term("two");
00599 
00600     did = db.add_document(doc1);
00601     TEST_EQUAL(did, 3);
00602 
00603     db.flush();
00604 
00605     db.reopen();
00606 
00607     db.delete_document(1);
00608     db.delete_document(2);
00609     db.delete_document(3);
00610 
00611     db.flush();
00612 
00613     db.reopen();
00614 
00615     TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
00616     TEST_EQUAL(db.postlist_begin("two"), db.postlist_end("two"));
00617     TEST_EQUAL(db.postlist_begin("three"), db.postlist_end("three"));
00618 
00619     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(1));
00620     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(2));
00621     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(3));
00622     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(4));
00623 
00624     // test positionlist_{begin,end}?
00625 
00626     TEST_EQUAL(db.get_doccount(), 0);
00627     TEST_EQUAL(db.get_avlength(), 0);
00628     TEST_EQUAL(db.get_termfreq("one"), 0);
00629     TEST_EQUAL(db.get_termfreq("two"), 0);
00630     TEST_EQUAL(db.get_termfreq("three"), 0);
00631 
00632     TEST(!db.term_exists("one"));
00633     TEST(!db.term_exists("two"));
00634     TEST(!db.term_exists("three"));
00635 
00636     TEST_EQUAL(db.get_collection_freq("one"), 0);
00637     TEST_EQUAL(db.get_collection_freq("two"), 0);
00638     TEST_EQUAL(db.get_collection_freq("three"), 0);
00639 
00640     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(1));
00641     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(2));
00642     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(3));
00643 
00644     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
00645     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
00646     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
00647 
00648     TEST_EQUAL(db.allterms_begin(), db.allterms_end());
00649 
00650     return true;
00651 }
00652 
00653 // another test of deletion of documents, a cut-down version of deldoc2
00654 DEFINE_TESTCASE(deldoc3, writable) {
00655     Xapian::WritableDatabase db = get_writable_database();
00656 
00657     Xapian::Document doc1;
00658 
00659     doc1.add_posting("one", 1);
00660 
00661     Xapian::docid did = db.add_document(doc1);
00662     TEST_EQUAL(did, 1);
00663 
00664     db.flush();
00665 
00666     db.reopen();
00667 
00668     db.delete_document(1);
00669 
00670     db.flush();
00671 
00672     db.reopen();
00673 
00674     TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
00675 
00676     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(1));
00677     (void)&db; // gcc 2.95 seems to miscompile without this!!! - Olly
00678     TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(2));
00679 
00680     // test positionlist_{begin,end}?
00681 
00682     TEST_EQUAL(db.get_doccount(), 0);
00683     TEST_EQUAL(db.get_avlength(), 0);
00684     TEST_EQUAL(db.get_termfreq("one"), 0);
00685 
00686     TEST(!db.term_exists("one"));
00687 
00688     TEST_EQUAL(db.get_collection_freq("one"), 0);
00689 
00690     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(1));
00691     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(2));
00692 
00693     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
00694     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
00695 
00696     TEST_EQUAL(db.allterms_begin(), db.allterms_end());
00697 
00698     return true;
00699 }
00700 
00701 // tests that deletion and updating of (lots of) documents works as expected
00702 DEFINE_TESTCASE(deldoc4, writable) {
00703     Xapian::WritableDatabase db = get_writable_database();
00704 
00705     Xapian::Document doc1;
00706 
00707     doc1.add_posting("one", 1);
00708     doc1.add_posting("two", 2);
00709     doc1.add_posting("two", 3);
00710 
00711     Xapian::Document doc2 = doc1;
00712     doc2.remove_term("one");
00713     doc2.add_posting("three", 4);
00714 
00715     Xapian::Document doc3 = doc2;
00716     doc3.add_posting("one", 7);
00717     doc3.remove_term("two");
00718 
00719     const Xapian::docid maxdoc = 1000 * 3;
00720     Xapian::docid did;
00721     for (Xapian::docid i = 0; i < maxdoc / 3; ++i) {
00722         did = db.add_document(doc1);
00723         TEST_EQUAL(did, i * 3 + 1);
00724         did = db.add_document(doc2);
00725         TEST_EQUAL(did, i * 3 + 2);
00726         did = db.add_document(doc3);
00727         TEST_EQUAL(did, i * 3 + 3);
00728 
00729         bool is_power_of_two = ((i & (i - 1)) == 0);
00730         if (is_power_of_two) {
00731             db.flush();
00732             db.reopen();
00733         }
00734     }
00735     db.flush();
00736     db.reopen();
00737 
00738     /* delete the documents in a peculiar order */
00739     for (Xapian::docid i = 0; i < maxdoc / 3; ++i) {
00740         db.delete_document(maxdoc - i);
00741         db.delete_document(maxdoc / 3 + i + 1);
00742         db.delete_document(i + 1);
00743     }
00744 
00745     db.flush();
00746 
00747     db.reopen();
00748 
00749     TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
00750     TEST_EQUAL(db.postlist_begin("two"), db.postlist_end("two"));
00751     TEST_EQUAL(db.postlist_begin("three"), db.postlist_end("three"));
00752 
00753     for (Xapian::docid i = 1; i <= maxdoc; ++i) {
00754         // TEST_EXCEPTION writes to tout each time if the test is run
00755         // in verbose mode and some string stream implementations get
00756         // very inefficient with large strings, so clear tout on each pass of
00757         // the loop to speed up the test since the older information isn't
00758         // interesting anyway.
00759         tout.str("");
00760         TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(i));
00761         TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(i));
00762         TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(i));
00763     }
00764 
00765     // test positionlist_{begin,end}?
00766 
00767     TEST_EQUAL(db.get_doccount(), 0);
00768     TEST_EQUAL(db.get_avlength(), 0);
00769     TEST_EQUAL(db.get_termfreq("one"), 0);
00770     TEST_EQUAL(db.get_termfreq("two"), 0);
00771     TEST_EQUAL(db.get_termfreq("three"), 0);
00772 
00773     TEST(!db.term_exists("one"));
00774     TEST(!db.term_exists("two"));
00775     TEST(!db.term_exists("three"));
00776 
00777     TEST_EQUAL(db.get_collection_freq("one"), 0);
00778     TEST_EQUAL(db.get_collection_freq("two"), 0);
00779     TEST_EQUAL(db.get_collection_freq("three"), 0);
00780 
00781     TEST_EQUAL(db.allterms_begin(), db.allterms_end());
00782 
00783     return true;
00784 }
00785 
00786 // Test deleting a document which was added in the same batch.
00787 DEFINE_TESTCASE(deldoc5, writable) {
00788     Xapian::WritableDatabase db = get_writable_database();
00789 
00790     Xapian::Document doc1;
00791 
00792     doc1.add_posting("foo", 1);
00793     doc1.add_posting("bar", 2);
00794     doc1.add_posting("aardvark", 3);
00795 
00796     Xapian::docid did = db.add_document(doc1);
00797     TEST_EQUAL(did, 1);
00798 
00799     doc1.remove_term("bar");
00800     doc1.add_term("hello");
00801 
00802     did = db.add_document(doc1);
00803     TEST_EQUAL(did, 2);
00804 
00805     doc1.add_term("world", 1);
00806     did = db.add_document(doc1);
00807     TEST_EQUAL(did, 3);
00808 
00809     db.delete_document(2);
00810 
00811     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
00812 
00813     db.flush();
00814 
00815     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
00816 
00817     TEST_EQUAL(db.get_termfreq("foo"), 2);
00818     TEST_EQUAL(db.get_termfreq("aardvark"), 2);
00819     TEST_EQUAL(db.get_termfreq("hello"), 1);
00820 
00821     Xapian::PostingIterator p = db.postlist_begin("foo");
00822     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
00823     TEST_EQUAL(*p, 1);
00824     ++p;
00825     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
00826     TEST_EQUAL(*p, 3);
00827     ++p;
00828     TEST_EQUAL(p, db.postlist_end("foo"));
00829 
00830     return true;
00831 }
00832 
00833 // Regression test for bug in quartz and flint, fixed in 1.0.2.
00834 DEFINE_TESTCASE(deldoc6, writable) {
00835     Xapian::WritableDatabase db = get_writable_database();
00836 
00837     Xapian::Document doc1;
00838 
00839     doc1.add_posting("foo", 1);
00840     doc1.add_posting("bar", 2);
00841     doc1.add_posting("aardvark", 3);
00842 
00843     Xapian::docid did = db.add_document(doc1);
00844     TEST_EQUAL(did, 1);
00845 
00846     doc1.remove_term("bar");
00847     doc1.add_term("hello");
00848 
00849     did = db.add_document(doc1);
00850     TEST_EQUAL(did, 2);
00851 
00852     db.flush();
00853 
00854     db.delete_document(2);
00855     TEST_EXCEPTION(Xapian::DocNotFoundError, db.delete_document(3));
00856 
00857     db.flush();
00858 
00859     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
00860 
00861     return true;
00862 }
00863 
00864 DEFINE_TESTCASE(replacedoc1, writable) {
00865     Xapian::WritableDatabase db = get_writable_database();
00866 
00867     Xapian::Document doc1;
00868 
00869     doc1.add_posting("foo", 1);
00870     doc1.add_posting("foo", 2);
00871     doc1.add_posting("gone",3);
00872     doc1.add_posting("bar", 4);
00873     doc1.add_posting("foo", 5);
00874     Xapian::docid did;
00875 
00876     did = db.add_document(doc1);
00877     TEST_EQUAL(did, 1);
00878 
00879     Xapian::Document doc2;
00880 
00881     doc2.add_posting("foo", 1);
00882     doc2.add_posting("pipco", 2);
00883     doc2.add_posting("bar", 4);
00884     doc2.add_posting("foo", 5);
00885 
00886     db.replace_document(did, doc2);
00887 
00888     Xapian::Document doc3 = db.get_document(did);
00889     Xapian::TermIterator tIter = doc3.termlist_begin();
00890     TEST_EQUAL(*tIter, "bar");
00891     Xapian::PositionIterator pIter = tIter.positionlist_begin();
00892     TEST_EQUAL(*pIter, 4);
00893     ++tIter;
00894     TEST_EQUAL(*tIter, "foo");
00895     Xapian::PositionIterator qIter = tIter.positionlist_begin();
00896     TEST_EQUAL(*qIter, 1);
00897     ++qIter;
00898     TEST_EQUAL(*qIter, 5);
00899     ++tIter;
00900     TEST_EQUAL(*tIter, "pipco");
00901     Xapian::PositionIterator rIter = tIter.positionlist_begin();
00902     TEST_EQUAL(*rIter, 2);
00903     ++tIter;
00904     TEST_EQUAL(tIter, doc3.termlist_end());
00905     return true;
00906 }
00907 
00908 // Test of new feature: WritableDatabase::replace_document accepts a docid
00909 // which doesn't yet exist as of Xapian 0.8.2.
00910 DEFINE_TESTCASE(replacedoc2, writable) {
00911     Xapian::WritableDatabase db = get_writable_database();
00912 
00913     Xapian::Document doc1;
00914 
00915     doc1.add_posting("foo", 1);
00916     doc1.add_posting("foo", 2);
00917     doc1.add_posting("gone",3);
00918     doc1.add_posting("bar", 4);
00919     doc1.add_posting("foo", 5);
00920     Xapian::docid did = 31770;
00921 
00922     db.replace_document(did, doc1);
00923 
00924     // Regression tests for bug in the InMemory backend - fixed in 1.0.2.
00925     TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
00926     Xapian::PostingIterator postit = db.postlist_begin("");
00927     TEST(postit != db.postlist_end(""));
00928     TEST_EQUAL(*postit, 31770);
00929 
00930     Xapian::Document doc2;
00931 
00932     doc2.add_posting("foo", 1);
00933     doc2.add_posting("pipco", 2);
00934     doc2.add_posting("bar", 4);
00935     doc2.add_posting("foo", 5);
00936 
00937     db.replace_document(did, doc2);
00938     TEST_EQUAL(db.get_doccount(), 1);
00939 
00940     Xapian::Document doc3 = db.get_document(did);
00941     Xapian::TermIterator tIter = doc3.termlist_begin();
00942     TEST_EQUAL(*tIter, "bar");
00943     Xapian::PositionIterator pIter = tIter.positionlist_begin();
00944     TEST_EQUAL(*pIter, 4);
00945     ++tIter;
00946     TEST_EQUAL(*tIter, "foo");
00947     Xapian::PositionIterator qIter = tIter.positionlist_begin();
00948     TEST_EQUAL(*qIter, 1);
00949     ++qIter;
00950     TEST_EQUAL(*qIter, 5);
00951     ++tIter;
00952     TEST_EQUAL(*tIter, "pipco");
00953     Xapian::PositionIterator rIter = tIter.positionlist_begin();
00954     TEST_EQUAL(*rIter, 2);
00955     ++tIter;
00956     TEST_EQUAL(tIter, doc3.termlist_end());
00957 
00958     did = db.add_document(doc1);
00959     TEST_EQUAL(did, 31771);
00960     TEST_EQUAL(db.get_doccount(), 2);
00961 
00962     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.replace_document(0, doc2));
00963 
00964     return true;
00965 }
00966 
00967 // Test replacing a document which was added in the same batch.
00968 DEFINE_TESTCASE(replacedoc3, writable) {
00969     Xapian::WritableDatabase db = get_writable_database();
00970 
00971     Xapian::Document doc1;
00972 
00973     doc1.add_posting("foo", 1);
00974     doc1.add_posting("bar", 2);
00975     doc1.add_posting("aardvark", 3);
00976 
00977     Xapian::docid did = db.add_document(doc1);
00978     TEST_EQUAL(did, 1);
00979 
00980     doc1.remove_term("bar");
00981     doc1.add_term("hello");
00982 
00983     did = db.add_document(doc1);
00984     TEST_EQUAL(did, 2);
00985 
00986     doc1.add_term("world", 1);
00987     did = db.add_document(doc1);
00988     TEST_EQUAL(did, 3);
00989 
00990     Xapian::Document doc2;
00991     doc2.add_term("world");
00992     db.replace_document(2, doc2);
00993 
00994     db.flush();
00995 
00996     // Check that the document exists (no DocNotFoundError).
00997     doc2 = db.get_document(2);
00998 
00999     TEST_EQUAL(db.get_termfreq("foo"), 2);
01000     TEST_EQUAL(db.get_termfreq("aardvark"), 2);
01001     TEST_EQUAL(db.get_termfreq("hello"), 1);
01002     TEST_EQUAL(db.get_termfreq("world"), 2);
01003 
01004     TEST_EQUAL(db.get_doclength(1), 3);
01005     TEST_EQUAL(db.get_doclength(2), 1);
01006     TEST_EQUAL(db.get_doclength(3), 4);
01007 
01008     Xapian::PostingIterator p = db.postlist_begin("foo");
01009     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
01010     TEST_EQUAL(*p, 1);
01011     TEST_EQUAL(p.get_doclength(), 3);
01012     ++p;
01013     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
01014     TEST_EQUAL(*p, 3);
01015     TEST_EQUAL(p.get_doclength(), 4);
01016     ++p;
01017     TEST_EQUAL(p, db.postlist_end("foo"));
01018 
01019     p = db.postlist_begin("world");
01020     TEST_NOT_EQUAL(p, db.postlist_end("world"));
01021     TEST_EQUAL(*p, 2);
01022     TEST_EQUAL(p.get_doclength(), 1);
01023     ++p;
01024     TEST_NOT_EQUAL(p, db.postlist_end("world"));
01025     TEST_EQUAL(*p, 3);
01026     TEST_EQUAL(p.get_doclength(), 4);
01027     ++p;
01028     TEST_EQUAL(p, db.postlist_end("world"));
01029 
01030     return true;
01031 }
01032 
01033 // Test replacing a document which was deleted in the same batch.
01034 DEFINE_TESTCASE(replacedoc4, writable) {
01035     Xapian::WritableDatabase db = get_writable_database();
01036 
01037     Xapian::Document doc1;
01038 
01039     doc1.add_posting("foo", 1);
01040     doc1.add_posting("bar", 2);
01041     doc1.add_posting("aardvark", 3);
01042 
01043     Xapian::docid did = db.add_document(doc1);
01044     TEST_EQUAL(did, 1);
01045 
01046     doc1.remove_term("bar");
01047     doc1.add_term("hello");
01048 
01049     did = db.add_document(doc1);
01050     TEST_EQUAL(did, 2);
01051 
01052     doc1.add_term("world", 1);
01053     did = db.add_document(doc1);
01054     TEST_EQUAL(did, 3);
01055 
01056     db.delete_document(2);
01057 
01058     Xapian::Document doc2;
01059     doc2.add_term("world");
01060     db.replace_document(2, doc2);
01061 
01062     db.flush();
01063 
01064     // Check that the document exists (no DocNotFoundError).
01065     doc2 = db.get_document(2);
01066 
01067     TEST_EQUAL(db.get_termfreq("foo"), 2);
01068     TEST_EQUAL(db.get_termfreq("aardvark"), 2);
01069     TEST_EQUAL(db.get_termfreq("hello"), 1);
01070     TEST_EQUAL(db.get_termfreq("world"), 2);
01071 
01072     Xapian::PostingIterator p = db.postlist_begin("foo");
01073     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
01074     TEST_EQUAL(*p, 1);
01075     ++p;
01076     TEST_NOT_EQUAL(p, db.postlist_end("foo"));
01077     TEST_EQUAL(*p, 3);
01078     ++p;
01079     TEST_EQUAL(p, db.postlist_end("foo"));
01080 
01081     p = db.postlist_begin("world");
01082     TEST_NOT_EQUAL(p, db.postlist_end("world"));
01083     TEST_EQUAL(*p, 2);
01084     ++p;
01085     TEST_NOT_EQUAL(p, db.postlist_end("world"));
01086     TEST_EQUAL(*p, 3);
01087     ++p;
01088     TEST_EQUAL(p, db.postlist_end("world"));
01089 
01090     return true;
01091 }
01092 
01093 // Test replacing a document with itself without modifying postings.
01094 // Regression test for bug in 0.9.9 and earlier - there flint and quartz
01095 // lose all positional information for the document when you do this.
01096 DEFINE_TESTCASE(replacedoc5, writable) {
01097     Xapian::WritableDatabase db = get_writable_database();
01098 
01099     Xapian::Document doc1;
01100     doc1.add_posting("hello", 1);
01101     doc1.add_posting("world", 2);
01102 
01103     Xapian::docid did = db.add_document(doc1);
01104     TEST_EQUAL(did, 1);
01105     db.flush();
01106 
01107     Xapian::Document doc2 = db.get_document(1);
01108     TEST(db.has_positions());
01109     TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
01110     TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
01111     db.replace_document(1, doc2);
01112     db.flush();
01113 
01114     TEST(db.has_positions());
01115     TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
01116     TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
01117 
01118     return true;
01119 }
01120 
01121 // Test replacing a document while adding values, without changing anything
01122 // else.  Regression test for a bug introduced while implementing lazy update,
01123 // and also covers a few other code paths.
01124 DEFINE_TESTCASE(replacedoc6, writable) {
01125     Xapian::WritableDatabase db = get_writable_database();
01126 
01127     Xapian::Document doc;
01128     Xapian::docid did = db.add_document(doc);
01129     TEST_EQUAL(did, 1);
01130     db.flush();
01131 
01132     // Add document
01133     doc = db.get_document(1);
01134     TEST_EQUAL(doc.get_value(1), "");
01135     TEST_EQUAL(doc.get_value(2), "");
01136     doc.add_value(1, "banana1");
01137     db.replace_document(1, doc);
01138 
01139     doc = db.get_document(1);
01140     TEST_EQUAL(doc.get_value(1), "banana1");
01141     TEST_EQUAL(doc.get_value(2), "");
01142     db.flush();
01143 
01144     doc = db.get_document(1);
01145     TEST_EQUAL(doc.get_value(1), "banana1");
01146     TEST_EQUAL(doc.get_value(2), "");
01147     doc.add_value(2, "banana2");
01148     db.replace_document(1, doc);
01149 
01150     TEST_EQUAL(doc.get_value(1), "banana1");
01151     TEST_EQUAL(doc.get_value(2), "banana2");
01152     db.flush();
01153 
01154     doc = db.get_document(1);
01155     TEST_EQUAL(doc.get_value(1), "banana1");
01156     TEST_EQUAL(doc.get_value(2), "banana2");
01157 
01158     return true;
01159 }
01160 
01161 // Test of new feature: WritableDatabase::replace_document and delete_document
01162 // can take a unique termname instead of a document id as of Xapian 0.8.2.
01163 DEFINE_TESTCASE(uniqueterm1, writable) {
01164     Xapian::WritableDatabase db = get_writable_database();
01165 
01166     for (int n = 1; n <= 20; ++n) {
01167         Xapian::Document doc;
01168         string uterm = "U" + om_tostring(n % 16);
01169         doc.add_term(uterm);
01170         doc.add_term(om_tostring(n));
01171         doc.add_term(om_tostring(n ^ 9));
01172         doc.add_term("all");
01173         doc.set_data("pass1");
01174         db.add_document(doc);
01175     }
01176 
01177     TEST_EQUAL(db.get_doccount(), 20);
01178 
01179     static const Xapian::doccount sizes[20] = {
01180         19, 17, 16, 15,
01181         15, 15, 15, 15,
01182         15, 15, 15, 15,
01183         15, 15, 15, 15,
01184         15, 15, 15, 15
01185     };
01186     for (int n = 1; n <= 20; ++n) {
01187         string uterm = "U" + om_tostring(n % 16);
01188         if (uterm == "U2") {
01189             db.delete_document(uterm);
01190         } else {
01191             Xapian::Document doc;
01192             doc.add_term(uterm);
01193             doc.add_term(om_tostring(n));
01194             doc.add_term(om_tostring(n ^ 9));
01195             doc.add_term("all");
01196             doc.set_data("pass2");
01197             db.replace_document(uterm, doc);
01198         }
01199         TEST_EQUAL(db.get_doccount(), sizes[n - 1]);
01200     }
01201 
01202     string uterm = "U571";
01203     Xapian::Document doc;
01204     doc.add_term(uterm);
01205     doc.set_data("pass3");
01206     db.replace_document(uterm, doc);
01207 
01208     TEST_EQUAL(db.get_doccount(), 16);
01209 
01210     db.delete_document("U2");
01211 
01212     TEST_EQUAL(db.get_doccount(), 16);
01213 
01214     return true;
01215 }
01216 
01217 // tests all document postlists
01218 DEFINE_TESTCASE(allpostlist2, writable) {
01219     Xapian::WritableDatabase db(get_writable_database("apitest_manydocs"));
01220     Xapian::PostingIterator i = db.postlist_begin("");
01221     unsigned int j = 1;
01222     while (i != db.postlist_end("")) {
01223         TEST_EQUAL(*i, j);
01224         i++;
01225         j++;
01226     }
01227     TEST_EQUAL(j, 513);
01228 
01229     db.delete_document(1);
01230     db.delete_document(50);
01231     db.delete_document(512);
01232 
01233     i = db.postlist_begin("");
01234     j = 2;
01235     while (i != db.postlist_end("")) {
01236         TEST_EQUAL(*i, j);
01237         i++;
01238         j++;
01239         if (j == 50) j++;
01240     }
01241     TEST_EQUAL(j, 512);
01242 
01243     i = db.postlist_begin("");
01244     j = 2;
01245     while (i != db.postlist_end("")) {
01246         TEST_EQUAL(*i, j);
01247         i++;
01248         j++;
01249         if (j == 40) {
01250             j += 10;
01251             i.skip_to(j);
01252             j++;
01253         }
01254     }
01255     TEST_EQUAL(j, 512);
01256 
01257     return true;
01258 }
01259 
01260 static void test_emptyterm2_helper(Xapian::WritableDatabase & db)
01261 {
01262     // Don't bother with postlist_begin() because allpostlist tests cover that.
01263     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
01264     TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
01265     TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
01266     TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
01267 }
01268 
01269 // tests results of passing an empty term to various methods
01270 // equivalent of emptyterm1 for a writable database
01271 DEFINE_TESTCASE(emptyterm2, writable) {
01272     {
01273         Xapian::WritableDatabase db(get_writable_database("apitest_manydocs"));
01274         TEST_EQUAL(db.get_doccount(), 512);
01275         test_emptyterm2_helper(db);
01276         db.delete_document(1);
01277         TEST_EQUAL(db.get_doccount(), 511);
01278         test_emptyterm2_helper(db);
01279         db.delete_document(50);
01280         TEST_EQUAL(db.get_doccount(), 510);
01281         test_emptyterm2_helper(db);
01282         db.delete_document(512);
01283         TEST_EQUAL(db.get_doccount(), 509);
01284         test_emptyterm2_helper(db);
01285     }
01286 
01287     {
01288         Xapian::WritableDatabase db(get_writable_database("apitest_onedoc"));
01289         TEST_EQUAL(db.get_doccount(), 1);
01290         test_emptyterm2_helper(db);
01291         db.delete_document(1);
01292         TEST_EQUAL(db.get_doccount(), 0);
01293         test_emptyterm2_helper(db);
01294     }
01295 
01296     {
01297         Xapian::WritableDatabase db(get_writable_database());
01298         TEST_EQUAL(db.get_doccount(), 0);
01299         test_emptyterm2_helper(db);
01300     }
01301 
01302     return true;
01303 }
01304 
01305 // Check that PHRASE/NEAR becomes AND if there's no positional info in the
01306 // database.
01307 DEFINE_TESTCASE(phraseorneartoand1, writable) {
01308     Xapian::WritableDatabase db = get_writable_database();
01309 
01310     for (int n = 1; n <= 20; ++n) {
01311         Xapian::Document doc;
01312         doc.add_term(om_tostring(n));
01313         doc.add_term(om_tostring(n ^ 9));
01314         doc.add_term("all");
01315         doc.set_data("pass1");
01316         db.add_document(doc);
01317     }
01318     db.flush();
01319 
01320     Xapian::Enquire enquire(db);
01321     Xapian::MSet mymset;
01322 
01323     const char * q1[] = { "all", "1" };
01324     enquire.set_query(Xapian::Query(Xapian::Query::OP_PHRASE, q1, q1 + 2));
01325     mymset = enquire.get_mset(0, 10);
01326     TEST_EQUAL(2, mymset.size());
01327 
01328     enquire.set_query(Xapian::Query(Xapian::Query::OP_NEAR, q1, q1 + 2));
01329     mymset = enquire.get_mset(0, 10);
01330     TEST_EQUAL(2, mymset.size());
01331 
01332     const char * q2[] = { "1", "2" };
01333     enquire.set_query(Xapian::Query(Xapian::Query::OP_PHRASE, q2, q2 + 2));
01334     mymset = enquire.get_mset(0, 10);
01335     TEST_EQUAL(0, mymset.size());
01336 
01337     enquire.set_query(Xapian::Query(Xapian::Query::OP_NEAR, q2, q2 + 2));
01338     mymset = enquire.get_mset(0, 10);
01339     TEST_EQUAL(0, mymset.size());
01340 
01341     return true;
01342 }
01343 
01344 // Check that a large number of position list entries for a particular term
01345 // works - regression test for flint.
01346 DEFINE_TESTCASE(longpositionlist1, writable) {
01347     Xapian::WritableDatabase db = get_writable_database();
01348 
01349     Xapian::Document doc;
01350     Xapian::termpos n;
01351     for (n = 1; n <= 2000; ++n) {
01352         doc.add_posting("fork", n * 3);
01353         doc.add_posting("knife", n * unsigned(log(double(n + 2))));
01354         doc.add_posting("spoon", n * n);
01355     }
01356     doc.set_data("cutlery");
01357     Xapian::docid did = db.add_document(doc);
01358     db.flush();
01359 
01360     doc = db.get_document(did);
01361 
01362     Xapian::TermIterator t, tend;
01363     Xapian::PositionIterator p, pend;
01364 
01365     t = doc.termlist_begin();
01366     tend = doc.termlist_end();
01367 
01368     TEST(t != tend);
01369     TEST_EQUAL(*t, "fork");
01370     p = t.positionlist_begin();
01371     pend = t.positionlist_end();
01372     for (n = 1; n <= 2000; ++n) {
01373         TEST(p != pend);
01374         TEST_EQUAL(*p, n * 3);
01375         ++p;
01376     }
01377     TEST(p == pend);
01378 
01379     ++t;
01380     TEST(t != tend);
01381     TEST_EQUAL(*t, "knife");
01382     p = t.positionlist_begin();
01383     pend = t.positionlist_end();
01384     for (n = 1; n <= 2000; ++n) {
01385         TEST(p != pend);
01386         TEST_EQUAL(*p, n * unsigned(log(double(n + 2))));
01387         ++p;
01388     }
01389     TEST(p == pend);
01390 
01391     ++t;
01392     TEST(t != tend);
01393     TEST_EQUAL(*t, "spoon");
01394     p = t.positionlist_begin();
01395     pend = t.positionlist_end();
01396     for (n = 1; n <= 2000; ++n) {
01397         TEST(p != pend);
01398         TEST_EQUAL(*p, n * n);
01399         ++p;
01400     }
01401     TEST(p == pend);
01402 
01403     ++t;
01404     TEST(t == tend);
01405 
01406     return true;
01407 }
01408 
01409 // Regression test for bug#110: Inconsistent sort order between pages with
01410 // set_sort_by_value_then_relevance.
01411 bool test_consistency2()
01412 {
01413     Xapian::WritableDatabase db = get_writable_database();
01414     char buf[2] = "X";
01415     int i = 0;
01416 
01417     // Add 5 documents indexed by "test" with wdf 1.
01418     for (i = 0; i < 5; ++i) {
01419         Xapian::Document doc;
01420         *buf = '0' + i;
01421         doc.add_value(0, buf);
01422         doc.add_term("test");
01423         db.add_document(doc);
01424     }
01425 
01426     // Add 5 documents indexed by "test" with wdf 2.
01427     for (i = 0; i < 5; ++i) {
01428         Xapian::Document doc;
01429         *buf = '0' + i;
01430         doc.add_value(0, buf);
01431         doc.add_term("test", 2);
01432         db.add_document(doc);
01433     }
01434 
01435     db.flush();
01436 
01437     Xapian::Enquire enq(db);
01438     enq.set_query(Xapian::Query("test"));
01439 
01440     enq.set_sort_by_value_then_relevance(0, true);
01441 
01442     // 10 results, unpaged.
01443     Xapian::MSet mset1 = enq.get_mset(0, 10);
01444     TEST_EQUAL(mset1.size(), 10);
01445 
01446     // 10 results, split.
01447     Xapian::MSet mset2a = enq.get_mset(0, 1);
01448     TEST_EQUAL(mset2a.size(), 1);
01449     Xapian::MSet mset2b = enq.get_mset(1, 1);
01450     TEST_EQUAL(mset2b.size(), 1);
01451     Xapian::MSet mset2c = enq.get_mset(2, 8);
01452     TEST_EQUAL(mset2c.size(), 8);
01453 
01454     TEST_EQUAL(*mset1[0], *mset2a[0]);
01455     TEST_EQUAL(*mset1[1], *mset2b[0]);
01456     for (i = 0; i < 8; ++i) {
01457         TEST_EQUAL(*mset1[i + 2], *mset2c[i]);
01458     }
01459 
01460     return true;
01461 }
01462 
01463 DEFINE_TESTCASE(crashrecovery1, writable) {
01464     const string & dbtype = get_dbtype();
01465     string path, base_ext;
01466     if (dbtype == "flint") {
01467         path = ".flint/dbw";
01468         base_ext = ".baseB";
01469     } else if (dbtype == "quartz") {
01470         path = ".quartz/dbw";
01471         base_ext = "_baseB";
01472     } else {
01473         SKIP_TEST("Test only supported for flint and quartz backends");
01474     }
01475 
01476     Xapian::Document doc;
01477     {
01478         Xapian::WritableDatabase db = get_writable_database();
01479         Xapian::Database dbr(get_writable_database_as_database());
01480         TEST_EQUAL(dbr.get_doccount(), 0);
01481 
01482         // Xapian::Database has full set of baseA, no baseB
01483 
01484         db.add_document(doc);
01485         db.flush();
01486         dbr.reopen();
01487         TEST_EQUAL(dbr.get_doccount(), 1);
01488 
01489         // Xapian::Database has full set of baseB, old baseA
01490 
01491         db.add_document(doc);
01492         db.flush();
01493         dbr.reopen();
01494         TEST_EQUAL(dbr.get_doccount(), 2);
01495 
01496         // Xapian::Database has full set of baseA, old baseB
01497 
01498         // Simulate a transaction starting, some of the baseB getting removed,
01499         // but then the transaction fails.
01500         unlink(path + "/record" + base_ext);
01501         unlink(path + "/termlist" + base_ext);
01502 
01503         dbr.reopen();
01504         TEST_EQUAL(dbr.get_doccount(), 2);
01505     }
01506 
01507     Xapian::WritableDatabase db(path, Xapian::DB_OPEN);
01508     // Xapian::Database has full set of baseA, some old baseB
01509     Xapian::Database dbr = Xapian::Database(path);
01510 
01511     db.add_document(doc);
01512     db.flush();
01513     dbr.reopen();
01514     TEST_EQUAL(dbr.get_doccount(), 3);
01515 
01516     // Xapian::Database has full set of baseB, old baseA
01517 
01518     db.add_document(doc);
01519     db.flush();
01520     dbr.reopen();
01521     TEST_EQUAL(dbr.get_doccount(), 4);
01522 
01523     return true;
01524 }
01525 
01526 // Check that DatabaseError is thrown if the docid counter would wrap.
01527 // Regression test for bug#152.
01528 DEFINE_TESTCASE(nomoredocids1, writable) {
01529     // The InMemory backend uses a vector for the documents, so trying to add
01530     // document "-1" will fail because we can't allocate enough memory!
01531     SKIP_TEST_FOR_BACKEND("inmemory");
01532 
01533     Xapian::WritableDatabase db = get_writable_database();
01534     Xapian::Document doc;
01535     doc.set_data("prose");
01536     doc.add_term("word");
01537 
01538     db.replace_document(Xapian::docid(-1), doc);
01539 
01540     TEST_EXCEPTION(Xapian::DatabaseError, db.add_document(doc));
01541 
01542     return true;
01543 }
01544 
01545 // Test synonym iterators.
01546 DEFINE_TESTCASE(synonymitor1, writable) {
01547     SKIP_TEST_UNLESS_BACKEND("flint");
01548 
01549     Xapian::WritableDatabase db = get_writable_database();
01550 
01551     // Test iterators for terms which aren't there.
01552     TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
01553 
01554     // Test iterating the synonym keys when there aren't any.
01555     TEST(db.synonym_keys_begin() == db.synonym_keys_end());
01556 
01557     db.add_synonym("hello", "howdy");
01558     db.add_synonym("hello", "hi");
01559     db.add_synonym("goodbye", "bye");
01560     db.add_synonym("goodbye", "farewell");
01561 
01562     Xapian::TermIterator t;
01563     string s;
01564 
01565     // Try these tests twice - once before flushing and once after.
01566     for (int times = 1; times <= 2; ++times) {
01567         // Test iterators for terms which aren't there.
01568         TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
01569         TEST(db.synonyms_begin("ghi") == db.synonyms_end("ghi"));
01570         TEST(db.synonyms_begin("zzzzz") == db.synonyms_end("zzzzz"));
01571 
01572         s = "|";
01573         t = db.synonyms_begin("hello");
01574         while (t != db.synonyms_end("hello")) {
01575             s += *t++;
01576             s += '|';
01577         }
01578         TEST_STRINGS_EQUAL(s, "|hi|howdy|");
01579 
01580         s = "|";
01581         t = db.synonyms_begin("goodbye");
01582         while (t != db.synonyms_end("goodbye")) {
01583             s += *t++;
01584             s += '|';
01585         }
01586         TEST_STRINGS_EQUAL(s, "|bye|farewell|");
01587 
01588         s = "|";
01589         t = db.synonym_keys_begin();
01590         while (t != db.synonym_keys_end()) {
01591             s += *t++;
01592             s += '|';
01593         }
01594         TEST_STRINGS_EQUAL(s, "|goodbye|hello|");
01595 
01596         db.flush();
01597     }
01598 
01599     // Delete a synonym for "hello" and all synonyms for "goodbye".
01600     db.remove_synonym("hello", "hi");
01601     db.clear_synonyms("goodbye");
01602 
01603     // Try these tests twice - once before flushing and once after.
01604     for (int times = 1; times <= 2; ++times) {
01605         // Test iterators for terms which aren't there.
01606         TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
01607         TEST(db.synonyms_begin("ghi") == db.synonyms_end("ghi"));
01608         TEST(db.synonyms_begin("zzzzz") == db.synonyms_end("zzzzz"));
01609 
01610         s = "|";
01611         t = db.synonyms_begin("hello");
01612         while (t != db.synonyms_end("hello")) {
01613             s += *t++;
01614             s += '|';
01615         }
01616         TEST_STRINGS_EQUAL(s, "|howdy|");
01617 
01618         TEST(db.synonyms_begin("goodbye") == db.synonyms_end("goodbye"));
01619 
01620         s = "|";
01621         t = db.synonym_keys_begin();
01622         while (t != db.synonym_keys_end()) {
01623             s += *t++;
01624             s += '|';
01625         }
01626         TEST_STRINGS_EQUAL(s, "|hello|");
01627 
01628         db.flush();
01629     }
01630 
01631     Xapian::Database db_multi;
01632     db_multi.add_database(db);
01633     db_multi.add_database(get_database("apitest_simpledata"));
01634 
01635     // Test iterators for terms which aren't there.
01636     TEST(db_multi.synonyms_begin("abc") == db_multi.synonyms_end("abc"));
01637     TEST(db_multi.synonyms_begin("ghi") == db_multi.synonyms_end("ghi"));
01638     TEST(db_multi.synonyms_begin("zzzzz") == db_multi.synonyms_end("zzzzz"));
01639 
01640     s = "|";
01641     t = db_multi.synonyms_begin("hello");
01642     while (t != db_multi.synonyms_end("hello")) {
01643         s += *t++;
01644         s += '|';
01645     }
01646     TEST_STRINGS_EQUAL(s, "|howdy|");
01647 
01648     TEST(db_multi.synonyms_begin("goodbye") == db_multi.synonyms_end("goodbye"));
01649 
01650     s = "|";
01651     t = db_multi.synonym_keys_begin();
01652     while (t != db_multi.synonym_keys_end()) {
01653         s += *t++;
01654         s += '|';
01655     }
01656     TEST_STRINGS_EQUAL(s, "|hello|");
01657 
01658     return true;
01659 }
01660 
01661 // Test basic metadata access methods.
01662 DEFINE_TESTCASE(metadata1, writable) {
01663     Xapian::WritableDatabase db = get_writable_database();
01664 
01665     TEST_EQUAL(db.get_metadata("foo"), "");
01666     try {
01667         db.set_metadata("foo", "bar");
01668     } catch (Xapian::UnimplementedError &) {
01669         SKIP_TEST("Metadata not supported by this backend");
01670     }
01671     TEST_EQUAL(db.get_metadata("foo"), "bar");
01672     db.set_metadata("foo", "baz");
01673     TEST_EQUAL(db.get_doccount(), 0);
01674     TEST_EQUAL(db.get_metadata("foo"), "baz");
01675     db.set_metadata("foo", "");
01676     TEST_EQUAL(db.get_metadata("foo"), "");
01677 
01678     TEST_EQUAL(db.get_doccount(), 0);
01679 
01680     return true;
01681 }
01682 
01683 // Test that metadata gets applied at same time as other changes.
01684 DEFINE_TESTCASE(metadata2, metadata) {
01685     SKIP_TEST_UNLESS_BACKEND("flint");
01686     Xapian::WritableDatabase db = get_writable_database();
01687     Xapian::Database dbr = get_writable_database_as_database();
01688 
01689     TEST_EQUAL(db.get_metadata("foo"), "");
01690     db.set_metadata("foo", "bar");
01691     TEST_EQUAL(db.get_metadata("foo"), "bar");
01692     TEST_EQUAL(dbr.get_metadata("foo"), "");
01693     db.flush();
01694     TEST_EQUAL(dbr.get_metadata("foo"), "");
01695     dbr.reopen();
01696     TEST_EQUAL(db.get_metadata("foo"), "bar");
01697     TEST_EQUAL(dbr.get_metadata("foo"), "bar");
01698     TEST_EQUAL(dbr.get_doccount(), 0);
01699 
01700     db.add_document(Xapian::Document());
01701     db.set_metadata("foo", "baz");
01702     TEST_EQUAL(db.get_doccount(), 1);
01703     TEST_EQUAL(db.get_metadata("foo"), "baz");
01704     db.flush();
01705 
01706     TEST_EQUAL(dbr.get_metadata("foo"), "bar");
01707     dbr.reopen();
01708     TEST_EQUAL(dbr.get_metadata("foo"), "baz");
01709 
01710     db.set_metadata("foo", "");
01711     TEST_EQUAL(db.get_metadata("foo"), "");
01712     db.flush();
01713     TEST_EQUAL(dbr.get_metadata("foo"), "baz");
01714     dbr.reopen();
01715     TEST_EQUAL(dbr.get_metadata("foo"), "");
01716 
01717     TEST_EQUAL(db.get_doccount(), 1);
01718 
01719     return true;
01720 }
01721 
01722 // Test the empty metadata keys give an error correctly.
01723 DEFINE_TESTCASE(metadata3, metadata) {
01724     Xapian::WritableDatabase db = get_writable_database();
01725 
01726     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_metadata(""));
01727     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.set_metadata("", "foo"));
01728     TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_metadata(""));
01729 
01730     return true;
01731 }
01732 
01733 // Regression test for adding a piece of metadata on its own before adding
01734 // other things.
01735 DEFINE_TESTCASE(metadata4, metadata) {
01736     Xapian::WritableDatabase db = get_writable_database();
01737 
01738     db.set_metadata("foo", "foo");
01739     db.flush();
01740 
01741     Xapian::Document doc;
01742     doc.add_posting("foo", 1);
01743     db.add_document(doc);
01744 
01745     Xapian::Database dbr(get_writable_database_as_database());
01746 
01747     return true;
01748 }
01749 
01750 
01751 
01752 // Test that adding a document with a really long term gives an error on
01753 // add_document() rather than on flush().
01754 DEFINE_TESTCASE(termtoolong1, writable) {
01755     // Quartz doesn't perform this check.
01756     SKIP_TEST_FOR_BACKEND("quartz");
01757     // Inmemory doesn't impose a limit.
01758     SKIP_TEST_FOR_BACKEND("inmemory");
01759 #ifndef XAPIAN_HAS_FLINT_BACKEND
01760     // If flint is disabled, remotetcp and remoteprog will use quartz
01761     // which doesn't perform this check.
01762     SKIP_TEST_FOR_BACKEND("remoteprog");
01763     SKIP_TEST_FOR_BACKEND("remotetcp");
01764 #endif
01765 
01766     Xapian::WritableDatabase db = get_writable_database();
01767 
01768     for (Xapian::doccount i = 246; i <= 290; ++i) {
01769         tout << "Term length " << i << endl;
01770         Xapian::Document doc;
01771         string term(i, 'X');
01772         doc.add_term(term);
01773         try {
01774             db.add_document(doc);
01775             TEST_AND_EXPLAIN(false, "Expecting exception InvalidArgumentError");
01776         } catch (const Xapian::InvalidArgumentError &e) {
01777             // Check that the max length is correctly expressed in the
01778             // exception message - we've got this wrong in two different ways
01779             // in the past!
01780             tout << e.get_msg() << endl;
01781             TEST(e.get_msg().find("Term too long (> 245)") != string::npos);
01782         }
01783     }
01784 
01785     for (Xapian::doccount j = 240; j <= 245; ++j) {
01786         tout << "Term length " << j << endl;
01787         Xapian::Document doc;
01788         string term(j, 'X');
01789         doc.add_term(term);
01790         db.add_document(doc);
01791     }
01792 
01793     db.flush();
01794 
01795     {
01796         // Currently flint doesn't allow
01797         Xapian::Document doc;
01798         doc.add_term(string(126, '\0'));
01799         db.add_document(doc);
01800         try {
01801             db.flush();
01802             TEST_AND_EXPLAIN(false, "Expecting exception InvalidArgumentError");
01803         } catch (const Xapian::InvalidArgumentError &e) {
01804             // Check that the max length is correctly expressed in the
01805             // exception message - we've got this wrong in two different ways
01806             // in the past!
01807             tout << e.get_msg() << endl;
01808             TEST(e.get_msg().find(" is 252 bytes") != string::npos);
01809         }
01810     }
01811 
01812     return true;
01813 }
01814 
01816 DEFINE_TESTCASE(postlist7, writable) {
01817     Xapian::WritableDatabase db_w = get_writable_database();
01818 
01819     {
01820         Xapian::Document doc;
01821         doc.add_term("foo", 3);
01822         doc.add_term("zz", 4);
01823         db_w.replace_document(5, doc);
01824     }
01825 
01826     Xapian::PostingIterator p;
01827     p = db_w.postlist_begin("foo");
01828     TEST(p != db_w.postlist_end("foo"));
01829     TEST_EQUAL(*p, 5);
01830     TEST_EQUAL(p.get_wdf(), 3);
01831     TEST_EQUAL(p.get_doclength(), 7);
01832     ++p;
01833     TEST(p == db_w.postlist_end("foo"));
01834 
01835     {
01836         Xapian::Document doc;
01837         doc.add_term("foo", 1);
01838         doc.add_term("zz", 1);
01839         db_w.replace_document(6, doc);
01840     }
01841 
01842     p = db_w.postlist_begin("foo");
01843     TEST(p != db_w.postlist_end("foo"));
01844     TEST_EQUAL(*p, 5);
01845     TEST_EQUAL(p.get_wdf(), 3);
01846     TEST_EQUAL(p.get_doclength(), 7);
01847     ++p;
01848     TEST(p != db_w.postlist_end("foo"));
01849     TEST_EQUAL(*p, 6);
01850     TEST_EQUAL(p.get_wdf(), 1);
01851     TEST_EQUAL(p.get_doclength(), 2);
01852     ++p;
01853     TEST(p == db_w.postlist_end("foo"));
01854 
01855     return true;
01856 }
01857 
01859 DEFINE_TESTCASE(writeread1, writable && metadata) {
01860     Xapian::WritableDatabase db_w = get_writable_database();
01861     db_w.set_metadata("1", "2");
01862     string longitem(20000, 'j');
01863     db_w.set_metadata("2", longitem);
01864 
01865     string readitem = db_w.get_metadata("2");
01866     TEST_EQUAL(readitem, longitem);
01867 
01868     return true;
01869 }
01870 
01871 DEFINE_TESTCASE(lazytablebug1, writable && flint) {
01872     {
01873         Xapian::WritableDatabase db = get_named_writable_database("lazytablebug1", string());
01874 
01875         Xapian::Document doc;
01876         doc.add_term("foo");
01877         db.add_document(doc);
01878         db.flush();
01879 
01880         string synonym(255, 'x');
01881         char buf[] = " iamafish!!!!!!!!!!";
01882         for (int i = 33; i < 120; ++i) {
01883             db.add_synonym(buf, synonym);
01884             ++buf[0];
01885         }
01886 
01887         db.flush();
01888     }
01889 
01890     Xapian::Database db = get_writable_database_as_database();
01891     for (Xapian::TermIterator t = db.synonym_keys_begin(); t != db.synonym_keys_end(); ++t) {
01892         tout << *t << endl;
01893     }
01894 
01895     return true;
01896 }
01897 
01898 static double
01899 bigoaddvalue_helper(size_t num_values)
01900 {
01901     Xapian::WritableDatabase db = get_writable_database();
01902 
01903     Xapian::Document doc;
01904     for (size_t i = 0; i < num_values; ++i) {
01905         doc.add_value(i, "moo");
01906     }
01907 
01908     OmTime start = OmTime::now();
01909 
01910     db.add_document(doc);
01911     db.flush();
01912 
01913     return (OmTime::now() - start).as_double();
01914 }
01915 
01916 DEFINE_TESTCASE(bigoaddvalue, writable) {
01917     const size_t N = 5000;
01918     double time_N = bigoaddvalue_helper(N);
01919     tout << "Adding a document with " << N << " values took " << time_N
01920          << " seconds" << endl;
01921     double time_10N = bigoaddvalue_helper(10 * N);
01922     tout << "Adding a document with " << 10 * N << " values took " << time_10N
01923          << " seconds" << endl;
01924 
01925     if (time_N == 0.0) {
01926         // The first test completed before the timer ticked at all!
01927         SKIP_TEST("Timer granularity is too coarse");
01928     }
01929 
01930     // O(n*n) is bad, but we don't require linearity - O(n*log(n)) is
01931     // acceptable, so put the threshold halfway between.
01932     const double ALLOWED_FACTOR = (100.0 + 10 * 2.71828) / 2.0;
01933     TEST_LESSER(time_10N, time_N * ALLOWED_FACTOR);
01934 
01935     return true;
01936 }
01937 
01939 DEFINE_TESTCASE(cursordelbug1, flint) {
01940     static const int terms[] = { 219, 221, 222, 223, 224, 225, 226 };
01941     static const int copies[] = { 74, 116, 199, 21, 45, 155, 189 };
01942 
01943     Xapian::WritableDatabase db;
01944     db = get_named_writable_database("cursordelbug1", string());
01945 
01946     for (size_t i = 0; i < sizeof(terms) / sizeof(terms[0]); ++i) {
01947         Xapian::Document doc;
01948         doc.add_term("XC" + om_tostring(terms[i]));
01949         doc.add_term("XTabc");
01950         doc.add_term("XAdef");
01951         doc.add_term("XRghi");
01952         doc.add_term("XYabc");
01953         size_t c = copies[i];
01954         while (c--) db.add_document(doc);
01955     }
01956 
01957     db.flush();
01958 
01959     for (size_t i = 0; i < sizeof(terms) / sizeof(terms[0]); ++i) {
01960         db.delete_document("XC" + om_tostring(terms[i]));
01961     }
01962 
01963     db.flush();
01964 
01965     string cmd = XAPIAN_BIN_PATH"xapian-check .flint/dbw__cursordelbug1";
01966 #ifdef __WIN32__
01967     cmd += " >nul";
01968 #else
01969     cmd += " >/dev/null";
01970 #endif
01971     if (system(cmd.c_str()) != 0)
01972         return false;
01973 
01974     return true;
01975 }

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