Branch data Line data Source code
1 : : /* api_db.cc: tests which need a backend
2 : : *
3 : : * Copyright 1999,2000,2001 BrightStation PLC
4 : : * Copyright 2002 Ananova Ltd
5 : : * Copyright 2002,2003,2004,2005,2006,2007,2008,2009 Olly Betts
6 : : * Copyright 2006,2007,2008,2009 Lemur Consulting Ltd
7 : : *
8 : : * This program is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU General Public License as
10 : : * published by the Free Software Foundation; either version 2 of the
11 : : * License, or (at your option) any later version.
12 : : *
13 : : * This program is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with this program; if not, write to the Free Software
20 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
21 : : * USA
22 : : */
23 : :
24 : : #include <config.h>
25 : :
26 : : #include "api_db.h"
27 : :
28 : : #include <algorithm>
29 : : #include <fstream>
30 : : #include <map>
31 : : #include <string>
32 : : #include <vector>
33 : :
34 : : #include <xapian.h>
35 : :
36 : : #include "backendmanager.h"
37 : : #include "backendmanager_local.h"
38 : : #include "testsuite.h"
39 : : #include "testutils.h"
40 : : #include "unixcmds.h"
41 : : #include "utils.h"
42 : :
43 : : #include "apitest.h"
44 : :
45 : : using namespace std;
46 : :
47 : : static Xapian::Query
48 : 10 : query(const string &t)
49 : : {
50 : 10 : return Xapian::Query(Xapian::Stem("english")(t));
51 : : }
52 : :
53 : : // #######################################################################
54 : : // # Tests start here
55 : :
56 : : // tests Xapian::Database::get_termfreq() and Xapian::Database::term_exists()
57 : 13 : DEFINE_TESTCASE(termstats, backend) {
58 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
59 : :
60 [ - + ][ # # ]: 13 : TEST(!db.term_exists("corn"));
61 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_termfreq("corn"), 0);
62 [ - + ][ # # ]: 13 : TEST(db.term_exists("banana"));
63 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_termfreq("banana"), 1);
64 [ - + ][ # # ]: 13 : TEST(db.term_exists("paragraph"));
65 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_termfreq("paragraph"), 5);
66 : :
67 : 13 : return true;
68 : : }
69 : :
70 : : // Check that stub databases work.
71 : 6 : DEFINE_TESTCASE(stubdb1, backend && !inmemory && !remote) {
72 : : // Only works for backends which have a path.
73 : 6 : mkdir(".stub", 0755);
74 : 6 : const char * dbpath = ".stub/stubdb1";
75 : 6 : ofstream out(dbpath);
76 [ - + # # ]: 6 : TEST(out.is_open());
77 : 6 : out << "auto ../" << get_database_path("apitest_simpledata") << endl;
78 : 6 : out.close();
79 : :
80 : : {
81 : 6 : Xapian::Database db = Xapian::Auto::open_stub(dbpath);
82 : 6 : Xapian::Enquire enquire(db);
83 : 6 : enquire.set_query(Xapian::Query("word"));
84 : 6 : enquire.get_mset(0, 10);
85 : : }
86 : : {
87 : 6 : Xapian::Database db(dbpath);
88 : 6 : Xapian::Enquire enquire(db);
89 : 6 : enquire.set_query(Xapian::Query("word"));
90 : 6 : enquire.get_mset(0, 10);
91 : : }
92 : :
93 : 6 : return true;
94 : : }
95 : :
96 : : // Check that stub databases work remotely.
97 : 6 : DEFINE_TESTCASE(stubdb2, backend && !inmemory && !remote) {
98 : : // Only works for backends which have a path.
99 : 6 : mkdir(".stub", 0755);
100 : 6 : const char * dbpath = ".stub/stubdb2";
101 : 6 : ofstream out(dbpath);
102 [ - + # # ]: 6 : TEST(out.is_open());
103 : : out << "remote :" << BackendManager::get_xapian_progsrv_command()
104 : 6 : << ' ' << get_database_path("apitest_simpledata") << endl;
105 : 6 : out.close();
106 : :
107 : : {
108 : 6 : Xapian::Database db = Xapian::Auto::open_stub(dbpath);
109 : 6 : Xapian::Enquire enquire(db);
110 : 6 : enquire.set_query(Xapian::Query("word"));
111 : 6 : enquire.get_mset(0, 10);
112 : : }
113 : : {
114 : 6 : Xapian::Database db(dbpath);
115 : 6 : Xapian::Enquire enquire(db);
116 : 6 : enquire.set_query(Xapian::Query("word"));
117 : 6 : enquire.get_mset(0, 10);
118 : : }
119 : :
120 : 6 : return true;
121 : : }
122 : :
123 : : // Regression test - bad entries were ignored after a good entry prior to 1.0.8.
124 : 6 : DEFINE_TESTCASE(stubdb3, backend && !inmemory && !remote) {
125 : : // Only works for backends which have a path.
126 : 6 : mkdir(".stub", 0755);
127 : 6 : const char * dbpath = ".stub/stubdb3";
128 : 6 : ofstream out(dbpath);
129 [ - + # # ]: 6 : TEST(out.is_open());
130 : : out << "auto ../" << get_database_path("apitest_simpledata") << "\n"
131 : 6 : "bad line here\n";
132 : 6 : out.close();
133 : :
134 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
135 : : Xapian::Database db = Xapian::Auto::open_stub(dbpath));
136 : :
137 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
138 : : Xapian::Database db(dbpath));
139 : :
140 : 6 : return true;
141 : : }
142 : :
143 : : // Test a stub database with just a bad entry.
144 : 6 : DEFINE_TESTCASE(stubdb4, backend && !inmemory && !remote) {
145 : : // Only works for backends which have a path.
146 : 6 : mkdir(".stub", 0755);
147 : 6 : const char * dbpath = ".stub/stubdb4";
148 : 6 : ofstream out(dbpath);
149 [ - + # # ]: 6 : TEST(out.is_open());
150 : 6 : out << "bad line here\n";
151 : 6 : out.close();
152 : :
153 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
154 : : Xapian::Database db = Xapian::Auto::open_stub(dbpath));
155 : :
156 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
157 : : Xapian::Database db(dbpath));
158 : :
159 : 6 : return true;
160 : : }
161 : :
162 : : // Test a stub database with a bad entry with no spaces (prior to 1.1.0 this
163 : : // was deliberately allowed, though not documented.
164 : 6 : DEFINE_TESTCASE(stubdb5, backend && !inmemory && !remote) {
165 : : // Only works for backends which have a path.
166 : 6 : mkdir(".stub", 0755);
167 : 6 : const char * dbpath = ".stub/stubdb5";
168 : 6 : ofstream out(dbpath);
169 [ - + # # ]: 6 : TEST(out.is_open());
170 : : out << "bad\n"
171 : 6 : "auto ../" << get_database_path("apitest_simpledata") << endl;
172 : 6 : out.close();
173 : :
174 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
175 : : Xapian::Database db = Xapian::Auto::open_stub(dbpath));
176 : :
177 [ + - ][ - + ]: 24 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
178 : : Xapian::Database db(dbpath));
179 : :
180 : 6 : return true;
181 : : }
182 : :
183 : : // Test a stub database with an inmemory database (new feature in 1.1.0).
184 : 1 : DEFINE_TESTCASE(stubdb6, inmemory) {
185 : 1 : mkdir(".stub", 0755);
186 : 1 : const char * dbpath = ".stub/stubdb6";
187 : 1 : ofstream out(dbpath);
188 [ - + # # ]: 1 : TEST(out.is_open());
189 : 1 : out << "inmemory\n";
190 : 1 : out.close();
191 : :
192 : : // Read-only tests:
193 : : {
194 : 1 : Xapian::Database db = Xapian::Auto::open_stub(dbpath);
195 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
196 : 1 : Xapian::Enquire enquire(db);
197 : 1 : enquire.set_query(Xapian::Query("word"));
198 : 1 : Xapian::MSet mset = enquire.get_mset(0, 10);
199 [ - + # # ]: 1 : TEST(mset.empty());
200 : : }
201 : : {
202 : 1 : Xapian::Database db(dbpath);
203 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
204 : 1 : Xapian::Enquire enquire(db);
205 : 1 : enquire.set_query(Xapian::Query("word"));
206 : 1 : Xapian::MSet mset = enquire.get_mset(0, 10);
207 [ - + # # ]: 1 : TEST(mset.empty());
208 : : }
209 : :
210 : : // Writable tests:
211 : : {
212 : 1 : Xapian::WritableDatabase db;
213 : 1 : db = Xapian::Auto::open_stub(dbpath, Xapian::DB_OPEN);
214 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
215 : 1 : db.add_document(Xapian::Document());
216 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 1);
217 : : }
218 : : {
219 : 1 : Xapian::WritableDatabase db(dbpath, Xapian::DB_OPEN);
220 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
221 : 1 : db.add_document(Xapian::Document());
222 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 1);
223 : : }
224 : :
225 : 1 : return true;
226 : : }
227 : :
228 : : #if 0 // the "force error" mechanism is no longer in place...
229 : : class MyErrorHandler : public Xapian::ErrorHandler {
230 : : public:
231 : : int count;
232 : :
233 : : bool handle_error(Xapian::Error & error) {
234 : : ++count;
235 : : tout << "Error handling caught: " << error.get_description()
236 : : << ", count is now " << count << "\n";
237 : : return true;
238 : : }
239 : :
240 : : MyErrorHandler() : count (0) {}
241 : : };
242 : :
243 : : // tests error handler in multimatch().
244 : : //DEFINE_TESTCASE(multierrhandler1, backend) {
245 : : MyErrorHandler myhandler;
246 : :
247 : : Xapian::Database mydb2(get_database("apitest_simpledata"));
248 : : Xapian::Database mydb3(get_database("apitest_simpledata2"));
249 : : int errcount = 1;
250 : : for (int testcount = 0; testcount < 14; testcount ++) {
251 : : tout << "testcount=" << testcount << "\n";
252 : : Xapian::Database mydb4(get_database("-e", "apitest_termorder"));
253 : : Xapian::Database mydb5(get_network_database("apitest_termorder", 1));
254 : : Xapian::Database mydb6(get_database("-e2", "apitest_termorder"));
255 : : Xapian::Database mydb7(get_database("-e3", "apitest_simpledata"));
256 : :
257 : : Xapian::Database dbs;
258 : : switch (testcount) {
259 : : case 0:
260 : : dbs.add_database(mydb2);
261 : : dbs.add_database(mydb3);
262 : : dbs.add_database(mydb4);
263 : : break;
264 : : case 1:
265 : : dbs.add_database(mydb4);
266 : : dbs.add_database(mydb2);
267 : : dbs.add_database(mydb3);
268 : : break;
269 : : case 2:
270 : : dbs.add_database(mydb3);
271 : : dbs.add_database(mydb4);
272 : : dbs.add_database(mydb2);
273 : : break;
274 : : case 3:
275 : : dbs.add_database(mydb2);
276 : : dbs.add_database(mydb3);
277 : : dbs.add_database(mydb5);
278 : : sleep(1);
279 : : break;
280 : : case 4:
281 : : dbs.add_database(mydb5);
282 : : dbs.add_database(mydb2);
283 : : dbs.add_database(mydb3);
284 : : sleep(1);
285 : : break;
286 : : case 5:
287 : : dbs.add_database(mydb3);
288 : : dbs.add_database(mydb5);
289 : : dbs.add_database(mydb2);
290 : : sleep(1);
291 : : break;
292 : : case 6:
293 : : dbs.add_database(mydb2);
294 : : dbs.add_database(mydb3);
295 : : dbs.add_database(mydb6);
296 : : break;
297 : : case 7:
298 : : dbs.add_database(mydb6);
299 : : dbs.add_database(mydb2);
300 : : dbs.add_database(mydb3);
301 : : break;
302 : : case 8:
303 : : dbs.add_database(mydb3);
304 : : dbs.add_database(mydb6);
305 : : dbs.add_database(mydb2);
306 : : break;
307 : : case 9:
308 : : dbs.add_database(mydb2);
309 : : dbs.add_database(mydb3);
310 : : dbs.add_database(mydb7);
311 : : break;
312 : : case 10:
313 : : dbs.add_database(mydb7);
314 : : dbs.add_database(mydb2);
315 : : dbs.add_database(mydb3);
316 : : break;
317 : : case 11:
318 : : dbs.add_database(mydb3);
319 : : dbs.add_database(mydb7);
320 : : dbs.add_database(mydb2);
321 : : break;
322 : : case 12:
323 : : dbs.add_database(mydb2);
324 : : dbs.add_database(mydb6);
325 : : dbs.add_database(mydb7);
326 : : break;
327 : : case 13:
328 : : dbs.add_database(mydb2);
329 : : dbs.add_database(mydb7);
330 : : dbs.add_database(mydb6);
331 : : break;
332 : : }
333 : : tout << "db=" << dbs << "\n";
334 : : Xapian::Enquire enquire(dbs, &myhandler);
335 : :
336 : : // make a query
337 : : Xapian::Query myquery = query(Xapian::Query::OP_OR, "inmemory", "word");
338 : : enquire.set_weighting_scheme(Xapian::BoolWeight());
339 : : enquire.set_query(myquery);
340 : :
341 : : tout << "query=" << myquery << "\n";
342 : : // retrieve the top ten results
343 : : Xapian::MSet mymset = enquire.get_mset(0, 10);
344 : :
345 : : switch (testcount) {
346 : : case 0: case 3: case 6: case 9:
347 : : mset_expect_order(mymset, 2, 4, 10);
348 : : break;
349 : : case 1: case 4: case 7: case 10:
350 : : mset_expect_order(mymset, 3, 5, 11);
351 : : break;
352 : : case 2: case 5: case 8: case 11:
353 : : mset_expect_order(mymset, 1, 6, 12);
354 : : break;
355 : : case 12:
356 : : case 13:
357 : : mset_expect_order(mymset, 4, 10);
358 : : errcount += 1;
359 : : break;
360 : : }
361 : : TEST_EQUAL(myhandler.count, errcount);
362 : : errcount += 1;
363 : : }
364 : :
365 : : return true;
366 : : }
367 : : #endif
368 : :
369 [ # # ][ - + ]: 28 : class myMatchDecider : public Xapian::MatchDecider {
370 : : public:
371 : 266 : bool operator()(const Xapian::Document &doc) const {
372 : : // Note that this is not recommended usage of get_data()
373 : 266 : return doc.get_data().find("This is") != string::npos;
374 : : }
375 : : };
376 : :
377 : : // Test Xapian::MatchDecider functor.
378 : 7 : DEFINE_TESTCASE(matchdecider1, backend && !remote) {
379 : 7 : Xapian::Database db(get_database("apitest_simpledata"));
380 : 7 : Xapian::Enquire enquire(db);
381 : 7 : enquire.set_query(Xapian::Query("this"));
382 : :
383 : 7 : myMatchDecider myfunctor;
384 : :
385 : 7 : Xapian::MSet mymset = enquire.get_mset(0, 100, 0, &myfunctor);
386 : :
387 : 7 : vector<bool> docid_checked(db.get_lastdocid());
388 : :
389 : : // Check that we get the expected number of matches, and that they
390 : : // satisfy the condition.
391 : 7 : Xapian::MSetIterator i = mymset.begin();
392 [ - + ][ # # ]: 7 : TEST(i != mymset.end());
393 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.size(), 3);
394 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_matches_lower_bound(), 3);
395 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_matches_upper_bound(), 3);
396 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_matches_estimated(), 3);
397 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 3);
398 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 3);
399 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_uncollapsed_matches_estimated(), 3);
400 [ + + ]: 28 : for ( ; i != mymset.end(); ++i) {
401 : 21 : const Xapian::Document doc(i.get_document());
402 [ - + # # ]: 21 : TEST(myfunctor(doc));
403 : 21 : docid_checked[*i] = true;
404 : : }
405 : :
406 : : // Check that there are some documents which aren't accepted by the match
407 : : // decider.
408 : 7 : mymset = enquire.get_mset(0, 100);
409 [ - + # # ]: 7 : TEST(mymset.size() > 3);
410 : :
411 : : // Check that the bounds are appropriate even if we don't ask for any
412 : : // actual matches.
413 : 7 : mymset = enquire.get_mset(0, 0, 0, &myfunctor);
414 [ - + # # ]: 7 : TEST_EQUAL(mymset.size(), 0);
415 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_matches_lower_bound(), 0);
416 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_matches_upper_bound(), 6);
417 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),>,0);
418 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),<=,6);
419 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_uncollapsed_matches_lower_bound(), 0);
420 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.get_uncollapsed_matches_upper_bound(), 6);
421 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
422 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
423 : :
424 : : // Check that the bounds are appropriate if we ask for only one hit.
425 : : // (Regression test - until SVN 10256, we didn't reduce the lower_bound
426 : : // appropriately, and returned 6 here.)
427 : 7 : mymset = enquire.get_mset(0, 1, 0, &myfunctor);
428 [ - + # # ]: 7 : TEST_EQUAL(mymset.size(), 1);
429 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),>=,1);
430 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),<=,3);
431 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),>=,3);
432 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),<=,6);
433 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),>,0);
434 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),<=,6);
435 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
436 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
437 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
438 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
439 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
440 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
441 : :
442 : : // Check that the other documents don't satisfy the condition.
443 [ + + ]: 42 : for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
444 [ + + ]: 35 : if (!docid_checked[did]) {
445 [ - + ][ # # ]: 14 : TEST(!myfunctor(db.get_document(did)));
446 : : }
447 : : }
448 : :
449 : : // Check that the bounds are appropriate if a collapse key is used.
450 : : // Use a value which is never set so we don't actually discard anything.
451 : 7 : enquire.set_collapse_key(99);
452 : 7 : mymset = enquire.get_mset(0, 1, 0, &myfunctor);
453 [ - + # # ]: 7 : TEST_EQUAL(mymset.size(), 1);
454 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),>=,1);
455 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),<=,3);
456 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),>=,3);
457 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),<=,6);
458 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),>,0);
459 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),<=,6);
460 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
461 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
462 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
463 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
464 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
465 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
466 : :
467 : : // Check that the bounds are appropriate if a percentage cutoff is in
468 : : // use. Set a 1% threshold so we don't actually discard anything.
469 : 7 : enquire.set_collapse_key(Xapian::BAD_VALUENO);
470 : 7 : enquire.set_cutoff(1);
471 : 7 : mymset = enquire.get_mset(0, 1, 0, &myfunctor);
472 [ - + # # ]: 7 : TEST_EQUAL(mymset.size(), 1);
473 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),>=,1);
474 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),<=,3);
475 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),>=,3);
476 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),<=,6);
477 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),>,0);
478 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),<=,6);
479 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
480 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
481 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
482 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
483 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
484 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
485 : :
486 : : // And now with both a collapse key and percentage cutoff.
487 : 7 : enquire.set_collapse_key(99);
488 : 7 : mymset = enquire.get_mset(0, 1, 0, &myfunctor);
489 [ - + # # ]: 7 : TEST_EQUAL(mymset.size(), 1);
490 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),>=,1);
491 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_lower_bound(),<=,3);
492 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),>=,3);
493 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_upper_bound(),<=,6);
494 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),>,0);
495 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_matches_estimated(),<=,6);
496 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),>=,1);
497 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_lower_bound(),<=,3);
498 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),>=,3);
499 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_upper_bound(),<=,6);
500 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),>,0);
501 [ - + ][ # # ]: 7 : TEST_REL(mymset.get_uncollapsed_matches_estimated(),<=,6);
502 : :
503 : 7 : return true;
504 : : }
505 : :
506 : : // Test Xapian::MatchDecider functor used as a match spy.
507 : 7 : DEFINE_TESTCASE(matchdecider2, backend && !remote) {
508 : 7 : Xapian::Database db(get_database("apitest_simpledata"));
509 : 7 : Xapian::Enquire enquire(db);
510 : 7 : enquire.set_query(Xapian::Query("this"));
511 : :
512 : 7 : myMatchDecider myfunctor;
513 : :
514 : 7 : Xapian::MSet mymset = enquire.get_mset(0, 100, 0, NULL, &myfunctor);
515 : :
516 : 7 : vector<bool> docid_checked(db.get_lastdocid());
517 : :
518 : : // Check that we get the expected number of matches, and that they
519 : : // satisfy the condition.
520 : 7 : Xapian::MSetIterator i = mymset.begin();
521 [ - + ][ # # ]: 7 : TEST(i != mymset.end());
522 [ - + ][ # # ]: 7 : TEST_EQUAL(mymset.size(), 3);
523 [ + + ]: 28 : for ( ; i != mymset.end(); ++i) {
524 : 21 : const Xapian::Document doc(i.get_document());
525 [ - + # # ]: 21 : TEST(myfunctor(doc));
526 : 21 : docid_checked[*i] = true;
527 : : }
528 : :
529 : : // Check that the other documents don't satisfy the condition.
530 [ + + ]: 42 : for (Xapian::docid did = 1; did < docid_checked.size(); ++did) {
531 [ + + ]: 35 : if (!docid_checked[did]) {
532 [ - + ][ # # ]: 14 : TEST(!myfunctor(db.get_document(did)));
533 : : }
534 : : }
535 : :
536 : 7 : return true;
537 : : }
538 : :
539 [ # # ][ - + ]: 14 : class myMatchDecider2 : public Xapian::MatchDecider {
540 : : public:
541 : 4116 : bool operator()(const Xapian::Document &doc) const {
542 : : // Note that this is not recommended usage of get_data()
543 : 4116 : return doc.get_data().find("We produce") == string::npos;
544 : : }
545 : : };
546 : :
547 : :
548 : : // Regression test for lower bound using functor, sorting and collapsing.
549 : 7 : DEFINE_TESTCASE(matchdecider3, backend && !remote) {
550 : 7 : Xapian::Database db(get_database("etext"));
551 : 7 : Xapian::Enquire enquire(db);
552 : 7 : enquire.set_query(Xapian::Query(""));
553 : 7 : enquire.set_collapse_key(12);
554 : 7 : enquire.set_sort_by_value(11, true);
555 : :
556 : 7 : myMatchDecider2 myfunctor;
557 : :
558 : 7 : Xapian::MSet mset1 = enquire.get_mset(0, 2, 0, NULL, &myfunctor);
559 : 7 : Xapian::MSet mset2 = enquire.get_mset(0, 1000, 0, NULL, &myfunctor);
560 : :
561 : : // mset2 should contain all the hits, so the statistics should be exact.
562 [ - + # # ]: 7 : TEST_EQUAL(mset2.get_matches_estimated(), mset2.size());
563 [ - + ][ # # ]: 7 : TEST_EQUAL(mset2.get_matches_lower_bound(), mset2.get_matches_estimated());
564 [ - + ][ # # ]: 7 : TEST_EQUAL(mset2.get_matches_estimated(), mset2.get_matches_upper_bound());
565 : :
566 [ - + ][ # # ]: 7 : TEST_REL(mset2.get_uncollapsed_matches_lower_bound(),<=,mset2.get_uncollapsed_matches_estimated());
567 [ - + ][ # # ]: 7 : TEST_REL(mset2.get_uncollapsed_matches_estimated(),<=,mset2.get_uncollapsed_matches_upper_bound());
568 : :
569 : : // Check that the lower bound in mset1 is not greater than the known
570 : : // number of hits. This failed until revision 10811.
571 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_matches_lower_bound(),<=,mset2.size());
572 : :
573 : : // Check that the bounds for mset1 make sense.
574 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_matches_lower_bound(),<=,mset1.get_matches_estimated());
575 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_matches_estimated(),<=,mset1.get_matches_upper_bound());
576 [ - + ][ # # ]: 7 : TEST_REL(mset1.size(),<=,mset1.get_matches_upper_bound());
577 : :
578 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_uncollapsed_matches_lower_bound(),<=,mset1.get_uncollapsed_matches_estimated());
579 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_uncollapsed_matches_estimated(),<=,mset1.get_uncollapsed_matches_upper_bound());
580 : :
581 : : // The uncollapsed match would match all documents but the one the
582 : : // matchdecider rejects.
583 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_uncollapsed_matches_upper_bound(),>=,db.get_doccount() - 1);
584 [ - + ][ # # ]: 7 : TEST_REL(mset1.get_uncollapsed_matches_upper_bound(),<=,db.get_doccount());
585 [ - + ][ # # ]: 7 : TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),>=,db.get_doccount() - 1);
586 [ - + ][ # # ]: 7 : TEST_REL(mset2.get_uncollapsed_matches_upper_bound(),<=,db.get_doccount());
587 : :
588 : 7 : return true;
589 : : }
590 : :
591 : : // tests that mset iterators on msets compare correctly.
592 : 13 : DEFINE_TESTCASE(msetiterator1, backend) {
593 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
594 : 13 : enquire.set_query(Xapian::Query("this"));
595 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 2);
596 : :
597 : 13 : Xapian::MSetIterator j;
598 : 13 : j = mymset.begin();
599 : 13 : Xapian::MSetIterator k = mymset.end();
600 : 13 : Xapian::MSetIterator l(j);
601 : 13 : Xapian::MSetIterator m(k);
602 : 13 : Xapian::MSetIterator n = mymset.begin();
603 : 13 : Xapian::MSetIterator o = mymset.begin();
604 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
605 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(l, m);
606 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
607 [ - + ][ # # ]: 13 : TEST_EQUAL(j, l);
608 [ - + ][ # # ]: 13 : TEST_EQUAL(j, j);
609 [ - + ][ # # ]: 13 : TEST_EQUAL(k, k);
610 : :
611 : 13 : k = j;
612 [ - + # # ]: 13 : TEST_EQUAL(j, k);
613 [ - + ][ # # ]: 13 : TEST_EQUAL(j, o);
614 : 13 : k++;
615 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
616 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, l);
617 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, m);
618 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, o);
619 : 13 : o++;
620 [ - + # # ]: 13 : TEST_EQUAL(k, o);
621 : 13 : k++;
622 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
623 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, l);
624 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
625 [ - + ][ # # ]: 13 : TEST_EQUAL(n, l);
626 : :
627 : 13 : n = m;
628 [ - + # # ]: 13 : TEST_NOT_EQUAL(n, l);
629 [ - + ][ # # ]: 13 : TEST_EQUAL(n, m);
630 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(n, mymset.begin());
631 [ - + ][ # # ]: 13 : TEST_EQUAL(n, mymset.end());
632 : :
633 : 13 : return true;
634 : : }
635 : :
636 : : // tests that mset iterators on empty msets compare equal.
637 : 13 : DEFINE_TESTCASE(msetiterator2, backend) {
638 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
639 : 13 : enquire.set_query(Xapian::Query("this"));
640 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 0);
641 : :
642 : 13 : Xapian::MSetIterator j = mymset.begin();
643 : 13 : Xapian::MSetIterator k = mymset.end();
644 : 13 : Xapian::MSetIterator l(j);
645 : 13 : Xapian::MSetIterator m(k);
646 [ - + # # ]: 13 : TEST_EQUAL(j, k);
647 [ - + ][ # # ]: 13 : TEST_EQUAL(l, m);
648 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
649 [ - + ][ # # ]: 13 : TEST_EQUAL(j, l);
650 [ - + ][ # # ]: 13 : TEST_EQUAL(j, j);
651 [ - + ][ # # ]: 13 : TEST_EQUAL(k, k);
652 : :
653 : 13 : return true;
654 : : }
655 : :
656 : : // tests that begin().get_document() works when first != 0
657 : 13 : DEFINE_TESTCASE(msetiterator3, backend) {
658 : 13 : Xapian::Database mydb(get_database("apitest_simpledata"));
659 : 13 : Xapian::Enquire enquire(mydb);
660 : 13 : enquire.set_query(Xapian::Query("this"));
661 : :
662 : 13 : Xapian::MSet mymset = enquire.get_mset(2, 10);
663 : :
664 [ - + # # ]: 13 : TEST(!mymset.empty());
665 : 13 : Xapian::Document doc(mymset.begin().get_document());
666 [ - + ][ # # ]: 13 : TEST(!doc.get_data().empty());
667 : :
668 : 13 : return true;
669 : : }
670 : :
671 : : // tests that eset iterators on empty esets compare equal.
672 : 13 : DEFINE_TESTCASE(esetiterator1, backend) {
673 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
674 : 13 : enquire.set_query(Xapian::Query("this"));
675 : :
676 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
677 [ - + # # ]: 13 : TEST(mymset.size() >= 2);
678 : :
679 : 13 : Xapian::RSet myrset;
680 : 13 : Xapian::MSetIterator i = mymset.begin();
681 : 13 : myrset.add_document(*i);
682 : 13 : myrset.add_document(*(++i));
683 : :
684 : 13 : Xapian::ESet myeset = enquire.get_eset(2, myrset);
685 : 13 : Xapian::ESetIterator j;
686 : 13 : j = myeset.begin();
687 : 13 : Xapian::ESetIterator k = myeset.end();
688 : 13 : Xapian::ESetIterator l(j);
689 : 13 : Xapian::ESetIterator m(k);
690 : 13 : Xapian::ESetIterator n = myeset.begin();
691 : :
692 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
693 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(l, m);
694 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
695 [ - + ][ # # ]: 13 : TEST_EQUAL(j, l);
696 [ - + ][ # # ]: 13 : TEST_EQUAL(j, j);
697 [ - + ][ # # ]: 13 : TEST_EQUAL(k, k);
698 : :
699 : 13 : k = j;
700 [ - + # # ]: 13 : TEST_EQUAL(j, k);
701 : 13 : k++;
702 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
703 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, l);
704 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, m);
705 : 13 : k++;
706 [ - + # # ]: 13 : TEST_NOT_EQUAL(j, k);
707 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(k, l);
708 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
709 [ - + ][ # # ]: 13 : TEST_EQUAL(n, l);
710 : :
711 : 13 : n = m;
712 [ - + # # ]: 13 : TEST_NOT_EQUAL(n, l);
713 [ - + ][ # # ]: 13 : TEST_EQUAL(n, m);
714 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(n, myeset.begin());
715 [ - + ][ # # ]: 13 : TEST_EQUAL(n, myeset.end());
716 : :
717 : 13 : return true;
718 : : }
719 : :
720 : : // tests that eset iterators on empty esets compare equal.
721 : 13 : DEFINE_TESTCASE(esetiterator2, backend) {
722 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
723 : 13 : enquire.set_query(Xapian::Query("this"));
724 : :
725 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 10);
726 [ - + # # ]: 13 : TEST(mymset.size() >= 2);
727 : :
728 : 13 : Xapian::RSet myrset;
729 : 13 : Xapian::MSetIterator i = mymset.begin();
730 : 13 : myrset.add_document(*i);
731 : 13 : myrset.add_document(*(++i));
732 : :
733 : 13 : Xapian::ESet myeset = enquire.get_eset(0, myrset);
734 : 13 : Xapian::ESetIterator j = myeset.begin();
735 : 13 : Xapian::ESetIterator k = myeset.end();
736 : 13 : Xapian::ESetIterator l(j);
737 : 13 : Xapian::ESetIterator m(k);
738 [ - + # # ]: 13 : TEST_EQUAL(j, k);
739 [ - + ][ # # ]: 13 : TEST_EQUAL(l, m);
740 [ - + ][ # # ]: 13 : TEST_EQUAL(k, m);
741 [ - + ][ # # ]: 13 : TEST_EQUAL(j, l);
742 [ - + ][ # # ]: 13 : TEST_EQUAL(j, j);
743 [ - + ][ # # ]: 13 : TEST_EQUAL(k, k);
744 : :
745 : 13 : return true;
746 : : }
747 : :
748 : : // tests the collapse-on-key
749 : 13 : DEFINE_TESTCASE(collapsekey1, backend) {
750 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
751 : 13 : enquire.set_query(Xapian::Query("this"));
752 : :
753 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
754 : 13 : Xapian::doccount mymsize1 = mymset1.size();
755 : :
756 [ + + ]: 91 : for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
757 : 78 : enquire.set_collapse_key(value_no);
758 : 78 : Xapian::MSet mymset = enquire.get_mset(0, 100);
759 : :
760 [ - + # # ]: 78 : TEST_AND_EXPLAIN(mymsize1 > mymset.size(),
761 : : "Had no fewer items when performing collapse: don't know whether it worked.");
762 : :
763 : 78 : map<string, Xapian::docid> values;
764 : 78 : Xapian::MSetIterator i = mymset.begin();
765 [ + + ]: 286 : for ( ; i != mymset.end(); ++i) {
766 : 208 : string value = i.get_document().get_value(value_no);
767 [ - + # # ]: 208 : TEST(values[value] == 0 || value.empty());
[ - + ][ # # ]
768 : 208 : values[value] = *i;
769 : : }
770 : : }
771 : :
772 : 13 : return true;
773 : : }
774 : :
775 : : // tests that collapse-on-key modifies the predicted bounds for the number of
776 : : // matches appropriately.
777 : 13 : DEFINE_TESTCASE(collapsekey2, backend) {
778 [ - + ]: 13 : SKIP_TEST("Don't have a suitable database currently");
779 : : // FIXME: this needs an appropriate database creating, but that's quite
780 : : // subtle to do it seems.
781 : : Xapian::Enquire enquire(get_database("apitest_simpledata2"));
782 : : enquire.set_query(Xapian::Query("this"));
783 : :
784 : : Xapian::MSet mset1 = enquire.get_mset(0, 1);
785 : :
786 : : // Test that if no duplicates are found, then the upper bound remains
787 : : // unchanged and the lower bound drops.
788 : : {
789 : : enquire.set_query(Xapian::Query("this"));
790 : : Xapian::valueno value_no = 3;
791 : : enquire.set_collapse_key(value_no);
792 : : Xapian::MSet mset = enquire.get_mset(0, 1);
793 : :
794 : : TEST_REL(mset.get_matches_lower_bound(),<,mset1.get_matches_lower_bound());
795 : : TEST_EQUAL(mset.get_matches_upper_bound(), mset1.get_matches_upper_bound());
796 : : }
797 : :
798 : : return true;
799 : : }
800 : :
801 : : // tests that collapse-on-key modifies the predicted bounds for the number of
802 : : // matches appropriately.
803 : 13 : DEFINE_TESTCASE(collapsekey3, backend) {
804 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
805 : 13 : enquire.set_query(Xapian::Query("this"));
806 : :
807 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 3);
808 : :
809 [ + + ]: 91 : for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
810 : 78 : enquire.set_collapse_key(value_no);
811 : 78 : Xapian::MSet mymset = enquire.get_mset(0, 3);
812 : :
813 [ - + # # ]: 78 : TEST_AND_EXPLAIN(mymset1.get_matches_lower_bound() > mymset.get_matches_lower_bound(),
814 : : "Lower bound was not lower when performing collapse: don't know whether it worked.");
815 [ - + ][ # # ]: 78 : TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() > mymset.get_matches_upper_bound(),
816 : : "Upper bound was not lower when performing collapse: don't know whether it worked.");
817 : :
818 : 78 : map<string, Xapian::docid> values;
819 : 78 : Xapian::MSetIterator i = mymset.begin();
820 [ + + ]: 260 : for ( ; i != mymset.end(); ++i) {
821 : 182 : string value = i.get_document().get_value(value_no);
822 [ - + # # ]: 182 : TEST(values[value] == 0 || value.empty());
[ - + ][ # # ]
823 : 182 : values[value] = *i;
824 : : }
825 : : }
826 : :
827 : : // Test that if the collapse value is always empty, then the upper bound
828 : : // remains unchanged, and the lower bound is the same or lower (it can be
829 : : // lower because the matcher counts the number of documents with empty
830 : : // collapse keys, but may have rejected a document because its weight is
831 : : // too low for the proto-MSet before it even looks at its collapse key).
832 : : {
833 : 13 : Xapian::valueno value_no = 1000;
834 : 13 : enquire.set_collapse_key(value_no);
835 : 13 : Xapian::MSet mymset = enquire.get_mset(0, 3);
836 : :
837 [ - + # # ]: 13 : TEST(mymset.get_matches_lower_bound() <= mymset1.get_matches_lower_bound());
838 [ - + ][ # # ]: 13 : TEST_EQUAL(mymset.get_matches_upper_bound(), mymset1.get_matches_upper_bound());
839 : :
840 : 13 : map<string, Xapian::docid> values;
841 : 13 : Xapian::MSetIterator i = mymset.begin();
842 [ + + ]: 52 : for ( ; i != mymset.end(); ++i) {
843 : 39 : string value = i.get_document().get_value(value_no);
844 [ + + - + ]: 39 : TEST(values[value] == 0 || value.empty());
[ - + ][ # # ]
845 : 39 : values[value] = *i;
846 : 13 : }
847 : : }
848 : :
849 : 13 : return true;
850 : : }
851 : :
852 : : // tests that collapse-on-key modifies the predicted bounds for the number of
853 : : // matches appropriately even when no results are requested.
854 : 13 : DEFINE_TESTCASE(collapsekey4, backend) {
855 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
856 : 13 : enquire.set_query(Xapian::Query("this"));
857 : :
858 : 13 : Xapian::MSet mymset1 = enquire.get_mset(0, 0);
859 : :
860 [ + + ]: 91 : for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
861 : 78 : enquire.set_collapse_key(value_no);
862 : 78 : Xapian::MSet mymset = enquire.get_mset(0, 0);
863 : :
864 [ - + # # ]: 78 : TEST_AND_EXPLAIN(mymset.get_matches_lower_bound() == 1,
865 : : "Lower bound was not 1 when performing collapse but not asking for any results.");
866 [ - + ][ # # ]: 78 : TEST_AND_EXPLAIN(mymset1.get_matches_upper_bound() == mymset.get_matches_upper_bound(),
867 : : "Upper bound was changed when performing collapse but not asking for any results.");
868 : :
869 : 78 : map<string, Xapian::docid> values;
870 : 78 : Xapian::MSetIterator i = mymset.begin();
871 [ - + ]: 78 : for ( ; i != mymset.end(); ++i) {
872 : 0 : string value = i.get_document().get_value(value_no);
873 [ # # # # ]: 0 : TEST(values[value] == 0 || value.empty());
[ # # ][ # # ]
874 : 0 : values[value] = *i;
875 : : }
876 : : }
877 : :
878 : 13 : return true;
879 : : }
880 : :
881 : : // test for keepalives
882 : 6 : DEFINE_TESTCASE(keepalive1, remote) {
883 : 6 : Xapian::Database db(get_remote_database("apitest_simpledata", 5000));
884 : :
885 : : /* Test that keep-alives work */
886 [ + + ]: 66 : for (int i = 0; i < 10; ++i) {
887 : 60 : sleep(2);
888 : 60 : db.keep_alive();
889 : : }
890 : 6 : Xapian::Enquire enquire(db);
891 : 6 : enquire.set_query(Xapian::Query("word"));
892 : 6 : enquire.get_mset(0, 10);
893 : :
894 : : /* Test that things break without keepalives */
895 : 6 : sleep(10);
896 : 6 : enquire.set_query(Xapian::Query("word"));
897 [ + - ][ - + ]: 12 : TEST_EXCEPTION(Xapian::NetworkError,
[ # # ][ - + ]
898 : : enquire.get_mset(0, 10));
899 : :
900 : 6 : return true;
901 : : }
902 : :
903 : : // test that iterating through all terms in a database works.
904 : 13 : DEFINE_TESTCASE(allterms1, backend) {
905 : 13 : Xapian::Database db(get_database("apitest_allterms"));
906 : 13 : Xapian::TermIterator ati = db.allterms_begin();
907 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
908 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "one");
909 [ - + ][ # # ]: 13 : TEST_EQUAL(ati.get_termfreq(), 1);
910 : :
911 : 13 : Xapian::TermIterator ati2 = ati;
912 : :
913 : 13 : ati++;
914 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
915 [ - + ]: 13 : if (verbose) {
916 : 0 : tout << "*ati = `" << *ati << "'\n";
917 : 0 : tout << "*ati.length = `" << (*ati).length() << "'\n";
918 : 0 : tout << "*ati == \"one\" = " << (*ati == "one") << "\n";
919 : 0 : tout << "*ati[3] = " << ((*ati)[3]) << "\n";
920 : 0 : tout << "*ati = `" << *ati << "'\n";
921 : : }
922 [ - + ][ # # ]: 13 : TEST(*ati == "three");
923 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 3);
924 : :
925 : : #if 0
926 : : TEST(ati2 != db.allterms_end());
927 : : TEST(*ati2 == "one");
928 : : TEST(ati2.get_termfreq() == 1);
929 : : #endif
930 : :
931 : 13 : ++ati;
932 : : #if 0
933 : : ++ati2;
934 : : #endif
935 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
936 [ - + ][ # # ]: 13 : TEST(*ati == "two");
937 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 2);
938 : :
939 : : #if 0
940 : : TEST(ati2 != db.allterms_end());
941 : : TEST(*ati2 == "three");
942 : : TEST(ati2.get_termfreq() == 3);
943 : : #endif
944 : :
945 : 13 : ati++;
946 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end());
947 : :
948 : 13 : return true;
949 : : }
950 : :
951 : : // test that iterating through all terms in two databases works.
952 : 13 : DEFINE_TESTCASE(allterms2, backend) {
953 : 13 : Xapian::Database db;
954 : 13 : db.add_database(get_database("apitest_allterms"));
955 : 13 : db.add_database(get_database("apitest_allterms2"));
956 : 13 : Xapian::TermIterator ati = db.allterms_begin();
957 : :
958 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
959 [ - + ][ # # ]: 13 : TEST(*ati == "five");
960 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 2);
961 : 13 : ati++;
962 : :
963 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
964 [ - + ][ # # ]: 13 : TEST(*ati == "four");
965 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 1);
966 : :
967 : 13 : ati++;
968 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
969 [ - + ][ # # ]: 13 : TEST(*ati == "one");
970 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 1);
971 : :
972 : 13 : ++ati;
973 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
974 [ - + ][ # # ]: 13 : TEST(*ati == "six");
975 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 3);
976 : :
977 : 13 : ati++;
978 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
979 [ - + ][ # # ]: 13 : TEST(*ati == "three");
980 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 3);
981 : :
982 : 13 : ati++;
983 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
984 [ - + ][ # # ]: 13 : TEST(*ati == "two");
985 [ - + ][ # # ]: 13 : TEST(ati.get_termfreq() == 2);
986 : :
987 : 13 : ati++;
988 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end());
989 : :
990 : 13 : return true;
991 : : }
992 : :
993 : : // test that skip_to sets at_end (regression test)
994 : 13 : DEFINE_TESTCASE(allterms3, backend) {
995 : 13 : Xapian::Database db;
996 : 13 : db.add_database(get_database("apitest_allterms"));
997 : 13 : Xapian::TermIterator ati = db.allterms_begin();
998 : :
999 : 13 : ati.skip_to(string("zzzzzz"));
1000 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end());
1001 : :
1002 : 13 : return true;
1003 : : }
1004 : :
1005 : : // test that next ignores extra entries due to long posting lists being
1006 : : // chunked (regression test for quartz)
1007 : 13 : DEFINE_TESTCASE(allterms4, backend) {
1008 : : // apitest_allterms4 contains 682 documents each containing just the word
1009 : : // "foo". 682 was the magic number which started to cause Quartz problems.
1010 : 13 : Xapian::Database db = get_database("apitest_allterms4");
1011 : :
1012 : 13 : Xapian::TermIterator i = db.allterms_begin();
1013 [ - + ][ # # ]: 13 : TEST(i != db.allterms_end());
1014 [ - + ][ # # ]: 13 : TEST(*i == "foo");
1015 [ - + ][ # # ]: 13 : TEST(i.get_termfreq() == 682);
1016 : 13 : ++i;
1017 [ - + ][ # # ]: 13 : TEST(i == db.allterms_end());
1018 : :
1019 : 13 : return true;
1020 : : }
1021 : :
1022 : : // test that skip_to with an exact match sets the current term (regression test
1023 : : // for quartz)
1024 : 13 : DEFINE_TESTCASE(allterms5, backend) {
1025 : 13 : Xapian::Database db;
1026 : 13 : db.add_database(get_database("apitest_allterms"));
1027 : 13 : Xapian::TermIterator ati = db.allterms_begin();
1028 : 13 : ati.skip_to("three");
1029 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end());
1030 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "three");
1031 : :
1032 : 13 : return true;
1033 : : }
1034 : :
1035 : : // test allterms iterators with prefixes
1036 : 13 : DEFINE_TESTCASE(allterms6, backend) {
1037 : 13 : Xapian::Database db;
1038 : 13 : db.add_database(get_database("apitest_allterms"));
1039 : 13 : db.add_database(get_database("apitest_allterms2"));
1040 : :
1041 : 13 : Xapian::TermIterator ati = db.allterms_begin("three");
1042 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("three"));
1043 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "three");
1044 : 13 : ati.skip_to("three");
1045 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("three"));
1046 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "three");
1047 : 13 : ati++;
1048 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end("three"));
1049 : :
1050 : 13 : ati = db.allterms_begin("thre");
1051 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("thre"));
1052 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "three");
1053 : 13 : ati.skip_to("three");
1054 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("thre"));
1055 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "three");
1056 : 13 : ati++;
1057 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end("thre"));
1058 : :
1059 : 13 : ati = db.allterms_begin("f");
1060 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("f"));
1061 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "five");
1062 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("f"));
1063 : 13 : ati.skip_to("three");
1064 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end("f"));
1065 : :
1066 : 13 : ati = db.allterms_begin("f");
1067 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("f"));
1068 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "five");
1069 : 13 : ati++;
1070 [ - + ][ # # ]: 13 : TEST(ati != db.allterms_end("f"));
1071 [ - + ][ # # ]: 13 : TEST_EQUAL(*ati, "four");
1072 : 13 : ati++;
1073 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end("f"));
1074 : :
1075 : 13 : ati = db.allterms_begin("absent");
1076 [ - + ][ # # ]: 13 : TEST(ati == db.allterms_end("absent"));
1077 : :
1078 : 13 : return true;
1079 : : }
1080 : :
1081 : : // test that searching for a term with a special characters in it works
1082 : 13 : DEFINE_TESTCASE(specialterms1, backend) {
1083 : 13 : Xapian::Enquire enquire(get_database("apitest_space"));
1084 : 13 : Xapian::MSet mymset;
1085 : : Xapian::doccount count;
1086 : 13 : Xapian::MSetIterator m;
1087 : 13 : Xapian::Stem stemmer("english");
1088 : :
1089 : 13 : enquire.set_query(stemmer("new\nline"));
1090 : 13 : mymset = enquire.get_mset(0, 10);
1091 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1092 : 13 : count = 0;
1093 [ + + ]: 26 : for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1094 [ - + ][ # # ]: 13 : TEST_EQUAL(count, 1);
1095 : :
1096 [ + + ]: 104 : for (Xapian::valueno value_no = 0; value_no < 7; ++value_no) {
1097 : 91 : string value = mymset.begin().get_document().get_value(value_no);
1098 [ - + # # ]: 91 : TEST_NOT_EQUAL(value, "");
1099 [ + + ]: 91 : if (value_no == 0) {
1100 [ - + ][ # # ]: 13 : TEST(value.size() > 263);
1101 [ - + ][ # # ]: 13 : TEST_EQUAL(static_cast<unsigned char>(value[262]), 255);
1102 [ + + ]: 3341 : for (int k = 0; k < 256; k++) {
1103 [ - + ][ # # ]: 3328 : TEST_EQUAL(static_cast<unsigned char>(value[k+7]), k);
1104 : : }
1105 : : }
1106 : : }
1107 : :
1108 : 13 : enquire.set_query(stemmer(string("big\0zero", 8)));
1109 : 13 : mymset = enquire.get_mset(0, 10);
1110 [ - + # # ]: 13 : TEST_MSET_SIZE(mymset, 1);
1111 : 13 : count = 0;
1112 [ + + ]: 26 : for (m = mymset.begin(); m != mymset.end(); ++m) ++count;
1113 [ - + ][ # # ]: 13 : TEST_EQUAL(count, 1);
1114 : :
1115 : 13 : return true;
1116 : : }
1117 : :
1118 : : // test that terms with a special characters in appear correctly when iterating
1119 : : // allterms
1120 : 13 : DEFINE_TESTCASE(specialterms2, backend) {
1121 : 13 : Xapian::Database db(get_database("apitest_space"));
1122 : :
1123 : : // Check the terms are all as expected (after stemming) and that allterms
1124 : : // copes with iterating over them.
1125 : 13 : Xapian::TermIterator t;
1126 : 13 : t = db.allterms_begin();
1127 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "back\\slash"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1128 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, string("big\0zero", 8)); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1129 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "new\nlin"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1130 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "one\x01on"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1131 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "space man"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1132 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "tab\tbi"); ++t; TEST_NOT_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1133 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, "tu\x02tu"); ++t; TEST_EQUAL(t, db.allterms_end());
[ - + ][ # # ]
1134 : :
1135 : : // Now check that skip_to exactly a term containing a zero byte works.
1136 : : // This is a regression test for flint and quartz - an Assert() used to
1137 : : // fire in debug builds (the Assert was wrong - the actual code handled
1138 : : // this OK).
1139 : 13 : t = db.allterms_begin();
1140 : 13 : t.skip_to(string("big\0zero", 8));
1141 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(t, db.allterms_end());
1142 [ - + ][ # # ]: 13 : TEST_EQUAL(*t, string("big\0zero", 8));
1143 : :
1144 : 13 : return true;
1145 : : }
1146 : :
1147 : : // test that rsets behave correctly with multiDBs
1148 : 10 : DEFINE_TESTCASE(rsetmultidb2, backend && !multi) {
1149 : 10 : Xapian::Database mydb1(get_database("apitest_rset", "apitest_simpledata2"));
1150 : 10 : Xapian::Database mydb2(get_database("apitest_rset"));
1151 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
1152 : :
1153 : 10 : Xapian::Enquire enquire1(mydb1);
1154 : 10 : Xapian::Enquire enquire2(mydb2);
1155 : :
1156 : 10 : Xapian::Query myquery = query("is");
1157 : :
1158 : 10 : enquire1.set_query(myquery);
1159 : 10 : enquire2.set_query(myquery);
1160 : :
1161 : 10 : Xapian::RSet myrset1;
1162 : 10 : Xapian::RSet myrset2;
1163 : 10 : myrset1.add_document(4);
1164 : 10 : myrset2.add_document(2);
1165 : :
1166 : 10 : Xapian::MSet mymset1a = enquire1.get_mset(0, 10);
1167 : 10 : Xapian::MSet mymset1b = enquire1.get_mset(0, 10, &myrset1);
1168 : 10 : Xapian::MSet mymset2a = enquire2.get_mset(0, 10);
1169 : 10 : Xapian::MSet mymset2b = enquire2.get_mset(0, 10, &myrset2);
1170 : :
1171 : 10 : mset_expect_order(mymset1a, 4, 3);
1172 : 10 : mset_expect_order(mymset1b, 4, 3);
1173 : 10 : mset_expect_order(mymset2a, 2, 5);
1174 : 10 : mset_expect_order(mymset2b, 2, 5);
1175 : :
1176 [ - + # # ]: 10 : TEST(mset_range_is_same_weights(mymset1a, 0, mymset2a, 0, 2));
1177 [ - + ][ # # ]: 10 : TEST(mset_range_is_same_weights(mymset1b, 0, mymset2b, 0, 2));
1178 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(mymset1a, mymset1b);
1179 [ - + ][ # # ]: 10 : TEST_NOT_EQUAL(mymset2a, mymset2b);
1180 : :
1181 : 10 : return true;
1182 : : }
1183 : :
1184 : : // tests an expand across multiple databases
1185 : 10 : DEFINE_TESTCASE(multiexpand1, backend && !multi) {
1186 : 10 : Xapian::Database mydb1(get_database("apitest_simpledata", "apitest_simpledata2"));
1187 : 10 : Xapian::Enquire enquire1(mydb1);
1188 : :
1189 : 10 : Xapian::Database mydb2(get_database("apitest_simpledata"));
1190 : 10 : mydb2.add_database(get_database("apitest_simpledata2"));
1191 : 10 : Xapian::Enquire enquire2(mydb2);
1192 : :
1193 : : // make simple equivalent rsets, with a document from each database in each.
1194 : 10 : Xapian::RSet rset1;
1195 : 10 : Xapian::RSet rset2;
1196 : 10 : rset1.add_document(1);
1197 : 10 : rset1.add_document(7);
1198 : 10 : rset2.add_document(1);
1199 : 10 : rset2.add_document(2);
1200 : :
1201 : : // Retrieve all the ESet results in each of the three setups:
1202 : :
1203 : : // This is the single database one.
1204 : 10 : Xapian::ESet eset1 = enquire1.get_eset(1000, rset1);
1205 : :
1206 : : // This is the multi database with approximation
1207 : 10 : Xapian::ESet eset2 = enquire2.get_eset(1000, rset2);
1208 : :
1209 : : // This is the multi database without approximation
1210 : 10 : Xapian::ESet eset3 = enquire2.get_eset(1000, rset2, Xapian::Enquire::USE_EXACT_TERMFREQ);
1211 : :
1212 [ - + # # ]: 10 : TEST_EQUAL(eset1.size(), eset3.size());
1213 : :
1214 : 10 : Xapian::ESetIterator i = eset1.begin();
1215 : 10 : Xapian::ESetIterator j = eset3.begin();
1216 [ + + ][ + - ]: 370 : while (i != eset1.end() && j != eset3.end()) {
[ + + ][ # # ]
[ # # ][ + - ]
[ + + ]
1217 [ - + ][ # # ]: 360 : TEST_EQUAL(*i, *j);
1218 [ - + ][ # # ]: 360 : TEST_EQUAL(i.get_weight(), j.get_weight());
1219 : 360 : ++i;
1220 : 360 : ++j;
1221 : : }
1222 [ - + ][ # # ]: 10 : TEST(i == eset1.end());
1223 [ - + ][ # # ]: 10 : TEST(j == eset3.end());
1224 : :
1225 : 10 : bool eset1_eq_eset2 = true;
1226 : 10 : i = eset1.begin();
1227 : 10 : j = eset2.begin();
1228 [ + - ][ + - ]: 10 : while (i != eset1.end() && j != eset2.end()) {
[ + - ][ # # ]
[ # # ][ + - ]
[ + - ]
1229 [ + - ]: 10 : if (i.get_weight() != j.get_weight()) {
1230 : 10 : eset1_eq_eset2 = false;
1231 : 10 : break;
1232 : : }
1233 : 0 : ++i;
1234 : 0 : ++j;
1235 : : }
1236 [ - + ][ # # ]: 10 : TEST(!eset1_eq_eset2);
1237 : :
1238 : 10 : return true;
1239 : : }
1240 : :
1241 : : // tests that opening a non-existent postlist returns an empty list
1242 : 13 : DEFINE_TESTCASE(postlist1, backend) {
1243 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1244 : :
1245 [ - + ][ # # ]: 13 : TEST_EQUAL(db.postlist_begin("rosebud"), db.postlist_end("rosebud"));
1246 : :
1247 : 13 : string s = "let_us_see_if_we_can_break_it_with_a_really_really_long_term.";
1248 [ + + ]: 117 : for (int i = 0; i < 8; ++i) {
1249 : 104 : s += s;
1250 [ - + ][ # # ]: 104 : TEST_EQUAL(db.postlist_begin(s), db.postlist_end(s));
1251 : : }
1252 : :
1253 : : // A regression test (no, really!)
1254 [ - + ][ # # ]: 13 : TEST_NOT_EQUAL(db.postlist_begin("a"), db.postlist_end("a"));
1255 : :
1256 : 13 : return true;
1257 : : }
1258 : :
1259 : : // tests that a Xapian::PostingIterator works as an STL iterator
1260 : 13 : DEFINE_TESTCASE(postlist2, backend) {
1261 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1262 : 13 : Xapian::PostingIterator p;
1263 : 13 : p = db.postlist_begin("this");
1264 : 13 : Xapian::PostingIterator pend = db.postlist_end("this");
1265 : :
1266 [ - + ][ # # ]: 13 : TEST(p.get_description() != "Xapian::PostingIterator(pos=END)");
1267 : :
1268 : : // test operator= creates a copy which compares equal
1269 : 13 : Xapian::PostingIterator p_copy = p;
1270 [ - + # # ]: 13 : TEST_EQUAL(p, p_copy);
1271 : :
1272 [ - + ][ # # ]: 13 : TEST(p_copy.get_description() != "Xapian::PostingIterator(pos=END)");
1273 : :
1274 : : // test copy constructor creates a copy which compares equal
1275 : 13 : Xapian::PostingIterator p_clone(p);
1276 [ - + # # ]: 13 : TEST_EQUAL(p, p_clone);
1277 : :
1278 [ - + ][ # # ]: 13 : TEST(p_clone.get_description() != "Xapian::PostingIterator(pos=END)");
1279 : :
1280 : 13 : vector<Xapian::docid> v(p, pend);
1281 : :
1282 : 13 : p = db.postlist_begin("this");
1283 : 13 : pend = db.postlist_end("this");
1284 : 13 : vector<Xapian::docid>::const_iterator i;
1285 [ + + ]: 91 : for (i = v.begin(); i != v.end(); i++) {
1286 [ - + ][ # # ]: 78 : TEST_NOT_EQUAL(p, pend);
1287 [ - + ][ # # ]: 78 : TEST_EQUAL(*i, *p);
1288 : 78 : p++;
1289 : : }
1290 [ - + ][ # # ]: 13 : TEST_EQUAL(p, pend);
1291 : :
1292 [ - + ][ # # ]: 13 : TEST_STRINGS_EQUAL(p.get_description(),
1293 : : "Xapian::PostingIterator(pos=END)");
1294 [ - + ][ # # ]: 13 : TEST_STRINGS_EQUAL(pend.get_description(),
1295 : : "Xapian::PostingIterator(pos=END)");
1296 : :
1297 : 13 : return true;
1298 : : }
1299 : :
1300 : : // tests that a Xapian::PostingIterator still works when the DB is deleted
1301 : 13 : DEFINE_TESTCASE(postlist3, backend) {
1302 : 13 : Xapian::PostingIterator u;
1303 : : {
1304 : 13 : Xapian::Database db_temp(get_database("apitest_simpledata"));
1305 : 13 : u = db_temp.postlist_begin("this");
1306 : : }
1307 : :
1308 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1309 : 13 : Xapian::PostingIterator p = db.postlist_begin("this");
1310 : 13 : Xapian::PostingIterator pend = db.postlist_end("this");
1311 : :
1312 [ + + ]: 91 : while (p != pend) {
1313 [ - + ][ # # ]: 78 : TEST_EQUAL(*p, *u);
1314 : 78 : p++;
1315 : 78 : u++;
1316 : : }
1317 : 13 : return true;
1318 : : }
1319 : :
1320 : : // tests skip_to
1321 : 13 : DEFINE_TESTCASE(postlist4, backend) {
1322 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1323 : 13 : Xapian::PostingIterator i = db.postlist_begin("this");
1324 : 13 : i.skip_to(1);
1325 : 13 : i.skip_to(999999999);
1326 [ - + ][ # # ]: 13 : TEST(i == db.postlist_end("this"));
1327 : 13 : return true;
1328 : : }
1329 : :
1330 : : // tests long postlists
1331 : 13 : DEFINE_TESTCASE(postlist5, backend) {
1332 : 13 : Xapian::Database db(get_database("apitest_manydocs"));
1333 : : // Allow for databases which don't support length
1334 [ + - ]: 13 : if (db.get_avlength() != 1)
1335 [ - + ][ # # ]: 13 : TEST_EQUAL_DOUBLE(db.get_avlength(), 4);
1336 : 13 : Xapian::PostingIterator i = db.postlist_begin("this");
1337 : 13 : unsigned int j = 1;
1338 [ + + ]: 6669 : while (i != db.postlist_end("this")) {
1339 [ - + ][ # # ]: 6656 : TEST_EQUAL(*i, j);
1340 : 6656 : i++;
1341 : 6656 : j++;
1342 : : }
1343 [ - + ][ # # ]: 13 : TEST_EQUAL(j, 513);
1344 : 13 : return true;
1345 : : }
1346 : :
1347 : : // tests document length in postlists
1348 : 13 : DEFINE_TESTCASE(postlist6, backend) {
1349 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1350 : 13 : Xapian::PostingIterator i = db.postlist_begin("this");
1351 [ - + ][ # # ]: 13 : TEST(i != db.postlist_end("this"));
1352 [ + + ]: 91 : while (i != db.postlist_end("this")) {
1353 [ - + ][ # # ]: 78 : TEST_EQUAL(i.get_doclength(), db.get_doclength(*i));
1354 [ - + ][ # # ]: 78 : TEST_REL(i.get_wdf(),<=,i.get_doclength());
1355 : 78 : ++i;
1356 : : }
1357 : 13 : return true;
1358 : : }
1359 : :
1360 : : // tests collection frequency
1361 : 13 : DEFINE_TESTCASE(collfreq1, backend) {
1362 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1363 : :
1364 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_collection_freq("this"), 11);
1365 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_collection_freq("first"), 1);
1366 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_collection_freq("last"), 0);
1367 [ - + ][ # # ]: 13 : TEST_EQUAL(db.get_collection_freq("word"), 9);
1368 : :
1369 : 13 : Xapian::Database db1(get_database("apitest_simpledata", "apitest_simpledata2"));
1370 : 13 : Xapian::Database db2(get_database("apitest_simpledata"));
1371 : 13 : db2.add_database(get_database("apitest_simpledata2"));
1372 : :
1373 [ - + ][ # # ]: 13 : TEST_EQUAL(db1.get_collection_freq("this"), 15);
1374 [ - + ][ # # ]: 13 : TEST_EQUAL(db1.get_collection_freq("first"), 1);
1375 [ - + ][ # # ]: 13 : TEST_EQUAL(db1.get_collection_freq("last"), 0);
1376 [ - + ][ # # ]: 13 : TEST_EQUAL(db1.get_collection_freq("word"), 11);
1377 [ - + ][ # # ]: 13 : TEST_EQUAL(db2.get_collection_freq("this"), 15);
1378 [ - + ][ # # ]: 13 : TEST_EQUAL(db2.get_collection_freq("first"), 1);
1379 [ - + ][ # # ]: 13 : TEST_EQUAL(db2.get_collection_freq("last"), 0);
1380 [ - + ][ # # ]: 13 : TEST_EQUAL(db2.get_collection_freq("word"), 11);
1381 : :
1382 : 13 : return true;
1383 : : }
1384 : :
1385 : : // Regression test for split msets being incorrect when sorting
1386 : 13 : DEFINE_TESTCASE(sortvalue1, backend) {
1387 : 13 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1388 : 13 : enquire.set_query(Xapian::Query("this"));
1389 : :
1390 [ + + ]: 39 : for (int pass = 1; pass <= 2; ++pass) {
1391 [ + + ]: 182 : for (Xapian::valueno value_no = 1; value_no < 7; ++value_no) {
1392 : 156 : tout << "Sorting on value " << value_no << endl;
1393 : 156 : enquire.set_sort_by_value(value_no, true);
1394 : 156 : Xapian::MSet allbset = enquire.get_mset(0, 100);
1395 : 156 : Xapian::MSet partbset1 = enquire.get_mset(0, 3);
1396 : 156 : Xapian::MSet partbset2 = enquire.get_mset(3, 97);
1397 [ - + # # ]: 156 : TEST_EQUAL(allbset.size(), partbset1.size() + partbset2.size());
1398 : :
1399 : 156 : bool ok = true;
1400 : 156 : int n = 0;
1401 : 156 : Xapian::MSetIterator i, j;
1402 : 156 : j = allbset.begin();
1403 [ + + ]: 624 : for (i = partbset1.begin(); i != partbset1.end(); ++i) {
1404 : 468 : tout << "Entry " << n << ": " << *i << " | " << *j << endl;
1405 [ - + ][ # # ]: 468 : TEST(j != allbset.end());
1406 [ - + ]: 468 : if (*i != *j) ok = false;
1407 : 468 : ++j;
1408 : 468 : ++n;
1409 : : }
1410 : 156 : tout << "===\n";
1411 [ + + ]: 624 : for (i = partbset2.begin(); i != partbset2.end(); ++i) {
1412 : 468 : tout << "Entry " << n << ": " << *i << " | " << *j << endl;
1413 [ - + ][ # # ]: 468 : TEST(j != allbset.end());
1414 [ - + ]: 468 : if (*i != *j) ok = false;
1415 : 468 : ++j;
1416 : 468 : ++n;
1417 : : }
1418 [ - + ][ # # ]: 156 : TEST(j == allbset.end());
1419 [ - + ]: 156 : if (!ok)
1420 [ # # ]: 0 : FAIL_TEST("Split msets aren't consistent with unsplit");
1421 : : }
1422 : 26 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1423 : : }
1424 : :
1425 : 13 : return true;
1426 : : }
1427 : :
1428 : : // consistency check match - vary mset size and check results agree.
1429 : : // consistency1 will run on the remote backend, but it's particularly slow
1430 : : // with that, and testing it there doesn't actually improve the test
1431 : : // coverage really.
1432 : 7 : DEFINE_TESTCASE(consistency1, backend && !remote) {
1433 : 7 : Xapian::Database db(get_database("etext"));
1434 : 7 : Xapian::Enquire enquire(db);
1435 : 7 : enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, Xapian::Query("the"), Xapian::Query("sky")));
1436 : 7 : Xapian::doccount lots = 214;
1437 : 7 : Xapian::MSet bigmset = enquire.get_mset(0, lots);
1438 [ - + # # ]: 7 : TEST_EQUAL(bigmset.size(), lots);
1439 : : try {
1440 [ + + ]: 1505 : for (Xapian::doccount start = 0; start < lots; ++start) {
1441 [ + + ]: 162533 : for (Xapian::doccount size = 0; size < lots - start; ++size) {
1442 : 161035 : Xapian::MSet mset = enquire.get_mset(start, size);
1443 [ + + ]: 161035 : if (mset.size()) {
1444 [ - + ][ # # ]: 159537 : TEST_EQUAL(start + mset.size(),
1445 : : min(start + size, bigmset.size()));
1446 [ - + ]: 1498 : } else if (size) {
1447 : : // tout << start << mset.size() << bigmset.size() << endl;
1448 [ # # ][ # # ]: 0 : TEST(start >= bigmset.size());
1449 : : }
1450 [ + + ]: 11594520 : for (Xapian::doccount i = 0; i < mset.size(); ++i) {
1451 [ - + ][ # # ]: 11433485 : TEST_EQUAL(*mset[i], *bigmset[start + i]);
1452 [ - + ][ # # ]: 11433485 : TEST_EQUAL_DOUBLE(mset[i].get_weight(),
1453 : : bigmset[start + i].get_weight());
1454 : : }
1455 : : }
1456 : : }
1457 : : }
1458 : 0 : catch (const Xapian::NetworkTimeoutError &) {
1459 : : // consistency1 is a long test - may timeout with the remote backend...
1460 [ # # ]: 0 : SKIP_TEST("Test taking too long");
1461 : : }
1462 : 7 : return true;
1463 : : }
1464 : :
1465 : : // tests that specifying a nonexistent input file throws an exception.
1466 : 1 : DEFINE_TESTCASE(flintdatabaseopeningerror1, flint) {
1467 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1468 : 1 : mkdir(".flint", 0755);
1469 : :
1470 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
1471 : : Xapian::Flint::open(".flint/nosuchdirectory"));
1472 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
1473 : : Xapian::Flint::open(".flint/nosuchdirectory", Xapian::DB_OPEN));
1474 : :
1475 : 1 : mkdir(".flint/emptydirectory", 0700);
1476 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
1477 : : Xapian::Flint::open(".flint/emptydirectory"));
1478 : :
1479 : 1 : touch(".flint/somefile");
1480 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
1481 : : Xapian::Flint::open(".flint/somefile"));
1482 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseOpeningError,
[ # # ][ - + ]
1483 : : Xapian::Flint::open(".flint/somefile", Xapian::DB_OPEN));
1484 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseCreateError,
[ # # ][ - + ]
1485 : : Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE));
1486 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseCreateError,
[ # # ][ - + ]
1487 : : Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE_OR_OPEN));
1488 [ + - ][ - + ]: 4 : TEST_EXCEPTION(Xapian::DatabaseCreateError,
[ # # ][ - + ]
1489 : : Xapian::Flint::open(".flint/somefile", Xapian::DB_CREATE_OR_OVERWRITE));
1490 : : #endif
1491 : :
1492 : 1 : return true;
1493 : : }
1494 : :
1495 : : /// Tests that appropriate error is thrown for database format change.
1496 : 1 : DEFINE_TESTCASE(flintdatabaseformaterror1, flint) {
1497 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1498 : 1 : string dbdir = test_driver::get_srcdir();
1499 : 1 : dbdir += "/testdata/flint-0.9.9";
1500 : :
1501 : : // We should get a version error when we try and open the database for
1502 : : // reading now.
1503 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseVersionError,
[ # # ][ - + ]
1504 : : Xapian::Database db(dbdir));
1505 : :
1506 : : // Also test when explicitly opening as a flint database.
1507 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseVersionError,
[ # # ][ - + ]
1508 : : (void)Xapian::Flint::open(dbdir));
1509 : :
1510 : : // Clean up the "flintlock" file that we will have created while trying
1511 : : // to open the database.
1512 : 1 : unlink((dbdir + "/flintlock").c_str());
1513 : : #endif
1514 : :
1515 : 1 : return true;
1516 : : }
1517 : :
1518 : : /// Test that an old database can be successfully overwritten when using
1519 : : // Xapian::DB_CREATE_OR_OVERWRITE.
1520 : 1 : DEFINE_TESTCASE(flintdatabaseformaterror2, flint) {
1521 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1522 : 1 : string flint099 = test_driver::get_srcdir();
1523 : 1 : flint099 += "/testdata/flint-0.9.9";
1524 : :
1525 : 1 : mkdir(".flint", 0755);
1526 : 1 : string dbdir = ".flint/test_flintdatabaseformaterror2";
1527 : :
1528 : 1 : rm_rf(dbdir);
1529 : 1 : cp_R(flint099, dbdir);
1530 : :
1531 : 1 : (void)Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
1532 : :
1533 : 1 : rm_rf(dbdir);
1534 : 1 : cp_R(flint099, dbdir);
1535 : :
1536 : : // Also test when explicitly opening as a flint database.
1537 : 1 : (void)Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
1538 : : #endif
1539 : :
1540 : 1 : return true;
1541 : : }
1542 : :
1543 : : // regression test for not releasing lock on error.
1544 : 1 : DEFINE_TESTCASE(flintdatabaseformaterror3, flint) {
1545 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1546 : 1 : string flint099 = test_driver::get_srcdir();
1547 : 1 : flint099 += "/testdata/flint-0.9.9";
1548 : :
1549 : 1 : mkdir(".flint", 0755);
1550 : 1 : string dbdir = ".flint/test_flintdatabaseformaterror3";
1551 : :
1552 : 1 : rm_rf(dbdir);
1553 : 1 : cp_R(flint099, dbdir);
1554 : :
1555 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseVersionError,
[ # # ][ - + ]
1556 : : Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OPEN));
1557 : :
1558 : : // This used to throw a DatabaseLockError: "Unable to acquire database
1559 : : // write lock on .flint/formatdb: already locked"
1560 : 1 : Xapian::WritableDatabase(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
1561 : : #endif
1562 : :
1563 : 1 : return true;
1564 : : }
1565 : :
1566 : : // Test that 1.0.2 and later can open 1.0.1 databases.
1567 : 1 : DEFINE_TESTCASE(flintbackwardcompat1, flint) {
1568 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1569 : 1 : string flint101 = test_driver::get_srcdir();
1570 : 1 : flint101 += "/testdata/flint-1.0.1";
1571 : :
1572 : 1 : mkdir(".flint", 0755);
1573 : 1 : string dbdir = ".flint/test_flintbackwardcompat1";
1574 : :
1575 : 1 : rm_rf(dbdir);
1576 : 1 : cp_R(flint101, dbdir);
1577 : :
1578 : : // Check we can open the older format for reading.
1579 : : {
1580 : 1 : Xapian::Database db(dbdir);
1581 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
1582 : : }
1583 : :
1584 : : // Check we can open the older format for update.
1585 : : {
1586 : 1 : Xapian::WritableDatabase db(dbdir, Xapian::DB_OPEN);
1587 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
1588 : : }
1589 : : #endif
1590 : :
1591 : 1 : return true;
1592 : : }
1593 : :
1594 : : // Test that 1.0.3 and later can open 1.0.2 databases.
1595 : 1 : DEFINE_TESTCASE(flintbackwardcompat2, flint) {
1596 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1597 : 1 : string flint102 = test_driver::get_srcdir();
1598 : 1 : flint102 += "/testdata/flint-1.0.2";
1599 : :
1600 : 1 : mkdir(".flint", 0755);
1601 : 1 : string dbdir = ".flint/test_flintbackwardcompat2";
1602 : :
1603 : 1 : rm_rf(dbdir);
1604 : 1 : cp_R(flint102, dbdir);
1605 : :
1606 : : // Check we can open the older format for reading.
1607 : : {
1608 : 1 : Xapian::Database db(dbdir);
1609 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
1610 : : }
1611 : :
1612 : : // Check we can open the older format for update.
1613 : : {
1614 : 1 : Xapian::WritableDatabase db(dbdir, Xapian::DB_OPEN);
1615 [ - + # # ]: 1 : TEST_EQUAL(db.get_doccount(), 0);
1616 : : }
1617 : : #endif
1618 : :
1619 : 1 : return true;
1620 : : }
1621 : :
1622 : : /// Test opening of a flint database
1623 : 1 : DEFINE_TESTCASE(flintdatabaseopen1, flint) {
1624 : : #ifdef XAPIAN_HAS_FLINT_BACKEND
1625 : 1 : const string dbdir = ".flint/test_flintdatabaseopen1";
1626 : 1 : mkdir(".flint", 0755);
1627 : :
1628 : : {
1629 : 1 : rm_rf(dbdir);
1630 : : Xapian::WritableDatabase wdb =
1631 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_CREATE);
1632 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseLockError,
[ # # ][ - + ]
1633 : : Xapian::Flint::open(dbdir, Xapian::DB_OPEN));
1634 : 1 : Xapian::Flint::open(dbdir);
1635 : : }
1636 : :
1637 : : {
1638 : 1 : rm_rf(dbdir);
1639 : : Xapian::WritableDatabase wdb =
1640 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
1641 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseLockError,
[ # # ][ - + ]
1642 : : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE));
1643 : 1 : Xapian::Flint::open(dbdir);
1644 : : }
1645 : :
1646 : : {
1647 : 1 : rm_rf(dbdir);
1648 : : Xapian::WritableDatabase wdb =
1649 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
1650 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseLockError,
[ # # ][ - + ]
1651 : : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN));
1652 : 1 : Xapian::Flint::open(dbdir);
1653 : : }
1654 : :
1655 : : {
1656 [ + - ][ - + ]: 2 : TEST_EXCEPTION(Xapian::DatabaseCreateError,
[ # # ][ - + ]
1657 : : Xapian::Flint::open(dbdir, Xapian::DB_CREATE));
1658 : : Xapian::WritableDatabase wdb =
1659 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OVERWRITE);
1660 : 1 : Xapian::Flint::open(dbdir);
1661 : : }
1662 : :
1663 : : {
1664 : : Xapian::WritableDatabase wdb =
1665 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_CREATE_OR_OPEN);
1666 : 1 : Xapian::Flint::open(dbdir);
1667 : : }
1668 : :
1669 : : {
1670 : : Xapian::WritableDatabase wdb =
1671 : 1 : Xapian::Flint::open(dbdir, Xapian::DB_OPEN);
1672 : 1 : Xapian::Flint::open(dbdir);
1673 : : }
1674 : : #endif
1675 : :
1676 : 1 : return true;
1677 : : }
1678 : :
1679 : : // feature test for Enquire:
1680 : : // set_sort_by_value
1681 : : // set_sort_by_value_then_relevance
1682 : : // set_sort_by_relevance_then_value
1683 : 13 : DEFINE_TESTCASE(sortrel1, backend) {
1684 : 13 : Xapian::Enquire enquire(get_database("apitest_sortrel"));
1685 : 13 : enquire.set_sort_by_value(1, true);
1686 : 13 : enquire.set_query(Xapian::Query("woman"));
1687 : :
1688 : 13 : const Xapian::docid order1[] = { 1,2,3,4,5,6,7,8,9 };
1689 : 13 : const Xapian::docid order2[] = { 2,1,3,6,5,4,7,9,8 };
1690 : 13 : const Xapian::docid order3[] = { 3,2,1,6,5,4,9,8,7 };
1691 : 13 : const Xapian::docid order4[] = { 7,8,9,4,5,6,1,2,3 };
1692 : 13 : const Xapian::docid order5[] = { 9,8,7,6,5,4,3,2,1 };
1693 : 13 : const Xapian::docid order6[] = { 7,9,8,6,5,4,2,1,3 };
1694 : 13 : const Xapian::docid order7[] = { 7,9,8,6,5,4,2,1,3 };
1695 : 13 : const Xapian::docid order8[] = { 7,6,2,9,5,1,8,4,3 };
1696 : 13 : const Xapian::docid order9[] = { 2,6,7,1,5,9,3,4,8 };
1697 : :
1698 : 13 : Xapian::MSet mset;
1699 : : size_t i;
1700 : :
1701 : 13 : mset = enquire.get_mset(0, 10);
1702 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
1703 [ + + ]: 130 : for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
1704 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order1[i]);
1705 : : }
1706 : :
1707 : 13 : enquire.set_sort_by_value_then_relevance(1, true);
1708 : :
1709 : 13 : mset = enquire.get_mset(0, 10);
1710 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
1711 [ + + ]: 130 : for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
1712 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order2[i]);
1713 : : }
1714 : :
1715 : 13 : enquire.set_sort_by_value(1, true);
1716 : :
1717 : 13 : mset = enquire.get_mset(0, 10);
1718 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order1) / sizeof(Xapian::docid));
1719 [ + + ]: 130 : for (i = 0; i < sizeof(order1) / sizeof(Xapian::docid); ++i) {
1720 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order1[i]);
1721 : : }
1722 : :
1723 : 13 : enquire.set_sort_by_value_then_relevance(1, true);
1724 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1725 : :
1726 : 13 : mset = enquire.get_mset(0, 10);
1727 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order2) / sizeof(Xapian::docid));
1728 [ + + ]: 130 : for (i = 0; i < sizeof(order2) / sizeof(Xapian::docid); ++i) {
1729 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order2[i]);
1730 : : }
1731 : :
1732 : 13 : enquire.set_sort_by_value(1, true);
1733 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1734 : :
1735 : 13 : mset = enquire.get_mset(0, 10);
1736 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order3) / sizeof(Xapian::docid));
1737 [ + + ]: 130 : for (i = 0; i < sizeof(order3) / sizeof(Xapian::docid); ++i) {
1738 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order3[i]);
1739 : : }
1740 : :
1741 : 13 : enquire.set_sort_by_value(1, false);
1742 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1743 : 13 : mset = enquire.get_mset(0, 10);
1744 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order4) / sizeof(Xapian::docid));
1745 [ + + ]: 130 : for (i = 0; i < sizeof(order4) / sizeof(Xapian::docid); ++i) {
1746 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order4[i]);
1747 : : }
1748 : :
1749 : 13 : enquire.set_sort_by_value(1, false);
1750 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1751 : 13 : mset = enquire.get_mset(0, 10);
1752 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order5) / sizeof(Xapian::docid));
1753 [ + + ]: 130 : for (i = 0; i < sizeof(order5) / sizeof(Xapian::docid); ++i) {
1754 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order5[i]);
1755 : : }
1756 : :
1757 : 13 : enquire.set_sort_by_value_then_relevance(1, false);
1758 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1759 : 13 : mset = enquire.get_mset(0, 10);
1760 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order6) / sizeof(Xapian::docid));
1761 [ + + ]: 130 : for (i = 0; i < sizeof(order6) / sizeof(Xapian::docid); ++i) {
1762 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order6[i]);
1763 : : }
1764 : :
1765 : 13 : enquire.set_sort_by_value_then_relevance(1, false);
1766 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1767 : 13 : mset = enquire.get_mset(0, 10);
1768 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order7) / sizeof(Xapian::docid));
1769 [ + + ]: 130 : for (i = 0; i < sizeof(order7) / sizeof(Xapian::docid); ++i) {
1770 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order7[i]);
1771 : : }
1772 : :
1773 : 13 : enquire.set_sort_by_relevance_then_value(1, true);
1774 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1775 : 13 : mset = enquire.get_mset(0, 10);
1776 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order8) / sizeof(Xapian::docid));
1777 [ + + ]: 130 : for (i = 0; i < sizeof(order8) / sizeof(Xapian::docid); ++i) {
1778 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order8[i]);
1779 : : }
1780 : :
1781 : 13 : enquire.set_sort_by_relevance_then_value(1, true);
1782 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1783 : 13 : mset = enquire.get_mset(0, 10);
1784 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order8) / sizeof(Xapian::docid));
1785 [ + + ]: 130 : for (i = 0; i < sizeof(order8) / sizeof(Xapian::docid); ++i) {
1786 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order8[i]);
1787 : : }
1788 : :
1789 : 13 : enquire.set_sort_by_relevance_then_value(1, false);
1790 : 13 : enquire.set_docid_order(Xapian::Enquire::ASCENDING);
1791 : 13 : mset = enquire.get_mset(0, 10);
1792 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order9) / sizeof(Xapian::docid));
1793 [ + + ]: 130 : for (i = 0; i < sizeof(order9) / sizeof(Xapian::docid); ++i) {
1794 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order9[i]);
1795 : : }
1796 : :
1797 : 13 : enquire.set_sort_by_relevance_then_value(1, false);
1798 : 13 : enquire.set_docid_order(Xapian::Enquire::DESCENDING);
1799 : 13 : mset = enquire.get_mset(0, 10);
1800 [ - + # # ]: 13 : TEST_EQUAL(mset.size(), sizeof(order9) / sizeof(Xapian::docid));
1801 [ + + ]: 130 : for (i = 0; i < sizeof(order9) / sizeof(Xapian::docid); ++i) {
1802 [ - + ][ # # ]: 117 : TEST_EQUAL(*mset[i], order9[i]);
1803 : : }
1804 : :
1805 : 13 : return true;
1806 : : }
1807 : :
1808 : : // Test network stats and local stats give the same results.
1809 : 6 : DEFINE_TESTCASE(netstats1, remote) {
1810 : 6 : BackendManagerLocal local_manager;
1811 : 6 : local_manager.set_datadir(test_driver::get_srcdir() + "/testdata/");
1812 : :
1813 : 6 : const char * words[] = { "paragraph", "word" };
1814 : 6 : Xapian::Query query(Xapian::Query::OP_OR, words, words + 2);
1815 : 6 : const size_t MSET_SIZE = 10;
1816 : :
1817 : 6 : Xapian::RSet rset;
1818 : 6 : rset.add_document(4);
1819 : 6 : rset.add_document(9);
1820 : :
1821 : 6 : Xapian::MSet mset_alllocal;
1822 : : {
1823 : 6 : Xapian::Database db;
1824 : 6 : db.add_database(local_manager.get_database("apitest_simpledata"));
1825 : 6 : db.add_database(local_manager.get_database("apitest_simpledata2"));
1826 : :
1827 : 6 : Xapian::Enquire enq(db);
1828 : 6 : enq.set_query(query);
1829 : 6 : mset_alllocal = enq.get_mset(0, MSET_SIZE, &rset);
1830 : : }
1831 : :
1832 : : {
1833 : 6 : Xapian::Database db;
1834 : 6 : db.add_database(local_manager.get_database("apitest_simpledata"));
1835 : 6 : db.add_database(get_database("apitest_simpledata2"));
1836 : :
1837 : 6 : Xapian::Enquire enq(db);
1838 : 6 : enq.set_query(query);
1839 : 6 : Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
1840 [ - + # # ]: 6 : TEST_EQUAL(mset.get_matches_lower_bound(), mset_alllocal.get_matches_lower_bound());
1841 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_upper_bound(), mset_alllocal.get_matches_upper_bound());
1842 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_estimated(), mset_alllocal.get_matches_estimated());
1843 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_max_attained(), mset_alllocal.get_max_attained());
1844 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.size(), mset_alllocal.size());
1845 [ - + ][ # # ]: 6 : TEST(mset_range_is_same(mset, 0, mset_alllocal, 0, mset.size()));
1846 : : }
1847 : :
1848 : : {
1849 : 6 : Xapian::Database db;
1850 : 6 : db.add_database(get_database("apitest_simpledata"));
1851 : 6 : db.add_database(local_manager.get_database("apitest_simpledata2"));
1852 : :
1853 : 6 : Xapian::Enquire enq(db);
1854 : 6 : enq.set_query(query);
1855 : 6 : Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
1856 [ - + # # ]: 6 : TEST_EQUAL(mset.get_matches_lower_bound(), mset_alllocal.get_matches_lower_bound());
1857 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_upper_bound(), mset_alllocal.get_matches_upper_bound());
1858 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_estimated(), mset_alllocal.get_matches_estimated());
1859 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_max_attained(), mset_alllocal.get_max_attained());
1860 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.size(), mset_alllocal.size());
1861 [ - + ][ # # ]: 6 : TEST(mset_range_is_same(mset, 0, mset_alllocal, 0, mset.size()));
1862 : : }
1863 : :
1864 : : {
1865 : 6 : Xapian::Database db;
1866 : 6 : db.add_database(get_database("apitest_simpledata"));
1867 : 6 : db.add_database(get_database("apitest_simpledata2"));
1868 : :
1869 : 6 : Xapian::Enquire enq(db);
1870 : 6 : enq.set_query(query);
1871 : 6 : Xapian::MSet mset = enq.get_mset(0, MSET_SIZE, &rset);
1872 [ - + # # ]: 6 : TEST_EQUAL(mset.get_matches_lower_bound(), mset_alllocal.get_matches_lower_bound());
1873 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_upper_bound(), mset_alllocal.get_matches_upper_bound());
1874 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_matches_estimated(), mset_alllocal.get_matches_estimated());
1875 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.get_max_attained(), mset_alllocal.get_max_attained());
1876 [ - + ][ # # ]: 6 : TEST_EQUAL(mset.size(), mset_alllocal.size());
1877 [ - + ][ # # ]: 6 : TEST(mset_range_is_same(mset, 0, mset_alllocal, 0, mset.size()));
1878 : : }
1879 : :
1880 : 6 : return true;
1881 : : }
1882 : :
1883 : : // Coordinate matching - scores 1 for each matching term
1884 : : class MyWeight : public Xapian::Weight {
1885 : : double scale_factor;
1886 : :
1887 : : public:
1888 : 57 : MyWeight * clone() const {
1889 : 57 : return new MyWeight;
1890 : : }
1891 : 40 : void init(double factor) {
1892 : 40 : scale_factor = factor;
1893 : 40 : }
1894 : 64 : MyWeight() { }
1895 [ + - ][ - + ]: 64 : ~MyWeight() { }
1896 : 0 : std::string name() const { return "MyWeight"; }
1897 : 0 : string serialise() const { return string(); }
1898 : 0 : MyWeight * unserialise(const string &) const { return new MyWeight; }
1899 : 98 : Xapian::weight get_sumpart(Xapian::termcount, Xapian::termcount) const {
1900 : 98 : return scale_factor;
1901 : : }
1902 : 68 : Xapian::weight get_maxpart() const { return scale_factor; }
1903 : :
1904 : 0 : Xapian::weight get_sumextra(Xapian::termcount) const { return 0; }
1905 : 10 : Xapian::weight get_maxextra() const { return 0; }
1906 : : };
1907 : :
1908 : : // tests user weighting scheme.
1909 : : // Would work with remote if we registered the weighting scheme.
1910 : : // FIXME: do this so we also test that functionality...
1911 : 7 : DEFINE_TESTCASE(userweight1, backend && !remote) {
1912 : 7 : Xapian::Enquire enquire(get_database("apitest_simpledata"));
1913 : 7 : enquire.set_weighting_scheme(MyWeight());
1914 : 7 : const char * query[] = { "this", "line", "paragraph", "rubbish" };
1915 : : enquire.set_query(Xapian::Query(Xapian::Query::OP_OR, query,
1916 : 7 : query + sizeof(query) / sizeof(query[0])));
1917 : 7 : Xapian::MSet mymset1 = enquire.get_mset(0, 100);
1918 : : // MyWeight scores 1 for each matching term, so the weight should equal
1919 : : // the number of matching terms.
1920 [ + + ]: 49 : for (Xapian::MSetIterator i = mymset1.begin(); i != mymset1.end(); ++i) {
1921 : 42 : Xapian::termcount matching_terms = 0;
1922 : 42 : Xapian::TermIterator t = enquire.get_matching_terms_begin(i);
1923 [ + + ]: 140 : while (t != enquire.get_matching_terms_end(i)) {
1924 : 98 : ++matching_terms;
1925 : 98 : ++t;
1926 : : }
1927 [ - + ][ # # ]: 42 : TEST_EQUAL(i.get_weight(), matching_terms);
1928 : 7 : }
1929 : :
1930 : 7 : return true;
1931 : : }
1932 : :
1933 : : // tests MatchAll queries
1934 : : // This is a regression test, which failed with assertion failures in
1935 : : // revision 9094. Also check that the results aren't ranked by relevance
1936 : : // (regression test for bug fixed in 1.0.9).
1937 : 13 : DEFINE_TESTCASE(matchall1, backend) {
1938 : 13 : Xapian::Database db(get_database("apitest_simpledata"));
1939 : 13 : Xapian::Enquire enquire(db);
1940 : 13 : enquire.set_query(Xapian::Query::MatchAll);
1941 : 13 : Xapian::MSet mset = enquire.get_mset(0, 10);
1942 [ - + # # ]: 13 : TEST_EQUAL(mset.get_matches_lower_bound(), db.get_doccount());
1943 [ - + ][ # # ]: 13 : TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), db.get_doccount());
1944 : :
1945 : : enquire.set_query(Xapian::Query(Xapian::Query::OP_OR,
1946 : : Xapian::Query("nosuchterm"),
1947 : 13 : Xapian::Query::MatchAll));
1948 : 13 : mset = enquire.get_mset(0, 10);
1949 [ - + # # ]: 13 : TEST_EQUAL(mset.get_matches_lower_bound(), db.get_doccount());
1950 [ - + ][ # # ]: 13 : TEST_EQUAL(mset.get_uncollapsed_matches_lower_bound(), db.get_doccount());
1951 : :
1952 : : // Check that the results aren't ranked by relevance (fixed in 1.0.9).
1953 [ - + ][ # # ]: 13 : TEST(mset.size() > 1);
1954 [ - + ][ # # ]: 13 : TEST_EQUAL(mset[mset.size() - 1].get_weight(), 0);
1955 [ - + ][ # # ]: 13 : TEST_EQUAL(*mset[0], 1);
1956 [ - + ][ # # ]: 13 : TEST_EQUAL(*mset[mset.size() - 1], mset.size());
1957 : :
1958 : 13 : return true;
1959 : : }
1960 : :
1961 : : // Test using a ValueSetMatchDecider
1962 : 7 : DEFINE_TESTCASE(valuesetmatchdecider2, backend && !remote) {
1963 : 7 : Xapian::Database db(get_database("apitest_phrase"));
1964 : 7 : Xapian::Enquire enq(db);
1965 : 7 : enq.set_query(Xapian::Query("leav"));
1966 : :
1967 : 7 : Xapian::ValueSetMatchDecider vsmd1(1, true);
1968 : 7 : vsmd1.add_value("n");
1969 : 7 : Xapian::ValueSetMatchDecider vsmd2(1, false);
1970 : 7 : vsmd2.add_value("n");
1971 : :
1972 : 7 : Xapian::MSet mymset = enq.get_mset(0, 20);
1973 : 7 : mset_expect_order(mymset, 8, 6, 4, 5, 7, 10, 12, 11, 13, 9, 14);
1974 : 7 : mymset = enq.get_mset(0, 20, 0, NULL, &vsmd1);
1975 : 7 : mset_expect_order(mymset, 6, 12);
1976 : 7 : mymset = enq.get_mset(0, 20, 0, NULL, &vsmd2);
1977 : 7 : mset_expect_order(mymset, 8, 4, 5, 7, 10, 11, 13, 9, 14);
1978 : :
1979 : 7 : return true;
1980 : : }
|