Branch data Line data Source code
1 : : /* api_wrdb.cc: tests which need a writable backend
2 : : *
3 : : * Copyright 1999,2000,2001 BrightStation PLC
4 : : * Copyright 2001 Hein Ragas
5 : : * Copyright 2002 Ananova Ltd
6 : : * Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010 Olly Betts
7 : : * Copyright 2006 Richard Boulton
8 : : * Copyright 2007 Lemur Consulting Ltd
9 : : *
10 : : * This program is free software; you can redistribute it and/or
11 : : * modify it under the terms of the GNU General Public License as
12 : : * published by the Free Software Foundation; either version 2 of the
13 : : * License, or (at your option) any later version.
14 : : *
15 : : * This program is distributed in the hope that it will be useful,
16 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : : * GNU General Public License for more details.
19 : : *
20 : : * You should have received a copy of the GNU General Public License
21 : : * along with this program; if not, write to the Free Software
22 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
23 : : * USA
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include "api_wrdb.h"
29 : :
30 : : #include <xapian.h>
31 : :
32 : : #include "backendmanager.h" // For XAPIAN_BIN_PATH.
33 : : #include "omassert.h"
34 : : #include "str.h"
35 : : #include "testsuite.h"
36 : : #include "testutils.h"
37 : : #include "unixcmds.h"
38 : : #include "utils.h"
39 : :
40 : : #include "apitest.h"
41 : :
42 : : #include <cmath>
43 : : #include <cstdlib>
44 : : #include <map>
45 : : #include <string>
46 : :
47 : : using namespace std;
48 : :
49 : : // #######################################################################
50 : : // # Tests start here
51 : :
52 : : // test that indexing a term more than once at the same position increases
53 : : // the wdf
54 : 10 : DEFINE_TESTCASE(adddoc1, writable) {
55 : 10 : Xapian::WritableDatabase db = get_writable_database();
56 : :
57 : 10 : Xapian::Document doc1, doc2, doc3;
58 : :
59 : : // doc1 should come top, but if term "foo" gets wdf of 1, doc2 will beat it
60 : : // doc3 should beat both
61 : : // Note: all docs have same length
62 : 10 : doc1.set_data(string("tom"));
63 : 10 : doc1.add_posting("foo", 1);
64 : 10 : doc1.add_posting("foo", 1);
65 : 10 : doc1.add_posting("foo", 1);
66 : 10 : doc1.add_posting("bar", 3);
67 : 10 : doc1.add_posting("bar", 4);
68 : 10 : db.add_document(doc1);
69 : :
70 : 10 : doc2.set_data(string("dick"));
71 : 10 : doc2.add_posting("foo", 1);
72 : 10 : doc2.add_posting("foo", 2);
73 : 10 : doc2.add_posting("bar", 3);
74 : 10 : doc2.add_posting("bar", 3);
75 : 10 : doc2.add_posting("bar", 3);
76 : 10 : db.add_document(doc2);
77 : :
78 : 10 : doc3.set_data(string("harry"));
79 : 10 : doc3.add_posting("foo", 1);
80 : 10 : doc3.add_posting("foo", 1);
81 : 10 : doc3.add_posting("foo", 2);
82 : 10 : doc3.add_posting("foo", 2);
83 : 10 : doc3.add_posting("bar", 3);
84 : 10 : db.add_document(doc3);
85 : :
86 : 10 : Xapian::Query query("foo");
87 : :
88 : 10 : Xapian::Enquire enq(db);
89 : 10 : enq.set_query(query);
90 : :
91 : 10 : Xapian::MSet mset = enq.get_mset(0, 10);
92 : :
93 : 10 : mset_expect_order(mset, 3, 1, 2);
94 : :
95 : 10 : return true;
96 : : }
97 : :
98 : : // test that removing a posting and removing a term works
99 : 10 : DEFINE_TESTCASE(adddoc2, writable) {
100 : 10 : Xapian::WritableDatabase db = get_writable_database();
101 : :
102 : 10 : Xapian::Document doc1;
103 : :
104 : 10 : doc1.add_posting("foo", 1);
105 : 10 : doc1.add_posting("foo", 1);
106 : 10 : doc1.add_posting("foo", 2);
107 : 10 : doc1.add_posting("foo", 2);
108 : 10 : doc1.add_posting("bar", 3);
109 : 10 : doc1.add_posting("gone", 1);
110 : : // Quartz had a bug handling a term >= 128 characters longer than the
111 : : // preceding term in the sort order - this is "foo" + 130 "X"s
112 : 10 : doc1.add_posting("fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 1);
113 : : Xapian::docid did;
114 : :
115 : 10 : Xapian::Document doc2 = db.get_document(did = db.add_document(doc1));
116 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
117 : :
118 : 10 : Xapian::TermIterator iter1 = doc1.termlist_begin();
119 : 10 : Xapian::TermIterator iter2 = doc2.termlist_begin();
120 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
121 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
122 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "bar");
123 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
124 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 1);
125 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 1);
126 : : //TEST_EQUAL(iter1.get_termfreq(), 0);
127 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_termfreq(), 1);
128 : :
129 : 10 : iter1++;
130 : 10 : iter2++;
131 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
132 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
133 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "foo");
134 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
135 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 4);
136 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 4);
137 : : //TEST_EQUAL(iter1.get_termfreq(), 0);
138 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_termfreq(), 1);
139 : :
140 : 10 : iter1++;
141 : 10 : iter2++;
142 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
143 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
144 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
145 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
146 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 1);
147 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 1);
148 : : // assertion fails in debug build! TEST_EQUAL(iter1.get_termfreq(), 0);
149 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_termfreq(), 1);
150 : :
151 : 10 : iter1++;
152 : 10 : iter2++;
153 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
154 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
155 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "gone");
156 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
157 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 1);
158 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 1);
159 : : // assertion fails in debug build! TEST_EQUAL(iter1.get_termfreq(), 0);
160 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_termfreq(), 1);
161 : :
162 : 10 : iter1++;
163 : 10 : iter2++;
164 [ - + ][ # # ]: 10 : TEST(iter1 == doc1.termlist_end());
165 [ - + ][ # # ]: 10 : TEST(iter2 == doc2.termlist_end());
166 : :
167 : 10 : doc2.remove_posting("foo", 1, 5);
168 : 10 : doc2.add_term("bat", 0);
169 : 10 : doc2.add_term("bar", 8);
170 : 10 : doc2.add_term("bag", 0);
171 : 10 : doc2.remove_term("gone");
172 : 10 : doc2.remove_term("fooXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
173 : :
174 : : // Should have (doc,wdf) pairs: (bag,0)(bar,9)(bat,0)(foo,0)
175 : : // positionlists (bag,none)(bar,3)(bat,none)(foo,2)
176 : :
177 : 10 : iter2 = doc2.termlist_begin();
178 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
179 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, "bag");
180 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
181 : 10 : iter2++;
182 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
183 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, "bar");
184 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
185 : 10 : iter2++;
186 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
187 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, "bat");
188 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
189 : 10 : iter2++;
190 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
191 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, "foo");
192 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
193 : 10 : iter2++;
194 [ - + ][ # # ]: 10 : TEST(iter2 == doc2.termlist_end());
195 : :
196 : 10 : doc1 = db.get_document(did = db.add_document(doc2));
197 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
198 : :
199 : 10 : iter1 = doc1.termlist_begin();
200 : 10 : iter2 = doc2.termlist_begin();
201 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
202 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
203 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "bag");
204 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
205 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 0);
206 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 0);
207 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_termfreq(), 1);
208 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
209 [ - + ][ # # ]: 10 : TEST(iter1.positionlist_begin() == iter1.positionlist_end());
210 [ - + ][ # # ]: 10 : TEST(iter2.positionlist_begin() == iter2.positionlist_end());
211 : :
212 : 10 : iter1++;
213 : 10 : iter2++;
214 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
215 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
216 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "bar");
217 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
218 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 9);
219 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 9);
220 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_termfreq(), 2);
221 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
222 : :
223 : 10 : Xapian::PositionIterator pi1;
224 : 10 : pi1 = iter1.positionlist_begin();
225 : 10 : Xapian::PositionIterator pi2 = iter2.positionlist_begin();
226 [ - + # # ]: 10 : TEST_EQUAL(*pi1, 3); pi1++;
227 [ - + # # ]: 10 : TEST_EQUAL(*pi2, 3); pi2++;
228 [ - + ][ # # ]: 10 : TEST(pi1 == iter1.positionlist_end());
229 [ - + ][ # # ]: 10 : TEST(pi2 == iter2.positionlist_end());
230 : :
231 : 10 : iter1++;
232 : 10 : iter2++;
233 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
234 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
235 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "bat");
236 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
237 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 0);
238 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 0);
239 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_termfreq(), 1);
240 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
241 [ - + ][ # # ]: 10 : TEST(iter1.positionlist_begin() == iter1.positionlist_end());
242 [ - + ][ # # ]: 10 : TEST(iter2.positionlist_begin() == iter2.positionlist_end());
243 : :
244 : 10 : iter1++;
245 : 10 : iter2++;
246 [ - + ][ # # ]: 10 : TEST(iter1 != doc1.termlist_end());
247 [ - + ][ # # ]: 10 : TEST(iter2 != doc2.termlist_end());
248 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter1, "foo");
249 [ - + ][ # # ]: 10 : TEST_EQUAL(*iter2, *iter1);
250 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_wdf(), 0);
251 [ - + ][ # # ]: 10 : TEST_EQUAL(iter2.get_wdf(), 0);
252 [ - + ][ # # ]: 10 : TEST_EQUAL(iter1.get_termfreq(), 2);
253 : : //TEST_EQUAL(iter2.get_termfreq(), 0);
254 : :
255 : 10 : Xapian::PositionIterator temp1 = iter1.positionlist_begin();
256 : 10 : pi1 = temp1;
257 : 10 : Xapian::PositionIterator temp2 = iter2.positionlist_begin();
258 : 10 : pi2 = temp2;
259 [ - + # # ]: 10 : TEST_EQUAL(*pi1, 2); pi1++;
260 [ - + # # ]: 10 : TEST_EQUAL(*pi2, 2); pi2++;
261 [ - + ][ # # ]: 10 : TEST(pi1 == iter1.positionlist_end());
262 [ - + ][ # # ]: 10 : TEST(pi2 == iter2.positionlist_end());
263 : :
264 : 10 : iter1++;
265 : 10 : iter2++;
266 [ - + ][ # # ]: 10 : TEST(iter1 == doc1.termlist_end());
267 [ - + ][ # # ]: 10 : TEST(iter2 == doc2.termlist_end());
268 : :
269 : 10 : return true;
270 : : }
271 : :
272 : : // test that adding lots of documents works, and doesn't leak memory
273 : : // REGRESSION FIXED:2003-09-07
274 : 10 : DEFINE_TESTCASE(adddoc3, writable) {
275 : 10 : Xapian::WritableDatabase db = get_writable_database();
276 : :
277 [ + + ]: 21010 : for (Xapian::doccount i = 0; i < 2100; ++i) {
278 : 21000 : Xapian::Document doc;
279 [ + + ]: 2121000 : for (Xapian::termcount t = 0; t < 100; ++t) {
280 : 2100000 : string term("foo");
281 : 2100000 : term += char(t ^ 70 ^ i);
282 : 2100000 : doc.add_posting(term, t);
283 : : }
284 : 21000 : db.add_document(doc);
285 : : }
286 : 10 : return true;
287 : : }
288 : :
289 : : // We want to test that a termlist starting with a 48 character long term works
290 : : // OK since this value currently requires special handling in flint for
291 : : // historical reasons!) Also test all other term lengths while we're at it.
292 : 10 : DEFINE_TESTCASE(adddoc4, writable) {
293 : 10 : Xapian::WritableDatabase db = get_writable_database();
294 : :
295 [ + + ]: 2410 : for (Xapian::doccount i = 1; i <= 240; ++i) {
296 : 2400 : Xapian::Document doc;
297 : 2400 : string term(i, 'X');
298 : 2400 : doc.add_term(term);
299 : 2400 : db.add_document(doc);
300 : : }
301 : 10 : db.add_document(Xapian::Document());
302 : 10 : db.commit();
303 : :
304 [ + + ]: 2410 : for (Xapian::doccount i = 1; i <= 240; ++i) {
305 : 2400 : Xapian::Document doc = db.get_document(i);
306 : 2400 : Xapian::TermIterator t = doc.termlist_begin();
307 [ - + ][ # # ]: 2400 : TEST(t != doc.termlist_end());
308 [ - + ][ # # ]: 2400 : TEST_EQUAL((*t).size(), i);
309 : 2400 : ++t;
310 [ - + ][ # # ]: 2400 : TEST(t == doc.termlist_end());
311 : : }
312 : :
313 : : // And test a document with no terms.
314 : 10 : Xapian::Document doc = db.get_document(241);
315 [ - + ][ # # ]: 10 : TEST(doc.termlist_begin() == doc.termlist_end());
316 : :
317 : 10 : return true;
318 : : }
319 : :
320 : : // Test adding a document, and checking that it got added correctly.
321 : : // This testcase used to be adddoc2 in quartztest.
322 : 10 : DEFINE_TESTCASE(adddoc5, writable) {
323 : : // Inmemory doesn't support get_writable_database_as_database().
324 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
325 : :
326 : : Xapian::docid did;
327 : 9 : Xapian::Document document_in;
328 : 9 : document_in.set_data("Foobar rising");
329 : 9 : document_in.add_value(7, "Value7");
330 : 9 : document_in.add_value(13, "Value13");
331 : 9 : document_in.add_posting("foobar", 1);
332 : 9 : document_in.add_posting("rising", 2);
333 : 9 : document_in.add_posting("foobar", 3);
334 : :
335 : 9 : Xapian::Document document_in2;
336 : 9 : document_in2.set_data("Foobar falling");
337 : 9 : document_in2.add_posting("foobar", 1);
338 : 9 : document_in2.add_posting("falling", 2);
339 : : {
340 : 9 : Xapian::WritableDatabase database(get_writable_database());
341 : :
342 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 0);
343 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 0);
344 : :
345 : 9 : did = database.add_document(document_in);
346 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 1);
347 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 3);
348 : :
349 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("foobar"), 1);
350 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("foobar"), 2);
351 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("rising"), 1);
352 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("rising"), 1);
353 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("falling"), 0);
354 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("falling"), 0);
355 : :
356 : 9 : Xapian::docid did2 = database.add_document(document_in2);
357 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 2);
358 [ - + ][ # # ]: 9 : TEST_NOT_EQUAL(did, did2);
359 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 5.0/2.0);
360 : :
361 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("foobar"), 2);
362 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("foobar"), 3);
363 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("rising"), 1);
364 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("rising"), 1);
365 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("falling"), 1);
366 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("falling"), 1);
367 : :
368 : 9 : database.delete_document(did);
369 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 1);
370 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 2);
371 : :
372 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("foobar"), 1);
373 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("foobar"), 1);
374 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("rising"), 0);
375 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("rising"), 0);
376 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("falling"), 1);
377 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("falling"), 1);
378 : :
379 : 9 : did = database.add_document(document_in);
380 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 2);
381 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 5.0/2.0);
382 : :
383 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("foobar"), 2);
384 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("foobar"), 3);
385 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("rising"), 1);
386 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("rising"), 1);
387 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("falling"), 1);
388 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("falling"), 1);
389 : : }
390 : :
391 : : {
392 : 9 : Xapian::Database database(get_writable_database_as_database());
393 : 9 : Xapian::Document document_out = database.get_document(did);
394 : :
395 [ - + ][ # # ]: 9 : TEST_EQUAL(document_in.get_data(), document_out.get_data());
396 : :
397 : : {
398 : 9 : Xapian::ValueIterator i(document_in.values_begin());
399 : 9 : Xapian::ValueIterator j(document_out.values_begin());
400 [ + + ]: 27 : for (; i != document_in.values_end(); i++, j++) {
401 [ - + ][ # # ]: 18 : TEST_NOT_EQUAL(j, document_out.values_end());
402 [ - + ][ # # ]: 18 : TEST_EQUAL(*i, *j);
403 [ - + ][ # # ]: 18 : TEST_EQUAL(i.get_valueno(), j.get_valueno());
404 : : }
405 [ - + ][ # # ]: 9 : TEST_EQUAL(j, document_out.values_end());
406 : : }
407 : :
408 : : {
409 : : // Regression test for bug fixed in 1.0.5 - values_begin() didn't
410 : : // ensure that values had been read. However, values_end() did
411 : : // (and so did values_count()) so this wasn't generally an issue
412 : : // but it shouldn't happen anyway.
413 : 9 : Xapian::Document doc_tmp = database.get_document(did);
414 : 9 : Xapian::ValueIterator i = document_in.values_begin();
415 : 9 : Xapian::ValueIterator j = doc_tmp.values_begin();
416 [ - + ][ # # ]: 9 : TEST_EQUAL(*i, *j);
417 : : }
418 : :
419 : : {
420 : 9 : Xapian::TermIterator i(document_in.termlist_begin());
421 : 9 : Xapian::TermIterator j(document_out.termlist_begin());
422 [ + + ]: 27 : for (; i != document_in.termlist_end(); i++, j++) {
423 [ - + ][ # # ]: 18 : TEST_NOT_EQUAL(j, document_out.termlist_end());
424 [ - + ][ # # ]: 18 : TEST_EQUAL(*i, *j);
425 [ - + ][ # # ]: 18 : TEST_EQUAL(i.get_wdf(), j.get_wdf());
426 [ + - ][ - + ]: 36 : TEST_EXCEPTION(Xapian::InvalidOperationError,
[ # # ][ - + ]
427 : : (void)i.get_termfreq());
428 [ - + # # ]: 18 : TEST_NOT_EQUAL(0, j.get_termfreq());
429 [ + + ]: 18 : if (*i == "foobar") {
430 : : // termfreq of foobar is 2
431 [ - + ][ # # ]: 9 : TEST_EQUAL(2, j.get_termfreq());
432 : : } else {
433 : : // termfreq of rising is 1
434 [ - + ][ # # ]: 9 : TEST_EQUAL(*i, "rising");
435 [ - + ][ # # ]: 9 : TEST_EQUAL(1, j.get_termfreq());
436 : : }
437 : 18 : Xapian::PositionIterator k(i.positionlist_begin());
438 : 18 : Xapian::PositionIterator l(j.positionlist_begin());
439 [ + + ]: 45 : for (; k != i.positionlist_end(); k++, l++) {
440 [ - + ][ # # ]: 27 : TEST_NOT_EQUAL(l, j.positionlist_end());
441 [ - + ][ # # ]: 27 : TEST_EQUAL(*k, *l);
442 : : }
443 [ - + ][ # # ]: 18 : TEST_EQUAL(l, j.positionlist_end());
444 : : }
445 [ - + ][ # # ]: 9 : TEST_EQUAL(j, document_out.termlist_end());
446 : 9 : }
447 : : }
448 : :
449 : 9 : return true;
450 : : }
451 : :
452 : : // Test adding a document, and checking that it got added correctly.
453 : : // This testcase used to be adddoc3 in quartztest.
454 : 10 : DEFINE_TESTCASE(adddoc6, writable) {
455 : : // Inmemory doesn't support get_writable_database_again().
456 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
457 : :
458 : : Xapian::docid did;
459 : 9 : Xapian::Document document_in;
460 : 9 : document_in.set_data("Foobar rising");
461 : 9 : document_in.add_value(7, "Value7");
462 : 9 : document_in.add_value(13, "Value13");
463 : 9 : document_in.add_posting("foo", 1);
464 : 9 : document_in.add_posting("bar", 2);
465 : :
466 : : {
467 : 9 : Xapian::WritableDatabase database(get_writable_database());
468 : :
469 : 9 : did = database.add_document(document_in);
470 [ - + # # ]: 9 : TEST_EQUAL(did, 1);
471 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_doccount(), 1);
472 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 2);
473 : : }
474 : :
475 : : {
476 : 9 : Xapian::WritableDatabase database(get_writable_database_again());
477 : :
478 : 9 : document_in.remove_term("foo");
479 : 9 : document_in.add_posting("baz", 1);
480 : :
481 : 9 : database.replace_document(1, document_in);
482 : :
483 : 9 : database.delete_document(1);
484 : :
485 [ - + # # ]: 9 : TEST_EQUAL(database.get_doccount(), 0);
486 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_avlength(), 0);
487 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("foo"), 0);
488 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("foo"), 0);
489 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("bar"), 0);
490 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("bar"), 0);
491 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_termfreq("baz"), 0);
492 [ - + ][ # # ]: 9 : TEST_EQUAL(database.get_collection_freq("baz"), 0);
493 : : }
494 : :
495 : 9 : return true;
496 : : }
497 : :
498 : : // tests that database destructors commit if it isn't done explicitly
499 : 10 : DEFINE_TESTCASE(implicitendsession1, writable) {
500 : 10 : Xapian::WritableDatabase db = get_writable_database();
501 : :
502 : 10 : Xapian::Document doc;
503 : :
504 : 10 : doc.set_data(string("top secret"));
505 : 10 : doc.add_posting("cia", 1);
506 : 10 : doc.add_posting("nsa", 2);
507 : 10 : doc.add_posting("fbi", 3);
508 : 10 : db.add_document(doc);
509 : :
510 : 10 : return true;
511 : : }
512 : :
513 : : // tests that assignment of Xapian::Database and Xapian::WritableDatabase works
514 : : // as expected
515 : 10 : DEFINE_TESTCASE(databaseassign1, writable) {
516 : 10 : Xapian::WritableDatabase wdb = get_writable_database();
517 : 10 : Xapian::Database db = get_database("");
518 : 10 : Xapian::Database actually_wdb = wdb;
519 : 10 : Xapian::WritableDatabase w1(wdb);
520 : 10 : w1 = wdb;
521 : 10 : Xapian::Database d1(wdb);
522 : 10 : Xapian::Database d2(actually_wdb);
523 : 10 : d2 = wdb;
524 : 10 : d2 = actually_wdb;
525 : 10 : wdb = wdb; // check assign to itself works
526 : 10 : db = db; // check assign to itself works
527 : 10 : return true;
528 : : }
529 : :
530 : : // tests that deletion and updating of documents works as expected
531 : 10 : DEFINE_TESTCASE(deldoc1, writable) {
532 : 10 : Xapian::WritableDatabase db = get_writable_database();
533 : :
534 : 10 : Xapian::Document doc1;
535 : :
536 : 10 : doc1.add_posting("foo", 1);
537 : 10 : doc1.add_posting("foo", 1);
538 : 10 : doc1.add_posting("foo", 2);
539 : 10 : doc1.add_posting("foo", 2);
540 : 10 : doc1.add_posting("bar", 3);
541 : 10 : doc1.add_posting("gone", 1);
542 : :
543 : 10 : Xapian::docid did = db.add_document(doc1);
544 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
545 : :
546 : 10 : doc1.remove_term("gone");
547 : :
548 : 10 : did = db.add_document(doc1);
549 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
550 : :
551 : 10 : doc1.add_term("new", 1);
552 : 10 : did = db.add_document(doc1);
553 [ - + # # ]: 10 : TEST_EQUAL(did, 3);
554 : :
555 : 10 : db.delete_document(1);
556 : :
557 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
[ # # ][ - + ]
558 : :
559 : 10 : doc1 = db.get_document(2);
560 : 10 : doc1.remove_term("foo");
561 : 10 : doc1.add_term("fwing");
562 : 10 : db.replace_document(2, doc1);
563 : :
564 : 10 : Xapian::Document doc2 = db.get_document(2);
565 : 10 : Xapian::TermIterator tit = doc2.termlist_begin();
566 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(tit, doc2.termlist_end());
567 [ - + ][ # # ]: 10 : TEST_EQUAL(*tit, "bar");
568 : 10 : tit++;
569 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(tit, doc2.termlist_end());
570 [ - + ][ # # ]: 10 : TEST_EQUAL(*tit, "fwing");
571 : 10 : tit++;
572 [ - + ][ # # ]: 10 : TEST_EQUAL(tit, doc2.termlist_end());
573 : :
574 : 10 : return true;
575 : : }
576 : :
577 : : // tests that deletion and updating of documents works as expected
578 : 10 : DEFINE_TESTCASE(deldoc2, writable) {
579 : 10 : Xapian::WritableDatabase db = get_writable_database();
580 : :
581 : 10 : Xapian::Document doc1;
582 : :
583 : 10 : doc1.add_posting("one", 1);
584 : 10 : doc1.add_posting("two", 2);
585 : 10 : doc1.add_posting("two", 3);
586 : : Xapian::docid did;
587 : :
588 : 10 : did = db.add_document(doc1);
589 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
590 : :
591 : 10 : doc1.remove_term("one");
592 : 10 : doc1.add_posting("three", 4);
593 : :
594 : 10 : did = db.add_document(doc1);
595 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
596 : :
597 : 10 : doc1.add_posting("one", 7);
598 : 10 : doc1.remove_term("two");
599 : :
600 : 10 : did = db.add_document(doc1);
601 [ - + # # ]: 10 : TEST_EQUAL(did, 3);
602 : :
603 : 10 : db.commit();
604 : :
605 : 10 : db.reopen();
606 : :
607 : 10 : db.delete_document(1);
608 : 10 : db.delete_document(2);
609 : 10 : db.delete_document(3);
610 : :
611 : 10 : db.commit();
612 : :
613 : 10 : db.reopen();
614 : :
615 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
616 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("two"), db.postlist_end("two"));
617 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("three"), db.postlist_end("three"));
618 : :
619 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(1));
[ # # ][ - + ]
620 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(2));
[ # # ][ - + ]
621 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(3));
[ # # ][ - + ]
622 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(4));
[ # # ][ - + ]
623 : :
624 : : // test positionlist_{begin,end}?
625 : :
626 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
627 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_avlength(), 0);
628 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("one"), 0);
629 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("two"), 0);
630 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("three"), 0);
631 : :
632 [ - + ][ # # ]: 10 : TEST(!db.term_exists("one"));
633 [ - + ][ # # ]: 10 : TEST(!db.term_exists("two"));
634 [ - + ][ # # ]: 10 : TEST(!db.term_exists("three"));
635 : :
636 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("one"), 0);
637 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("two"), 0);
638 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("three"), 0);
639 : :
640 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(1));
[ # # ][ - + ]
641 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(2));
[ # # ][ - + ]
642 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(3));
[ # # ][ - + ]
643 : :
644 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
[ # # ][ - + ]
645 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
646 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(3));
[ # # ][ - + ]
647 : :
648 [ - + ][ # # ]: 10 : TEST_EQUAL(db.allterms_begin(), db.allterms_end());
649 : :
650 : 10 : return true;
651 : : }
652 : :
653 : : // another test of deletion of documents, a cut-down version of deldoc2
654 : 10 : DEFINE_TESTCASE(deldoc3, writable) {
655 : 10 : Xapian::WritableDatabase db = get_writable_database();
656 : :
657 : 10 : Xapian::Document doc1;
658 : :
659 : 10 : doc1.add_posting("one", 1);
660 : :
661 : 10 : Xapian::docid did = db.add_document(doc1);
662 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
663 : :
664 : 10 : db.commit();
665 : :
666 : 10 : db.reopen();
667 : :
668 : 10 : db.delete_document(1);
669 : :
670 : 10 : db.commit();
671 : :
672 : 10 : db.reopen();
673 : :
674 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
675 : :
676 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(1));
[ # # ][ - + ]
677 : : (void)&db; // gcc 2.95 seems to miscompile without this!!! - Olly
678 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(2));
[ # # ][ - + ]
679 : :
680 : : // test positionlist_{begin,end}?
681 : :
682 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
683 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_avlength(), 0);
684 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("one"), 0);
685 : :
686 [ - + ][ # # ]: 10 : TEST(!db.term_exists("one"));
687 : :
688 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("one"), 0);
689 : :
690 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(1));
[ # # ][ - + ]
691 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(2));
[ # # ][ - + ]
692 : :
693 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
[ # # ][ - + ]
694 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
695 : :
696 [ - + ][ # # ]: 10 : TEST_EQUAL(db.allterms_begin(), db.allterms_end());
697 : :
698 : 10 : return true;
699 : : }
700 : :
701 : : // tests that deletion and updating of (lots of) documents works as expected
702 : 10 : DEFINE_TESTCASE(deldoc4, writable) {
703 : 10 : Xapian::WritableDatabase db = get_writable_database();
704 : :
705 : 10 : Xapian::Document doc1;
706 : :
707 : 10 : doc1.add_posting("one", 1);
708 : 10 : doc1.add_posting("two", 2);
709 : 10 : doc1.add_posting("two", 3);
710 : :
711 : 10 : Xapian::Document doc2 = doc1;
712 : 10 : doc2.remove_term("one");
713 : 10 : doc2.add_posting("three", 4);
714 : :
715 : 10 : Xapian::Document doc3 = doc2;
716 : 10 : doc3.add_posting("one", 7);
717 : 10 : doc3.remove_term("two");
718 : :
719 : 10 : const Xapian::docid maxdoc = 1000 * 3;
720 : : Xapian::docid did;
721 [ + + ]: 10010 : for (Xapian::docid i = 0; i < maxdoc / 3; ++i) {
722 : 10000 : did = db.add_document(doc1);
723 [ - + # # ]: 10000 : TEST_EQUAL(did, i * 3 + 1);
724 : 10000 : did = db.add_document(doc2);
725 [ - + # # ]: 10000 : TEST_EQUAL(did, i * 3 + 2);
726 : 10000 : did = db.add_document(doc3);
727 [ - + # # ]: 10000 : TEST_EQUAL(did, i * 3 + 3);
728 : :
729 : 10000 : bool is_power_of_two = ((i & (i - 1)) == 0);
730 [ + + ]: 10000 : if (is_power_of_two) {
731 : 110 : db.commit();
732 : 110 : db.reopen();
733 : : }
734 : : }
735 : 10 : db.commit();
736 : 10 : db.reopen();
737 : :
738 : : /* delete the documents in a peculiar order */
739 [ + + ]: 10010 : for (Xapian::docid i = 0; i < maxdoc / 3; ++i) {
740 : 10000 : db.delete_document(maxdoc - i);
741 : 10000 : db.delete_document(maxdoc / 3 + i + 1);
742 : 10000 : db.delete_document(i + 1);
743 : : }
744 : :
745 : 10 : db.commit();
746 : :
747 : 10 : db.reopen();
748 : :
749 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("one"), db.postlist_end("one"));
750 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("two"), db.postlist_end("two"));
751 [ - + ][ # # ]: 10 : TEST_EQUAL(db.postlist_begin("three"), db.postlist_end("three"));
752 : :
753 [ + + ]: 30010 : for (Xapian::docid i = 1; i <= maxdoc; ++i) {
754 : : // TEST_EXCEPTION writes to tout each time if the test is run
755 : : // in verbose mode and some string stream implementations get
756 : : // very inefficient with large strings, so clear tout on each pass of
757 : : // the loop to speed up the test since the older information isn't
758 : : // interesting anyway.
759 : 30000 : tout.str(string());
760 [ + - ][ - + ]: 60000 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.termlist_begin(i));
[ # # ][ - + ]
761 [ + - ][ - + ]: 60000 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_doclength(i));
[ # # ][ - + ]
762 [ + - ][ - + ]: 60000 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(i));
[ # # ][ - + ]
763 : : }
764 : :
765 : : // test positionlist_{begin,end}?
766 : :
767 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
768 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_avlength(), 0);
769 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("one"), 0);
770 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("two"), 0);
771 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("three"), 0);
772 : :
773 [ - + ][ # # ]: 10 : TEST(!db.term_exists("one"));
774 [ - + ][ # # ]: 10 : TEST(!db.term_exists("two"));
775 [ - + ][ # # ]: 10 : TEST(!db.term_exists("three"));
776 : :
777 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("one"), 0);
778 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("two"), 0);
779 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_collection_freq("three"), 0);
780 : :
781 [ - + ][ # # ]: 10 : TEST_EQUAL(db.allterms_begin(), db.allterms_end());
782 : :
783 : 10 : return true;
784 : : }
785 : :
786 : : // Test deleting a document which was added in the same batch.
787 : 10 : DEFINE_TESTCASE(deldoc5, writable) {
788 : 10 : Xapian::WritableDatabase db = get_writable_database();
789 : :
790 : 10 : Xapian::Document doc1;
791 : :
792 : 10 : doc1.add_posting("foo", 1);
793 : 10 : doc1.add_posting("bar", 2);
794 : 10 : doc1.add_posting("aardvark", 3);
795 : :
796 : 10 : Xapian::docid did = db.add_document(doc1);
797 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
798 : :
799 : 10 : doc1.remove_term("bar");
800 : 10 : doc1.add_term("hello");
801 : :
802 : 10 : did = db.add_document(doc1);
803 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
804 : :
805 : 10 : doc1.add_term("world", 1);
806 : 10 : did = db.add_document(doc1);
807 [ - + # # ]: 10 : TEST_EQUAL(did, 3);
808 : :
809 : 10 : db.delete_document(2);
810 : :
811 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
812 : :
813 : 10 : db.commit();
814 : :
815 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
816 : :
817 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("foo"), 2);
818 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("aardvark"), 2);
819 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("hello"), 1);
820 : :
821 : 10 : Xapian::PostingIterator p = db.postlist_begin("foo");
822 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
823 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 1);
824 : 10 : ++p;
825 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
826 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 3);
827 : 10 : ++p;
828 [ - + ][ # # ]: 10 : TEST_EQUAL(p, db.postlist_end("foo"));
829 : :
830 : 10 : return true;
831 : : }
832 : :
833 : : // Regression test for bug in quartz and flint, fixed in 1.0.2.
834 : 10 : DEFINE_TESTCASE(deldoc6, writable) {
835 : 10 : Xapian::WritableDatabase db = get_writable_database();
836 : :
837 : 10 : Xapian::Document doc1;
838 : :
839 : 10 : doc1.add_posting("foo", 1);
840 : 10 : doc1.add_posting("bar", 2);
841 : 10 : doc1.add_posting("aardvark", 3);
842 : :
843 : 10 : Xapian::docid did = db.add_document(doc1);
844 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
845 : :
846 : 10 : doc1.remove_term("bar");
847 : 10 : doc1.add_term("hello");
848 : :
849 : 10 : did = db.add_document(doc1);
850 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
851 : :
852 : 10 : db.commit();
853 : :
854 : 10 : db.delete_document(2);
855 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.delete_document(3));
[ # # ][ - + ]
856 : :
857 : 10 : db.commit();
858 : :
859 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(2));
[ # # ][ - + ]
860 : :
861 : 10 : return true;
862 : : }
863 : :
864 : 10 : DEFINE_TESTCASE(replacedoc1, writable) {
865 : 10 : Xapian::WritableDatabase db = get_writable_database();
866 : :
867 : 10 : Xapian::Document doc1;
868 : :
869 : 10 : doc1.add_posting("foo", 1);
870 : 10 : doc1.add_posting("foo", 2);
871 : 10 : doc1.add_posting("gone",3);
872 : 10 : doc1.add_posting("bar", 4);
873 : 10 : doc1.add_posting("foo", 5);
874 : : Xapian::docid did;
875 : :
876 : 10 : did = db.add_document(doc1);
877 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
878 : :
879 : 10 : Xapian::Document doc2;
880 : :
881 : 10 : doc2.add_posting("foo", 1);
882 : 10 : doc2.add_posting("pipco", 2);
883 : 10 : doc2.add_posting("bar", 4);
884 : 10 : doc2.add_posting("foo", 5);
885 : :
886 : 10 : db.replace_document(did, doc2);
887 : :
888 : 10 : Xapian::Document doc3 = db.get_document(did);
889 : 10 : Xapian::TermIterator tIter = doc3.termlist_begin();
890 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "bar");
891 : 10 : Xapian::PositionIterator pIter = tIter.positionlist_begin();
892 [ - + # # ]: 10 : TEST_EQUAL(*pIter, 4);
893 : 10 : ++tIter;
894 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "foo");
895 : 10 : Xapian::PositionIterator qIter = tIter.positionlist_begin();
896 [ - + # # ]: 10 : TEST_EQUAL(*qIter, 1);
897 : 10 : ++qIter;
898 [ - + # # ]: 10 : TEST_EQUAL(*qIter, 5);
899 : 10 : ++tIter;
900 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "pipco");
901 : 10 : Xapian::PositionIterator rIter = tIter.positionlist_begin();
902 [ - + # # ]: 10 : TEST_EQUAL(*rIter, 2);
903 : 10 : ++tIter;
904 [ - + ][ # # ]: 10 : TEST_EQUAL(tIter, doc3.termlist_end());
905 : 10 : return true;
906 : : }
907 : :
908 : : // Test of new feature: WritableDatabase::replace_document accepts a docid
909 : : // which doesn't yet exist as of Xapian 0.8.2.
910 : 10 : DEFINE_TESTCASE(replacedoc2, writable) {
911 : 10 : Xapian::WritableDatabase db = get_writable_database();
912 : :
913 : 10 : Xapian::Document doc1;
914 : :
915 : 10 : doc1.add_posting("foo", 1);
916 : 10 : doc1.add_posting("foo", 2);
917 : 10 : doc1.add_posting("gone",3);
918 : 10 : doc1.add_posting("bar", 4);
919 : 10 : doc1.add_posting("foo", 5);
920 : 10 : Xapian::docid did = 31770;
921 : :
922 : 10 : db.replace_document(did, doc1);
923 : :
924 : : // Regression tests for bug in the InMemory backend - fixed in 1.0.2.
925 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::DocNotFoundError, db.get_document(1));
[ # # ][ - + ]
926 : 10 : Xapian::PostingIterator postit = db.postlist_begin("");
927 [ - + ][ # # ]: 10 : TEST(postit != db.postlist_end(""));
928 [ - + ][ # # ]: 10 : TEST_EQUAL(*postit, 31770);
929 : :
930 : 10 : Xapian::Document doc2;
931 : :
932 : 10 : doc2.add_posting("foo", 1);
933 : 10 : doc2.add_posting("pipco", 2);
934 : 10 : doc2.add_posting("bar", 4);
935 : 10 : doc2.add_posting("foo", 5);
936 : :
937 : 10 : db.replace_document(did, doc2);
938 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 1);
939 : :
940 : 10 : Xapian::Document doc3 = db.get_document(did);
941 : 10 : Xapian::TermIterator tIter = doc3.termlist_begin();
942 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "bar");
943 : 10 : Xapian::PositionIterator pIter = tIter.positionlist_begin();
944 [ - + # # ]: 10 : TEST_EQUAL(*pIter, 4);
945 : 10 : ++tIter;
946 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "foo");
947 : 10 : Xapian::PositionIterator qIter = tIter.positionlist_begin();
948 [ - + # # ]: 10 : TEST_EQUAL(*qIter, 1);
949 : 10 : ++qIter;
950 [ - + # # ]: 10 : TEST_EQUAL(*qIter, 5);
951 : 10 : ++tIter;
952 [ - + ][ # # ]: 10 : TEST_EQUAL(*tIter, "pipco");
953 : 10 : Xapian::PositionIterator rIter = tIter.positionlist_begin();
954 [ - + # # ]: 10 : TEST_EQUAL(*rIter, 2);
955 : 10 : ++tIter;
956 [ - + ][ # # ]: 10 : TEST_EQUAL(tIter, doc3.termlist_end());
957 : :
958 : 10 : did = db.add_document(doc1);
959 [ - + # # ]: 10 : TEST_EQUAL(did, 31771);
960 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doccount(), 2);
961 : :
962 [ + - ][ - + ]: 20 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.replace_document(0, doc2));
[ # # ][ - + ]
963 : :
964 : 10 : return true;
965 : : }
966 : :
967 : : // Test replacing a document which was added in the same batch.
968 : 10 : DEFINE_TESTCASE(replacedoc3, writable) {
969 : 10 : Xapian::WritableDatabase db = get_writable_database();
970 : :
971 : 10 : Xapian::Document doc1;
972 : :
973 : 10 : doc1.add_posting("foo", 1);
974 : 10 : doc1.add_posting("bar", 2);
975 : 10 : doc1.add_posting("aardvark", 3);
976 : :
977 : 10 : Xapian::docid did = db.add_document(doc1);
978 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
979 : :
980 : 10 : doc1.remove_term("bar");
981 : 10 : doc1.add_term("hello");
982 : :
983 : 10 : did = db.add_document(doc1);
984 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
985 : :
986 : 10 : doc1.add_term("world", 1);
987 : 10 : did = db.add_document(doc1);
988 [ - + # # ]: 10 : TEST_EQUAL(did, 3);
989 : :
990 : 10 : Xapian::Document doc2;
991 : 10 : doc2.add_term("world");
992 : 10 : db.replace_document(2, doc2);
993 : :
994 : 10 : db.commit();
995 : :
996 : : // Check that the document exists (no DocNotFoundError).
997 : 10 : doc2 = db.get_document(2);
998 : :
999 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("foo"), 2);
1000 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("aardvark"), 2);
1001 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("hello"), 1);
1002 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("world"), 2);
1003 : :
1004 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doclength(1), 3);
1005 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doclength(2), 1);
1006 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doclength(3), 4);
1007 : :
1008 : 10 : Xapian::PostingIterator p = db.postlist_begin("foo");
1009 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
1010 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 1);
1011 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 3);
1012 : 10 : ++p;
1013 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
1014 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 3);
1015 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 4);
1016 : 10 : ++p;
1017 [ - + ][ # # ]: 10 : TEST_EQUAL(p, db.postlist_end("foo"));
1018 : :
1019 : 10 : p = db.postlist_begin("world");
1020 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("world"));
1021 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 2);
1022 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 1);
1023 : 10 : ++p;
1024 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("world"));
1025 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 3);
1026 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 4);
1027 : 10 : ++p;
1028 [ - + ][ # # ]: 10 : TEST_EQUAL(p, db.postlist_end("world"));
1029 : :
1030 : 10 : return true;
1031 : : }
1032 : :
1033 : : // Test replacing a document which was deleted in the same batch.
1034 : 10 : DEFINE_TESTCASE(replacedoc4, writable) {
1035 : 10 : Xapian::WritableDatabase db = get_writable_database();
1036 : :
1037 : 10 : Xapian::Document doc1;
1038 : :
1039 : 10 : doc1.add_posting("foo", 1);
1040 : 10 : doc1.add_posting("bar", 2);
1041 : 10 : doc1.add_posting("aardvark", 3);
1042 : :
1043 : 10 : Xapian::docid did = db.add_document(doc1);
1044 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
1045 : :
1046 : 10 : doc1.remove_term("bar");
1047 : 10 : doc1.add_term("hello");
1048 : :
1049 : 10 : did = db.add_document(doc1);
1050 [ - + # # ]: 10 : TEST_EQUAL(did, 2);
1051 : :
1052 : 10 : doc1.add_term("world", 1);
1053 : 10 : did = db.add_document(doc1);
1054 [ - + # # ]: 10 : TEST_EQUAL(did, 3);
1055 : :
1056 : 10 : db.delete_document(2);
1057 : :
1058 : 10 : Xapian::Document doc2;
1059 : 10 : doc2.add_term("world");
1060 : 10 : db.replace_document(2, doc2);
1061 : :
1062 : 10 : db.commit();
1063 : :
1064 : : // Check that the document exists (no DocNotFoundError).
1065 : 10 : doc2 = db.get_document(2);
1066 : :
1067 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("foo"), 2);
1068 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("aardvark"), 2);
1069 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("hello"), 1);
1070 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_termfreq("world"), 2);
1071 : :
1072 : 10 : Xapian::PostingIterator p = db.postlist_begin("foo");
1073 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
1074 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 1);
1075 : 10 : ++p;
1076 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("foo"));
1077 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 3);
1078 : 10 : ++p;
1079 [ - + ][ # # ]: 10 : TEST_EQUAL(p, db.postlist_end("foo"));
1080 : :
1081 : 10 : p = db.postlist_begin("world");
1082 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("world"));
1083 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 2);
1084 : 10 : ++p;
1085 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(p, db.postlist_end("world"));
1086 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 3);
1087 : 10 : ++p;
1088 [ - + ][ # # ]: 10 : TEST_EQUAL(p, db.postlist_end("world"));
1089 : :
1090 : 10 : return true;
1091 : : }
1092 : :
1093 : : // Test replacing a document with itself without modifying postings.
1094 : : // Regression test for bug in 0.9.9 and earlier - there flint and quartz
1095 : : // lose all positional information for the document when you do this.
1096 : 10 : DEFINE_TESTCASE(replacedoc5, writable) {
1097 : 10 : Xapian::WritableDatabase db = get_writable_database();
1098 : :
1099 : : {
1100 : 10 : Xapian::Document doc;
1101 : 10 : doc.add_posting("hello", 1);
1102 : 10 : doc.add_posting("world", 2);
1103 : :
1104 : 10 : Xapian::docid did = db.add_document(doc);
1105 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
1106 : 10 : db.commit();
1107 : : }
1108 : :
1109 : : {
1110 : 10 : Xapian::Document doc = db.get_document(1);
1111 [ - + # # ]: 10 : TEST(db.has_positions());
1112 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
1113 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
1114 : 10 : db.replace_document(1, doc);
1115 : 10 : db.commit();
1116 : :
1117 [ - + # # ]: 10 : TEST(db.has_positions());
1118 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
1119 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
1120 : : }
1121 : :
1122 : : // Brass, chert and flint now spot simple cases of replacing the same
1123 : : // document and don't do needless work. Force them to actually do the
1124 : : // replacement to make sure that case works.
1125 : :
1126 : : {
1127 : 10 : Xapian::Document doc;
1128 : 10 : doc.add_term("Q2");
1129 : 10 : db.add_document(doc);
1130 : 10 : db.commit();
1131 : : }
1132 : :
1133 : : {
1134 : 10 : Xapian::Document doc = db.get_document(1);
1135 [ - + # # ]: 10 : TEST(db.has_positions());
1136 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
1137 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
1138 : 10 : (void)db.get_document(2);
1139 : 10 : db.replace_document(1, doc);
1140 : 10 : db.commit();
1141 : :
1142 [ - + # # ]: 10 : TEST(db.has_positions());
1143 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "hello") != db.positionlist_end(1, "hello"));
1144 [ - + ][ # # ]: 10 : TEST(db.positionlist_begin(1, "world") != db.positionlist_end(1, "world"));
1145 : : }
1146 : :
1147 : 10 : return true;
1148 : : }
1149 : :
1150 : : // Test replacing a document while adding values, without changing anything
1151 : : // else. Regression test for a bug introduced while implementing lazy update,
1152 : : // and also covers a few other code paths.
1153 : 10 : DEFINE_TESTCASE(replacedoc6, writable) {
1154 : 10 : Xapian::WritableDatabase db = get_writable_database();
1155 : :
1156 : 10 : Xapian::Document doc;
1157 : 10 : Xapian::docid did = db.add_document(doc);
1158 [ - + # # ]: 10 : TEST_EQUAL(did, 1);
1159 : 10 : db.commit();
1160 : :
1161 : : // Add document
1162 : 10 : doc = db.get_document(1);
1163 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(1), "");
1164 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(2), "");
1165 : 10 : doc.add_value(1, "banana1");
1166 : 10 : db.replace_document(1, doc);
1167 : :
1168 : 10 : doc = db.get_document(1);
1169 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(1), "banana1");
1170 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(2), "");
1171 : 10 : db.commit();
1172 : :
1173 : 10 : doc = db.get_document(1);
1174 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(1), "banana1");
1175 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(2), "");
1176 : 10 : doc.add_value(2, "banana2");
1177 : 10 : db.replace_document(1, doc);
1178 : :
1179 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(1), "banana1");
1180 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(2), "banana2");
1181 : 10 : db.commit();
1182 : :
1183 : 10 : doc = db.get_document(1);
1184 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(1), "banana1");
1185 [ - + ][ # # ]: 10 : TEST_EQUAL(doc.get_value(2), "banana2");
1186 : :
1187 : 10 : return true;
1188 : : }
1189 : :
1190 : : // Test of new feature: WritableDatabase::replace_document and delete_document
1191 : : // can take a unique termname instead of a document id as of Xapian 0.8.2.
1192 : 10 : DEFINE_TESTCASE(uniqueterm1, writable) {
1193 : 10 : Xapian::WritableDatabase db = get_writable_database();
1194 : :
1195 [ + + ]: 210 : for (int n = 1; n <= 20; ++n) {
1196 : 200 : Xapian::Document doc;
1197 : 200 : string uterm = "U" + str(n % 16);
1198 : 200 : doc.add_term(uterm);
1199 : 200 : doc.add_term(str(n));
1200 : 200 : doc.add_term(str(n ^ 9));
1201 : 200 : doc.add_term("all");
1202 : 200 : doc.set_data("pass1");
1203 : 200 : db.add_document(doc);
1204 : : }
1205 : :
1206 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doccount(), 20);
1207 : :
1208 : : static const Xapian::doccount sizes[20] = {
1209 : : 19, 17, 16, 15,
1210 : : 15, 15, 15, 15,
1211 : : 15, 15, 15, 15,
1212 : : 15, 15, 15, 15,
1213 : : 15, 15, 15, 15
1214 : : };
1215 [ + + ]: 210 : for (int n = 1; n <= 20; ++n) {
1216 : 200 : string uterm = "U" + str(n % 16);
1217 [ + + ]: 200 : if (uterm == "U2") {
1218 : 20 : db.delete_document(uterm);
1219 : : } else {
1220 : 180 : Xapian::Document doc;
1221 : 180 : doc.add_term(uterm);
1222 : 180 : doc.add_term(str(n));
1223 : 180 : doc.add_term(str(n ^ 9));
1224 : 180 : doc.add_term("all");
1225 : 180 : doc.set_data("pass2");
1226 : 180 : db.replace_document(uterm, doc);
1227 : : }
1228 [ - + ][ # # ]: 200 : TEST_EQUAL(db.get_doccount(), sizes[n - 1]);
1229 : : }
1230 : :
1231 : 10 : string uterm = "U571";
1232 : 10 : Xapian::Document doc;
1233 : 10 : doc.add_term(uterm);
1234 : 10 : doc.set_data("pass3");
1235 : 10 : db.replace_document(uterm, doc);
1236 : :
1237 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 16);
1238 : :
1239 : 10 : db.delete_document("U2");
1240 : :
1241 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 16);
1242 : :
1243 : 10 : return true;
1244 : : }
1245 : :
1246 : : // tests all document postlists
1247 : 10 : DEFINE_TESTCASE(allpostlist2, writable) {
1248 : 10 : Xapian::WritableDatabase db(get_writable_database("apitest_manydocs"));
1249 : 10 : Xapian::PostingIterator i = db.postlist_begin("");
1250 : 10 : unsigned int j = 1;
1251 [ + + ]: 5130 : while (i != db.postlist_end("")) {
1252 [ - + ][ # # ]: 5120 : TEST_EQUAL(*i, j);
1253 : 5120 : i++;
1254 : 5120 : j++;
1255 : : }
1256 [ - + ][ # # ]: 10 : TEST_EQUAL(j, 513);
1257 : :
1258 : 10 : db.delete_document(1);
1259 : 10 : db.delete_document(50);
1260 : 10 : db.delete_document(512);
1261 : :
1262 : 10 : i = db.postlist_begin("");
1263 : 10 : j = 2;
1264 [ + + ]: 5100 : while (i != db.postlist_end("")) {
1265 [ - + ][ # # ]: 5090 : TEST_EQUAL(*i, j);
1266 : 5090 : i++;
1267 : 5090 : j++;
1268 [ + + ]: 5090 : if (j == 50) j++;
1269 : : }
1270 [ - + ][ # # ]: 10 : TEST_EQUAL(j, 512);
1271 : :
1272 : 10 : i = db.postlist_begin("");
1273 : 10 : j = 2;
1274 [ + + ]: 5000 : while (i != db.postlist_end("")) {
1275 [ - + ][ # # ]: 4990 : TEST_EQUAL(*i, j);
1276 : 4990 : i++;
1277 : 4990 : j++;
1278 [ + + ]: 4990 : if (j == 40) {
1279 : 10 : j += 10;
1280 : 10 : i.skip_to(j);
1281 : 10 : j++;
1282 : : }
1283 : : }
1284 [ - + ][ # # ]: 10 : TEST_EQUAL(j, 512);
1285 : :
1286 : 10 : return true;
1287 : : }
1288 : :
1289 : 70 : static void test_emptyterm2_helper(Xapian::WritableDatabase & db)
1290 : : {
1291 : : // Don't bother with postlist_begin() because allpostlist tests cover that.
1292 [ + - ][ - + ]: 280 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.positionlist_begin(1, ""));
[ # # ][ - + ]
1293 [ - + ][ # # ]: 70 : TEST_EQUAL(db.get_doccount(), db.get_termfreq(""));
1294 [ - + ][ # # ]: 70 : TEST_EQUAL(db.get_doccount() != 0, db.term_exists(""));
1295 [ - + ][ # # ]: 70 : TEST_EQUAL(db.get_doccount(), db.get_collection_freq(""));
1296 : 70 : }
1297 : :
1298 : : // tests results of passing an empty term to various methods
1299 : : // equivalent of emptyterm1 for a writable database
1300 : 10 : DEFINE_TESTCASE(emptyterm2, writable) {
1301 : : {
1302 : 10 : Xapian::WritableDatabase db(get_writable_database("apitest_manydocs"));
1303 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 512);
1304 : 10 : test_emptyterm2_helper(db);
1305 : 10 : db.delete_document(1);
1306 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 511);
1307 : 10 : test_emptyterm2_helper(db);
1308 : 10 : db.delete_document(50);
1309 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 510);
1310 : 10 : test_emptyterm2_helper(db);
1311 : 10 : db.delete_document(512);
1312 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 509);
1313 : 10 : test_emptyterm2_helper(db);
1314 : : }
1315 : :
1316 : : {
1317 : 10 : Xapian::WritableDatabase db(get_writable_database("apitest_onedoc"));
1318 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 1);
1319 : 10 : test_emptyterm2_helper(db);
1320 : 10 : db.delete_document(1);
1321 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
1322 : 10 : test_emptyterm2_helper(db);
1323 : : }
1324 : :
1325 : : {
1326 : 10 : Xapian::WritableDatabase db(get_writable_database());
1327 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
1328 : 10 : test_emptyterm2_helper(db);
1329 : : }
1330 : :
1331 : 10 : return true;
1332 : : }
1333 : :
1334 : : // Check that PHRASE/NEAR becomes AND if there's no positional info in the
1335 : : // database.
1336 : 10 : DEFINE_TESTCASE(phraseorneartoand1, writable) {
1337 : 10 : Xapian::WritableDatabase db = get_writable_database();
1338 : :
1339 [ + + ]: 210 : for (int n = 1; n <= 20; ++n) {
1340 : 200 : Xapian::Document doc;
1341 : 200 : doc.add_term(str(n));
1342 : 200 : doc.add_term(str(n ^ 9));
1343 : 200 : doc.add_term("all");
1344 : 200 : doc.set_data("pass1");
1345 : 200 : db.add_document(doc);
1346 : : }
1347 : 10 : db.commit();
1348 : :
1349 : 10 : Xapian::Enquire enquire(db);
1350 : 10 : Xapian::MSet mymset;
1351 : :
1352 : 10 : const char * q1[] = { "all", "1" };
1353 : 10 : enquire.set_query(Xapian::Query(Xapian::Query::OP_PHRASE, q1, q1 + 2));
1354 : 10 : mymset = enquire.get_mset(0, 10);
1355 [ - + # # ]: 10 : TEST_EQUAL(2, mymset.size());
1356 : :
1357 : 10 : enquire.set_query(Xapian::Query(Xapian::Query::OP_NEAR, q1, q1 + 2));
1358 : 10 : mymset = enquire.get_mset(0, 10);
1359 [ - + # # ]: 10 : TEST_EQUAL(2, mymset.size());
1360 : :
1361 : 10 : const char * q2[] = { "1", "2" };
1362 : 10 : enquire.set_query(Xapian::Query(Xapian::Query::OP_PHRASE, q2, q2 + 2));
1363 : 10 : mymset = enquire.get_mset(0, 10);
1364 [ - + # # ]: 10 : TEST_EQUAL(0, mymset.size());
1365 : :
1366 : 10 : enquire.set_query(Xapian::Query(Xapian::Query::OP_NEAR, q2, q2 + 2));
1367 : 10 : mymset = enquire.get_mset(0, 10);
1368 [ - + # # ]: 10 : TEST_EQUAL(0, mymset.size());
1369 : :
1370 : 10 : return true;
1371 : : }
1372 : :
1373 : : // Check that a large number of position list entries for a particular term
1374 : : // works - regression test for flint.
1375 : 10 : DEFINE_TESTCASE(longpositionlist1, writable) {
1376 : 10 : Xapian::WritableDatabase db = get_writable_database();
1377 : :
1378 : 10 : Xapian::Document doc;
1379 : : Xapian::termpos n;
1380 [ + + ]: 20010 : for (n = 1; n <= 2000; ++n) {
1381 : 20000 : doc.add_posting("fork", n * 3);
1382 : 20000 : doc.add_posting("knife", n * unsigned(log(double(n + 2))));
1383 : 20000 : doc.add_posting("spoon", n * n);
1384 : : }
1385 : 10 : doc.set_data("cutlery");
1386 : 10 : Xapian::docid did = db.add_document(doc);
1387 : 10 : db.commit();
1388 : :
1389 : 10 : doc = db.get_document(did);
1390 : :
1391 : 10 : Xapian::TermIterator t, tend;
1392 : 10 : Xapian::PositionIterator p, pend;
1393 : :
1394 : 10 : t = doc.termlist_begin();
1395 : 10 : tend = doc.termlist_end();
1396 : :
1397 [ - + # # ]: 10 : TEST(t != tend);
1398 [ - + ][ # # ]: 10 : TEST_EQUAL(*t, "fork");
1399 : 10 : p = t.positionlist_begin();
1400 : 10 : pend = t.positionlist_end();
1401 [ + + ]: 20010 : for (n = 1; n <= 2000; ++n) {
1402 [ - + ][ # # ]: 20000 : TEST(p != pend);
1403 [ - + ][ # # ]: 20000 : TEST_EQUAL(*p, n * 3);
1404 : 20000 : ++p;
1405 : : }
1406 [ - + ][ # # ]: 10 : TEST(p == pend);
1407 : :
1408 : 10 : ++t;
1409 [ - + # # ]: 10 : TEST(t != tend);
1410 [ - + ][ # # ]: 10 : TEST_EQUAL(*t, "knife");
1411 : 10 : p = t.positionlist_begin();
1412 : 10 : pend = t.positionlist_end();
1413 [ + + ]: 20010 : for (n = 1; n <= 2000; ++n) {
1414 [ - + ][ # # ]: 20000 : TEST(p != pend);
1415 [ - + ][ # # ]: 20000 : TEST_EQUAL(*p, n * unsigned(log(double(n + 2))));
1416 : 20000 : ++p;
1417 : : }
1418 [ - + ][ # # ]: 10 : TEST(p == pend);
1419 : :
1420 : 10 : ++t;
1421 [ - + # # ]: 10 : TEST(t != tend);
1422 [ - + ][ # # ]: 10 : TEST_EQUAL(*t, "spoon");
1423 : 10 : p = t.positionlist_begin();
1424 : 10 : pend = t.positionlist_end();
1425 [ + + ]: 20010 : for (n = 1; n <= 2000; ++n) {
1426 [ - + ][ # # ]: 20000 : TEST(p != pend);
1427 [ - + ][ # # ]: 20000 : TEST_EQUAL(*p, n * n);
1428 : 20000 : ++p;
1429 : : }
1430 [ - + ][ # # ]: 10 : TEST(p == pend);
1431 : :
1432 : 10 : ++t;
1433 [ - + # # ]: 10 : TEST(t == tend);
1434 : :
1435 : 10 : return true;
1436 : : }
1437 : :
1438 : : // Regression test for bug#110: Inconsistent sort order between pages with
1439 : : // set_sort_by_value_then_relevance.
1440 : 10 : DEFINE_TESTCASE(consistency2, writable) {
1441 : 10 : Xapian::WritableDatabase db = get_writable_database();
1442 : 10 : char buf[2] = "X";
1443 : 10 : int i = 0;
1444 : :
1445 : : // Add 5 documents indexed by "test" with wdf 1.
1446 [ + + ]: 60 : for (i = 0; i < 5; ++i) {
1447 : 50 : Xapian::Document doc;
1448 : 50 : *buf = '0' + i;
1449 : 50 : doc.add_value(0, buf);
1450 : 50 : doc.add_term("test");
1451 : 50 : db.add_document(doc);
1452 : : }
1453 : :
1454 : : // Add 5 documents indexed by "test" with wdf 2.
1455 [ + + ]: 60 : for (i = 0; i < 5; ++i) {
1456 : 50 : Xapian::Document doc;
1457 : 50 : *buf = '0' + i;
1458 : 50 : doc.add_value(0, buf);
1459 : 50 : doc.add_term("test", 2);
1460 : 50 : db.add_document(doc);
1461 : : }
1462 : :
1463 : 10 : db.commit();
1464 : :
1465 : 10 : Xapian::Enquire enq(db);
1466 : 10 : enq.set_query(Xapian::Query("test"));
1467 : :
1468 : 10 : enq.set_sort_by_value_then_relevance(0, true);
1469 : :
1470 : : // 10 results, unpaged.
1471 : 10 : Xapian::MSet mset1 = enq.get_mset(0, 10);
1472 [ - + # # ]: 10 : TEST_EQUAL(mset1.size(), 10);
1473 : :
1474 : : // 10 results, split.
1475 : 10 : Xapian::MSet mset2a = enq.get_mset(0, 1);
1476 [ - + # # ]: 10 : TEST_EQUAL(mset2a.size(), 1);
1477 : 10 : Xapian::MSet mset2b = enq.get_mset(1, 1);
1478 [ - + # # ]: 10 : TEST_EQUAL(mset2b.size(), 1);
1479 : 10 : Xapian::MSet mset2c = enq.get_mset(2, 8);
1480 [ - + # # ]: 10 : TEST_EQUAL(mset2c.size(), 8);
1481 : :
1482 [ - + ][ # # ]: 10 : TEST_EQUAL(*mset1[0], *mset2a[0]);
1483 [ - + ][ # # ]: 10 : TEST_EQUAL(*mset1[1], *mset2b[0]);
1484 [ + + ]: 90 : for (i = 0; i < 8; ++i) {
1485 [ - + ][ # # ]: 80 : TEST_EQUAL(*mset1[i + 2], *mset2c[i]);
1486 : : }
1487 : :
1488 : 10 : return true;
1489 : : }
1490 : :
1491 : 3 : DEFINE_TESTCASE(crashrecovery1, brass || chert || flint) {
1492 : 3 : const string & dbtype = get_dbtype();
1493 : 3 : string path = ".";
1494 : 3 : path += dbtype;
1495 : 3 : path += "/dbw";
1496 : 3 : const char * base_ext = ".baseB";
1497 : :
1498 : 3 : Xapian::Document doc;
1499 : : {
1500 : 3 : Xapian::WritableDatabase db = get_writable_database();
1501 : 3 : Xapian::Database dbr(get_writable_database_as_database());
1502 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 0);
1503 : :
1504 : : // Xapian::Database has full set of baseA, no baseB
1505 : :
1506 : 3 : db.add_document(doc);
1507 : 3 : db.commit();
1508 : 3 : dbr.reopen();
1509 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 1);
1510 : :
1511 : : // Xapian::Database has full set of baseB, old baseA
1512 : :
1513 : 3 : db.add_document(doc);
1514 : 3 : db.commit();
1515 : 3 : dbr.reopen();
1516 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 2);
1517 : :
1518 : : // Xapian::Database has full set of baseA, old baseB
1519 : :
1520 : : // Simulate a transaction starting, some of the baseB getting removed,
1521 : : // but then the transaction fails.
1522 : 3 : unlink(path + "/record" + base_ext);
1523 : 3 : unlink(path + "/termlist" + base_ext);
1524 : :
1525 : 3 : dbr.reopen();
1526 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 2);
1527 : : }
1528 : :
1529 : 3 : Xapian::WritableDatabase db(path, Xapian::DB_OPEN);
1530 : : // Xapian::Database has full set of baseA, some old baseB
1531 : 3 : Xapian::Database dbr = Xapian::Database(path);
1532 : :
1533 : 3 : db.add_document(doc);
1534 : 3 : db.commit();
1535 : 3 : dbr.reopen();
1536 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 3);
1537 : :
1538 : : // Xapian::Database has full set of baseB, old baseA
1539 : :
1540 : 3 : db.add_document(doc);
1541 : 3 : db.commit();
1542 : 3 : dbr.reopen();
1543 [ - + # # ]: 3 : TEST_EQUAL(dbr.get_doccount(), 4);
1544 : :
1545 : 3 : return true;
1546 : : }
1547 : :
1548 : : // Check that DatabaseError is thrown if the docid counter would wrap.
1549 : : // Regression test for bug#152.
1550 : 10 : DEFINE_TESTCASE(nomoredocids1, writable) {
1551 : : // The InMemory backend uses a vector for the documents, so trying to add
1552 : : // document "-1" will fail because we can't allocate enough memory!
1553 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
1554 : :
1555 : 9 : Xapian::WritableDatabase db = get_writable_database();
1556 : 9 : Xapian::Document doc;
1557 : 9 : doc.set_data("prose");
1558 : 9 : doc.add_term("word");
1559 : :
1560 : 9 : db.replace_document(Xapian::docid(-1), doc);
1561 : :
1562 [ + - ][ - + ]: 18 : TEST_EXCEPTION(Xapian::DatabaseError, db.add_document(doc));
[ # # ][ - + ]
1563 : :
1564 : 9 : return true;
1565 : : }
1566 : :
1567 : : // Test synonym iterators.
1568 : 3 : DEFINE_TESTCASE(synonymitor1, writable && synonyms) {
1569 : 3 : Xapian::WritableDatabase db = get_writable_database();
1570 : :
1571 : : // Test iterators for terms which aren't there.
1572 [ - + ][ # # ]: 3 : TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
1573 : :
1574 : : // Test iterating the synonym keys when there aren't any.
1575 [ - + ][ # # ]: 3 : TEST(db.synonym_keys_begin() == db.synonym_keys_end());
1576 : :
1577 : 3 : db.add_synonym("hello", "howdy");
1578 : 3 : db.add_synonym("hello", "hi");
1579 : 3 : db.add_synonym("goodbye", "bye");
1580 : 3 : db.add_synonym("goodbye", "farewell");
1581 : :
1582 : 3 : Xapian::TermIterator t;
1583 : 3 : string s;
1584 : :
1585 : : // Try these tests twice - once before committing and once after.
1586 [ + + ]: 9 : for (int times = 1; times <= 2; ++times) {
1587 : : // Test iterators for terms which aren't there.
1588 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
1589 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("ghi") == db.synonyms_end("ghi"));
1590 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("zzzzz") == db.synonyms_end("zzzzz"));
1591 : :
1592 : 6 : s = "|";
1593 : 6 : t = db.synonyms_begin("hello");
1594 [ + + ]: 18 : while (t != db.synonyms_end("hello")) {
1595 : 12 : s += *t++;
1596 : 12 : s += '|';
1597 : : }
1598 [ - + ][ # # ]: 6 : TEST_STRINGS_EQUAL(s, "|hi|howdy|");
1599 : :
1600 : 6 : s = "|";
1601 : 6 : t = db.synonyms_begin("goodbye");
1602 [ + + ]: 18 : while (t != db.synonyms_end("goodbye")) {
1603 : 12 : s += *t++;
1604 : 12 : s += '|';
1605 : : }
1606 [ - + ][ # # ]: 6 : TEST_STRINGS_EQUAL(s, "|bye|farewell|");
1607 : :
1608 : 6 : s = "|";
1609 : 6 : t = db.synonym_keys_begin();
1610 [ + + ]: 18 : while (t != db.synonym_keys_end()) {
1611 : 12 : s += *t++;
1612 : 12 : s += '|';
1613 : : }
1614 [ - + ][ # # ]: 6 : TEST_STRINGS_EQUAL(s, "|goodbye|hello|");
1615 : :
1616 : 6 : db.commit();
1617 : : }
1618 : :
1619 : : // Delete a synonym for "hello" and all synonyms for "goodbye".
1620 : 3 : db.remove_synonym("hello", "hi");
1621 : 3 : db.clear_synonyms("goodbye");
1622 : :
1623 : : // Try these tests twice - once before committing and once after.
1624 [ + + ]: 9 : for (int times = 1; times <= 2; ++times) {
1625 : : // Test iterators for terms which aren't there.
1626 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("abc") == db.synonyms_end("abc"));
1627 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("ghi") == db.synonyms_end("ghi"));
1628 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("zzzzz") == db.synonyms_end("zzzzz"));
1629 : :
1630 : 6 : s = "|";
1631 : 6 : t = db.synonyms_begin("hello");
1632 [ + + ]: 12 : while (t != db.synonyms_end("hello")) {
1633 : 6 : s += *t++;
1634 : 6 : s += '|';
1635 : : }
1636 [ - + ][ # # ]: 6 : TEST_STRINGS_EQUAL(s, "|howdy|");
1637 : :
1638 [ - + ][ # # ]: 6 : TEST(db.synonyms_begin("goodbye") == db.synonyms_end("goodbye"));
1639 : :
1640 : 6 : s = "|";
1641 : 6 : t = db.synonym_keys_begin();
1642 [ + + ]: 12 : while (t != db.synonym_keys_end()) {
1643 : 6 : s += *t++;
1644 : 6 : s += '|';
1645 : : }
1646 [ - + ][ # # ]: 6 : TEST_STRINGS_EQUAL(s, "|hello|");
1647 : :
1648 : 6 : db.commit();
1649 : : }
1650 : :
1651 : 3 : Xapian::Database db_multi;
1652 : 3 : db_multi.add_database(db);
1653 : 3 : db_multi.add_database(get_database("apitest_simpledata"));
1654 : :
1655 : : // Test iterators for terms which aren't there.
1656 [ - + ][ # # ]: 3 : TEST(db_multi.synonyms_begin("abc") == db_multi.synonyms_end("abc"));
1657 [ - + ][ # # ]: 3 : TEST(db_multi.synonyms_begin("ghi") == db_multi.synonyms_end("ghi"));
1658 [ - + ][ # # ]: 3 : TEST(db_multi.synonyms_begin("zzzzz") == db_multi.synonyms_end("zzzzz"));
1659 : :
1660 : 3 : s = "|";
1661 : 3 : t = db_multi.synonyms_begin("hello");
1662 [ + + ]: 6 : while (t != db_multi.synonyms_end("hello")) {
1663 : 3 : s += *t++;
1664 : 3 : s += '|';
1665 : : }
1666 [ - + ][ # # ]: 3 : TEST_STRINGS_EQUAL(s, "|howdy|");
1667 : :
1668 [ - + ][ # # ]: 3 : TEST(db_multi.synonyms_begin("goodbye") == db_multi.synonyms_end("goodbye"));
1669 : :
1670 : 3 : s = "|";
1671 : 3 : t = db_multi.synonym_keys_begin();
1672 [ + + ]: 6 : while (t != db_multi.synonym_keys_end()) {
1673 : 3 : s += *t++;
1674 : 3 : s += '|';
1675 : : }
1676 [ - + ][ # # ]: 3 : TEST_STRINGS_EQUAL(s, "|hello|");
1677 : :
1678 : 3 : return true;
1679 : : }
1680 : :
1681 : : // Test that adding a document with a really long term gives an error on
1682 : : // add_document() rather than on commit().
1683 : 10 : DEFINE_TESTCASE(termtoolong1, writable) {
1684 : : // Inmemory doesn't impose a limit.
1685 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
1686 : :
1687 : 9 : Xapian::WritableDatabase db = get_writable_database();
1688 : :
1689 [ + + ]: 414 : for (Xapian::doccount i = 246; i <= 290; ++i) {
1690 : 405 : tout.str(string());
1691 : 405 : tout << "Term length " << i << endl;
1692 : 405 : Xapian::Document doc;
1693 : 405 : string term(i, 'X');
1694 : 405 : doc.add_term(term);
1695 : : try {
1696 : 405 : db.add_document(doc);
1697 [ # # ]: 0 : TEST_AND_EXPLAIN(false, "Expecting exception InvalidArgumentError");
1698 : 810 : } catch (const Xapian::InvalidArgumentError &e) {
1699 : : // Check that the max length is correctly expressed in the
1700 : : // exception message - we've got this wrong in two different ways
1701 : : // in the past!
1702 : 405 : tout << e.get_msg() << endl;
1703 [ - + # # ]: 405 : TEST(e.get_msg().find("Term too long (> 245)") != string::npos);
1704 : : }
1705 : : }
1706 : :
1707 [ + + ]: 63 : for (Xapian::doccount j = 240; j <= 245; ++j) {
1708 : 54 : tout.str(string());
1709 : 54 : tout << "Term length " << j << endl;
1710 : 54 : Xapian::Document doc;
1711 : 54 : string term(j, 'X');
1712 : 54 : doc.add_term(term);
1713 : 54 : db.add_document(doc);
1714 : : }
1715 : :
1716 : 9 : db.commit();
1717 : :
1718 : : {
1719 : : // Currently brass, flint and chert escape zero bytes from terms in
1720 : : // keys for some tables, so a term with 127 zero bytes won't work
1721 : : // either.
1722 : 9 : Xapian::Document doc;
1723 : 9 : doc.add_term(string(127, '\0'));
1724 : 9 : db.add_document(doc);
1725 : : try {
1726 : 9 : db.commit();
1727 [ # # ]: 0 : TEST_AND_EXPLAIN(false, "Expecting exception InvalidArgumentError");
1728 : 18 : } catch (const Xapian::InvalidArgumentError &e) {
1729 : : // Check that the max length is correctly expressed in the
1730 : : // exception message - we've got this wrong in two different ways
1731 : : // in the past!
1732 : 9 : tout << e.get_msg() << endl;
1733 [ - + # # ]: 9 : TEST(e.get_msg().find(" is 252 bytes") != string::npos);
1734 : 9 : }
1735 : : }
1736 : :
1737 : 9 : return true;
1738 : : }
1739 : :
1740 : : /// Test playing with a postlist
1741 : 10 : DEFINE_TESTCASE(postlist7, writable) {
1742 : 10 : Xapian::WritableDatabase db_w = get_writable_database();
1743 : :
1744 : : {
1745 : 10 : Xapian::Document doc;
1746 : 10 : doc.add_term("foo", 3);
1747 : 10 : doc.add_term("zz", 4);
1748 : 10 : db_w.replace_document(5, doc);
1749 : : }
1750 : :
1751 : 10 : Xapian::PostingIterator p;
1752 : 10 : p = db_w.postlist_begin("foo");
1753 [ - + ][ # # ]: 10 : TEST(p != db_w.postlist_end("foo"));
1754 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 5);
1755 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_wdf(), 3);
1756 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 7);
1757 : 10 : ++p;
1758 [ - + ][ # # ]: 10 : TEST(p == db_w.postlist_end("foo"));
1759 : :
1760 : : {
1761 : 10 : Xapian::Document doc;
1762 : 10 : doc.add_term("foo", 1);
1763 : 10 : doc.add_term("zz", 1);
1764 : 10 : db_w.replace_document(6, doc);
1765 : : }
1766 : :
1767 : 10 : p = db_w.postlist_begin("foo");
1768 [ - + ][ # # ]: 10 : TEST(p != db_w.postlist_end("foo"));
1769 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 5);
1770 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_wdf(), 3);
1771 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 7);
1772 : 10 : ++p;
1773 [ - + ][ # # ]: 10 : TEST(p != db_w.postlist_end("foo"));
1774 [ - + ][ # # ]: 10 : TEST_EQUAL(*p, 6);
1775 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_wdf(), 1);
1776 [ - + ][ # # ]: 10 : TEST_EQUAL(p.get_doclength(), 2);
1777 : 10 : ++p;
1778 [ - + ][ # # ]: 10 : TEST(p == db_w.postlist_end("foo"));
1779 : :
1780 : 10 : return true;
1781 : : }
1782 : :
1783 : 3 : DEFINE_TESTCASE(lazytablebug1, brass || chert || flint) {
1784 : : {
1785 : 3 : Xapian::WritableDatabase db = get_named_writable_database("lazytablebug1", string());
1786 : :
1787 : 3 : Xapian::Document doc;
1788 : 3 : doc.add_term("foo");
1789 : 3 : db.add_document(doc);
1790 : 3 : db.commit();
1791 : :
1792 : 3 : string synonym(255, 'x');
1793 : 3 : char buf[] = " iamafish!!!!!!!!!!";
1794 [ + + ]: 264 : for (int i = 33; i < 120; ++i) {
1795 : 261 : db.add_synonym(buf, synonym);
1796 : 261 : ++buf[0];
1797 : : }
1798 : :
1799 : 3 : db.commit();
1800 : : }
1801 : :
1802 : 3 : Xapian::Database db = get_writable_database_as_database();
1803 [ + + ]: 264 : for (Xapian::TermIterator t = db.synonym_keys_begin(); t != db.synonym_keys_end(); ++t) {
1804 : 261 : tout << *t << endl;
1805 : 3 : }
1806 : :
1807 : 3 : return true;
1808 : : }
1809 : :
1810 : : /** Regression test for bug #287 for flint.
1811 : : *
1812 : : * Chert also has the same duff code but this testcase doesn't actually
1813 : : * tickle the bug there.
1814 : : */
1815 : 3 : DEFINE_TESTCASE(cursordelbug1, brass || chert || flint) {
1816 : : static const int terms[] = { 219, 221, 222, 223, 224, 225, 226 };
1817 : : static const int copies[] = { 74, 116, 199, 21, 45, 155, 189 };
1818 : :
1819 : 3 : Xapian::WritableDatabase db;
1820 : 3 : db = get_named_writable_database("cursordelbug1", string());
1821 : :
1822 [ + + ]: 24 : for (size_t i = 0; i < sizeof(terms) / sizeof(terms[0]); ++i) {
1823 : 21 : Xapian::Document doc;
1824 : 21 : doc.add_term("XC" + str(terms[i]));
1825 : 21 : doc.add_term("XTabc");
1826 : 21 : doc.add_term("XAdef");
1827 : 21 : doc.add_term("XRghi");
1828 : 21 : doc.add_term("XYabc");
1829 : 21 : size_t c = copies[i];
1830 [ + + ]: 2418 : while (c--) db.add_document(doc);
1831 : : }
1832 : :
1833 : 3 : db.commit();
1834 : :
1835 [ + + ]: 24 : for (size_t i = 0; i < sizeof(terms) / sizeof(terms[0]); ++i) {
1836 : 21 : db.delete_document("XC" + str(terms[i]));
1837 : : }
1838 : :
1839 : 3 : db.commit();
1840 : :
1841 : 3 : string cmd = XAPIAN_BIN_PATH"xapian-check ";
1842 : 3 : cmd += get_named_writable_database_path("cursordelbug1");
1843 : : #ifdef __WIN32__
1844 : : cmd += " >nul";
1845 : : #else
1846 : 3 : cmd += " >/dev/null";
1847 : : #endif
1848 [ - + ]: 3 : if (system(cmd.c_str()) != 0)
1849 : 0 : return false;
1850 : :
1851 : 3 : return true;
1852 : : }
1853 : :
1854 : : /** Helper function for modifyvalues1.
1855 : : *
1856 : : * Check that the values stored in the database match */
1857 : : static void
1858 : 120 : check_vals(const Xapian::Database & db, const map<Xapian::docid, string> & vals)
1859 : : {
1860 [ - + ][ # # ]: 120 : TEST_EQUAL(db.get_doccount(), vals.size());
1861 [ - + ]: 120 : if (vals.size() == 0) return;
1862 [ - + ][ # # ]: 120 : TEST_REL(vals.rbegin()->first,<=,db.get_lastdocid());
1863 : 120 : map<Xapian::docid, string>::const_iterator i;
1864 [ + + ]: 120120 : for (i = vals.begin(); i != vals.end(); ++i) {
1865 : 120000 : tout.str(string());
1866 : 120000 : tout << "Checking value in doc " << i->first << " - should be '" << i->second << "'\n";
1867 : 120000 : Xapian::Document doc = db.get_document(i->first);
1868 : 120000 : string dbval = doc.get_value(1);
1869 [ - + # # ]: 120000 : TEST_EQUAL(dbval, i->second);
1870 [ + + ]: 120000 : if (dbval.empty()) {
1871 [ - + ][ # # ]: 23420 : TEST_EQUAL(0, doc.values_count());
1872 [ - + ][ # # ]: 23420 : TEST_EQUAL(doc.values_begin(), doc.values_end());
1873 : : } else {
1874 [ - + ][ # # ]: 96580 : TEST_EQUAL(1, doc.values_count());
1875 : 96580 : Xapian::ValueIterator valit = doc.values_begin();
1876 [ - + # # ]: 96580 : TEST_NOT_EQUAL(valit, doc.values_end());
1877 [ - + ][ # # ]: 96580 : TEST_EQUAL(dbval, *valit);
1878 [ - + ][ # # ]: 96580 : TEST_EQUAL(1, valit.get_valueno());
1879 : 96580 : ++valit;
1880 [ - + # # ]: 96580 : TEST_EQUAL(valit, doc.values_end());
1881 : : }
1882 : : }
1883 : : }
1884 : :
1885 : : /** Regression test for bug in initial streaming values implementation in
1886 : : * chert.
1887 : : */
1888 : 10 : DEFINE_TESTCASE(modifyvalues1, writable) {
1889 : 10 : unsigned int seed = 7;
1890 : 10 : Xapian::WritableDatabase db = get_writable_database();
1891 : : // Note: doccount must be coprime with 13
1892 : 10 : const Xapian::doccount doccount = 1000;
1893 : : STATIC_ASSERT(doccount % 13 != 0);
1894 : :
1895 : 10 : map<Xapian::docid, string> vals;
1896 : :
1897 [ + + ]: 10010 : for (Xapian::doccount num = 1; num <= doccount; ++num) {
1898 : 10000 : tout.str(string());
1899 : 10000 : Xapian::Document doc;
1900 : 10000 : string val = "val" + str(num);
1901 : 10000 : tout << "Setting val '" << val << "' in doc " << num << "\n";
1902 : 10000 : doc.add_value(1, val);
1903 : 10000 : db.add_document(doc);
1904 : 10000 : vals[num] = val;
1905 : : }
1906 : 10 : check_vals(db, vals);
1907 : 10 : db.commit();
1908 : 10 : check_vals(db, vals);
1909 : :
1910 : : // Modify one of the values (this is a regression test which failed with
1911 : : // the initial implementation of streaming values).
1912 : : {
1913 : 10 : Xapian::Document doc;
1914 : 10 : string val = "newval0";
1915 : 10 : tout << "Setting val '" << val << "' in doc 2\n";
1916 : 10 : doc.add_value(1, val);
1917 : 10 : db.replace_document(2, doc);
1918 : 10 : vals[2] = val;
1919 : 10 : check_vals(db, vals);
1920 : 10 : db.commit();
1921 : 10 : check_vals(db, vals);
1922 : : }
1923 : :
1924 : : // Check that value doesn't get lost when replacing a document with itself.
1925 : : {
1926 : 10 : tout << "Replacing document 1 with itself\n";
1927 : 10 : Xapian::Document doc = db.get_document(1);
1928 : 10 : db.replace_document(1, doc);
1929 : 10 : check_vals(db, vals);
1930 : 10 : db.commit();
1931 : 10 : check_vals(db, vals);
1932 : : }
1933 : :
1934 : : // Check that value doesn't get lost when replacing a document with itself,
1935 : : // accessing another document in the meantime. This is a regression test
1936 : : // for a bug in the code which implements lazy updates - this used to
1937 : : // forget the values in the document in this situation.
1938 : : {
1939 : 10 : tout << "Replacing document 1 with itself, after reading doc 2.\n";
1940 : 10 : Xapian::Document doc = db.get_document(1);
1941 : 10 : db.get_document(2);
1942 : 10 : db.replace_document(1, doc);
1943 : 10 : check_vals(db, vals);
1944 : 10 : db.commit();
1945 : 10 : check_vals(db, vals);
1946 : : }
1947 : :
1948 : : // Do some random modifications: seed random generator, for repeatable
1949 : : // results.
1950 : 10 : tout << "Setting seed to " << seed << "\n";
1951 : 10 : srand(seed);
1952 [ + + ]: 20010 : for (Xapian::doccount num = 1; num <= doccount * 2; ++num) {
1953 : 20000 : tout.str(string());
1954 : 20000 : Xapian::docid did = ((rand() >> 8) % doccount) + 1;
1955 : 20000 : Xapian::Document doc;
1956 : 20000 : string val;
1957 : :
1958 [ + + ]: 20000 : if (num % 5 != 0) {
1959 : 16000 : val = "newval" + str(num);
1960 : 16000 : tout << "Setting val '" << val << "' in doc " << did << "\n";
1961 : 16000 : doc.add_value(1, val);
1962 : : } else {
1963 : 4000 : tout << "Adding/replacing empty document " << did << "\n";
1964 : : }
1965 : 20000 : db.replace_document(did, doc);
1966 : 20000 : vals[did] = val;
1967 : : }
1968 : 10 : check_vals(db, vals);
1969 : 10 : db.commit();
1970 : 10 : check_vals(db, vals);
1971 : :
1972 : : // Delete all the remaining values, in a slightly shuffled order.
1973 : : // This is where it's important that doccount is coprime with 13.
1974 [ + + ]: 10010 : for (Xapian::doccount num = 0; num < doccount * 13; num += 13) {
1975 : 10000 : tout.str(string());
1976 : 10000 : Xapian::docid did = (num % doccount) + 1;
1977 : 10000 : tout << "Clearing val in doc " << did << "\n";
1978 : 10000 : Xapian::Document doc;
1979 : 10000 : db.replace_document(did, doc);
1980 : 10000 : vals[did] = string();
1981 : : }
1982 : 10 : check_vals(db, vals);
1983 : 10 : db.commit();
1984 : 10 : check_vals(db, vals);
1985 : :
1986 : 10 : return true;
1987 : : }
|