Branch data Line data Source code
1 : : /* api_postingsource.cc: tests of posting sources
2 : : *
3 : : * Copyright 2008,2009 Olly Betts
4 : : * Copyright 2008,2009 Lemur Consulting Ltd
5 : : * Copyright 2010 Richard Boulton
6 : : *
7 : : * This program is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU General Public License as
9 : : * published by the Free Software Foundation; either version 2 of the
10 : : * License, or (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, write to the Free Software
19 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 : : * USA
21 : : */
22 : :
23 : : #include <config.h>
24 : :
25 : : #include "api_postingsource.h"
26 : :
27 : : #include <xapian.h>
28 : :
29 : : #include <string>
30 : :
31 : : #include "testutils.h"
32 : : #include "str.h"
33 : : #include "apitest.h"
34 : :
35 : : using namespace std;
36 : :
37 [ + - ][ - + ]: 48 : class MyOddPostingSource : public Xapian::PostingSource {
38 : : Xapian::doccount num_docs;
39 : :
40 : : Xapian::doccount last_docid;
41 : :
42 : : Xapian::docid did;
43 : :
44 : 38 : MyOddPostingSource(Xapian::doccount num_docs_,
45 : : Xapian::doccount last_docid_)
46 : 38 : : num_docs(num_docs_), last_docid(last_docid_), did(0)
47 : 38 : { }
48 : :
49 : : public:
50 : 10 : MyOddPostingSource(const Xapian::Database &db)
51 : 10 : : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
52 : 10 : { }
53 : :
54 : 38 : PostingSource * clone() const { return new MyOddPostingSource(num_docs, last_docid); }
55 : :
56 : 8 : void init(const Xapian::Database &) { did = 0; }
57 : :
58 : : // These bounds could be better, but that's not important here.
59 : 8 : Xapian::doccount get_termfreq_min() const { return 0; }
60 : :
61 : 12 : Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
62 : :
63 : 8 : Xapian::doccount get_termfreq_max() const { return num_docs; }
64 : :
65 : 64 : void next(Xapian::weight wt) {
66 : : (void)wt;
67 : 64 : ++did;
68 [ + + ]: 64 : if (did % 2 == 0) ++did;
69 : 64 : }
70 : :
71 : 4 : void skip_to(Xapian::docid to_did, Xapian::weight wt) {
72 : : (void)wt;
73 : 4 : did = to_did;
74 [ + - ]: 4 : if (did % 2 == 0) ++did;
75 : 4 : }
76 : :
77 : 68 : bool at_end() const {
78 : : // Doesn't work if last_docid is 2^32 - 1.
79 : 68 : return did > last_docid;
80 : : }
81 : :
82 : 64 : Xapian::docid get_docid() const { return did; }
83 : :
84 : 0 : string get_description() const { return "MyOddPostingSource"; }
85 : : };
86 : :
87 : 4 : DEFINE_TESTCASE(externalsource1, backend && !remote && !multi) {
88 : : // Doesn't work for remote without registering with the server.
89 : : // Doesn't work for multi because it checks the docid in the
90 : : // subdatabase.
91 : 4 : Xapian::Database db(get_database("apitest_phrase"));
92 : 4 : Xapian::Enquire enq(db);
93 : 4 : MyOddPostingSource src(db);
94 : :
95 : : // Check that passing NULL is rejected as intended.
96 [ + - ][ - + ]: 8 : TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(NULL));
[ # # ][ - + ]
97 : 4 : Xapian::PostingSource * nullsrc = NULL;
98 [ + - ][ - + ]: 8 : TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query bad(nullsrc));
[ # # ][ - + ]
99 : :
100 : 4 : enq.set_query(Xapian::Query(&src));
101 : :
102 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
103 : 4 : mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
104 : :
105 : : Xapian::Query q(Xapian::Query::OP_FILTER,
106 : : Xapian::Query("leav"),
107 : 4 : Xapian::Query(&src));
108 : 4 : enq.set_query(q);
109 : :
110 : 4 : mset = enq.get_mset(0, 10);
111 : 4 : mset_expect_order(mset, 5, 7, 11, 13, 9);
112 : :
113 : 4 : return true;
114 : : }
115 : :
116 : : // Test that trying to use PostingSource with the remote backend throws
117 : : // Xapian::UnimplementedError as expected (we need to register the class
118 : : // in xapian-tcpsrv/xapian-progsrv for this to work).
119 : 6 : DEFINE_TESTCASE(externalsource2, remote) {
120 : 6 : Xapian::Database db(get_database("apitest_phrase"));
121 : 6 : Xapian::Enquire enq(db);
122 : 6 : MyOddPostingSource src(db);
123 : :
124 : 6 : enq.set_query(Xapian::Query(&src));
125 : :
126 [ + - ][ - + ]: 12 : TEST_EXCEPTION(Xapian::UnimplementedError,
[ # # ][ - + ]
127 : : Xapian::MSet mset = enq.get_mset(0, 10));
128 : :
129 : : Xapian::Query q(Xapian::Query::OP_FILTER,
130 : : Xapian::Query("leav"),
131 : 6 : Xapian::Query(&src));
132 : 6 : enq.set_query(q);
133 : :
134 [ + - ][ - + ]: 12 : TEST_EXCEPTION(Xapian::UnimplementedError,
[ # # ][ - + ]
135 : : Xapian::MSet mset = enq.get_mset(0, 10));
136 : :
137 : 6 : return true;
138 : : }
139 : :
140 [ + - ][ - + ]: 52 : class MyOddWeightingPostingSource : public Xapian::PostingSource {
141 : : Xapian::doccount num_docs;
142 : :
143 : : Xapian::doccount last_docid;
144 : :
145 : : Xapian::docid did;
146 : :
147 : 48 : MyOddWeightingPostingSource(Xapian::doccount num_docs_,
148 : : Xapian::doccount last_docid_)
149 : 48 : : num_docs(num_docs_), last_docid(last_docid_), did(0)
150 : : {
151 : 48 : set_maxweight(1000);
152 : 48 : }
153 : :
154 : : public:
155 : 4 : MyOddWeightingPostingSource(const Xapian::Database &db)
156 : 4 : : num_docs(db.get_doccount()), last_docid(db.get_lastdocid()), did(0)
157 : 4 : { }
158 : :
159 : 48 : PostingSource * clone() const {
160 : 48 : return new MyOddWeightingPostingSource(num_docs, last_docid);
161 : : }
162 : :
163 : 20 : void init(const Xapian::Database &) { did = 0; }
164 : :
165 : 304 : Xapian::weight get_weight() const {
166 [ + + ]: 304 : return (did % 2) ? 1000 : 0.001;
167 : : }
168 : :
169 : : // These bounds could be better, but that's not important here.
170 : 20 : Xapian::doccount get_termfreq_min() const { return 0; }
171 : :
172 : 32 : Xapian::doccount get_termfreq_est() const { return num_docs / 2; }
173 : :
174 : 20 : Xapian::doccount get_termfreq_max() const { return num_docs; }
175 : :
176 : 316 : void next(Xapian::weight wt) {
177 : : (void)wt;
178 : 316 : ++did;
179 : 316 : }
180 : :
181 : 12 : void skip_to(Xapian::docid to_did, Xapian::weight wt) {
182 : : (void)wt;
183 : 12 : did = to_did;
184 : 12 : }
185 : :
186 : 328 : bool at_end() const {
187 : : // Doesn't work if last_docid is 2^32 - 1.
188 : 328 : return did > last_docid;
189 : : }
190 : :
191 : 316 : Xapian::docid get_docid() const { return did; }
192 : :
193 : 0 : string get_description() const {
194 : 0 : return "MyOddWeightingPostingSource";
195 : : }
196 : : };
197 : :
198 : : // Like externalsource1, except we use the weight to favour odd documents.
199 : 4 : DEFINE_TESTCASE(externalsource3, backend && !remote && !multi) {
200 : : // Doesn't work for remote without registering with the server.
201 : : // Doesn't work for multi because it checks the docid in the
202 : : // subdatabase.
203 : 4 : Xapian::Database db(get_database("apitest_phrase"));
204 : 4 : Xapian::Enquire enq(db);
205 : 4 : MyOddWeightingPostingSource src(db);
206 : :
207 : 4 : enq.set_query(Xapian::Query(&src));
208 : :
209 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
210 : 4 : mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17, 2);
211 : :
212 : : Xapian::Query q(Xapian::Query::OP_OR,
213 : : Xapian::Query("leav"),
214 : 4 : Xapian::Query(&src));
215 : 4 : enq.set_query(q);
216 : :
217 : 4 : mset = enq.get_mset(0, 5);
218 : 4 : mset_expect_order(mset, 5, 7, 11, 13, 9);
219 : :
220 : 4 : tout << "max possible weight = " << mset.get_max_possible() << endl;
221 [ - + # # ]: 4 : TEST(mset.get_max_possible() > 1000);
222 : :
223 : 4 : enq.set_cutoff(0, 1000.001);
224 : 4 : mset = enq.get_mset(0, 10);
225 : 4 : mset_expect_order(mset, 5, 7, 11, 13, 9);
226 : :
227 : 4 : tout << "max possible weight = " << mset.get_max_possible() << endl;
228 [ - + # # ]: 4 : TEST(mset.get_max_possible() > 1000);
229 : :
230 : 4 : enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 0.5));
231 : 4 : mset = enq.get_mset(0, 10);
232 [ - + # # ]: 4 : TEST(mset.empty());
233 : :
234 [ - + ][ # # ]: 4 : TEST_EQUAL(mset.get_max_possible(), 500);
235 : :
236 : 4 : enq.set_query(Xapian::Query(q.OP_SCALE_WEIGHT, Xapian::Query(&src), 2));
237 : 4 : mset = enq.get_mset(0, 10);
238 : 4 : mset_expect_order(mset, 1, 3, 5, 7, 9, 11, 13, 15, 17);
239 : :
240 [ - + # # ]: 4 : TEST_EQUAL(mset.get_max_possible(), 2000);
241 : :
242 : 4 : return true;
243 : : }
244 : :
245 [ + - ][ - + ]: 62 : class MyDontAskWeightPostingSource : public Xapian::PostingSource {
246 : : Xapian::doccount num_docs;
247 : :
248 : : Xapian::doccount last_docid;
249 : :
250 : : Xapian::docid did;
251 : :
252 : 55 : MyDontAskWeightPostingSource(Xapian::doccount num_docs_,
253 : : Xapian::doccount last_docid_)
254 : 55 : : num_docs(num_docs_), last_docid(last_docid_), did(0)
255 : 55 : { }
256 : :
257 : : public:
258 : 7 : MyDontAskWeightPostingSource() : Xapian::PostingSource() {}
259 : :
260 : 55 : PostingSource * clone() const { return new MyDontAskWeightPostingSource(num_docs, last_docid); }
261 : :
262 : 20 : void init(const Xapian::Database &db) {
263 : 20 : num_docs = db.get_doccount();
264 : 20 : last_docid = db.get_lastdocid();
265 : 20 : did = 0;
266 : 20 : }
267 : :
268 : 0 : Xapian::weight get_weight() const {
269 [ # # ]: 0 : FAIL_TEST("MyDontAskWeightPostingSource::get_weight() called");
270 : : }
271 : :
272 : : // These bounds could be better, but that's not important here.
273 : 20 : Xapian::doccount get_termfreq_min() const { return num_docs; }
274 : :
275 : 30 : Xapian::doccount get_termfreq_est() const { return num_docs; }
276 : :
277 : 20 : Xapian::doccount get_termfreq_max() const { return num_docs; }
278 : :
279 : 77 : void next(Xapian::weight wt) {
280 : : (void)wt;
281 : 77 : ++did;
282 : 77 : }
283 : :
284 : 77 : void skip_to(Xapian::docid to_did, Xapian::weight wt) {
285 : : (void)wt;
286 : 77 : did = to_did;
287 : 77 : }
288 : :
289 : 154 : bool at_end() const {
290 : : // Doesn't work if last_docid is 2^32 - 1.
291 : 154 : return did > last_docid;
292 : : }
293 : :
294 : 148 : Xapian::docid get_docid() const { return did; }
295 : :
296 : 0 : string get_description() const {
297 : 0 : return "MyDontAskWeightPostingSource";
298 : : }
299 : : };
300 : :
301 : : // Check that boolean use doesn't call get_weight().
302 : 7 : DEFINE_TESTCASE(externalsource4, backend && !remote) {
303 : 7 : Xapian::Database db(get_database("apitest_phrase"));
304 : 7 : Xapian::Enquire enq(db);
305 : 7 : MyDontAskWeightPostingSource src;
306 : :
307 : 7 : tout << "OP_SCALE_WEIGHT 0" << endl;
308 : 7 : enq.set_query(Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT, Xapian::Query(&src), 0));
309 : :
310 : 7 : Xapian::MSet mset = enq.get_mset(0, 5);
311 : 7 : mset_expect_order(mset, 1, 2, 3, 4, 5);
312 : :
313 : 7 : tout << "OP_FILTER" << endl;
314 : : Xapian::Query q(Xapian::Query::OP_FILTER,
315 : : Xapian::Query("leav"),
316 : 7 : Xapian::Query(&src));
317 : 7 : enq.set_query(q);
318 : :
319 : 7 : mset = enq.get_mset(0, 5);
320 : 7 : mset_expect_order(mset, 8, 6, 4, 5, 7);
321 : :
322 : 7 : tout << "BoolWeight" << endl;
323 : 7 : enq.set_query(Xapian::Query(&src));
324 : 7 : enq.set_weighting_scheme(Xapian::BoolWeight());
325 : :
326 : : //mset = enq.get_mset(0, 5);
327 : : //mset_expect_order(mset, 1, 2, 3, 4, 5);
328 : :
329 : 7 : return true;
330 : : }
331 : :
332 : : // Check that valueweightsource works correctly.
333 : 13 : DEFINE_TESTCASE(valueweightsource1, backend) {
334 : 13 : Xapian::Database db(get_database("apitest_phrase"));
335 : 13 : Xapian::Enquire enq(db);
336 : 13 : Xapian::ValueWeightPostingSource src(11);
337 : :
338 : : // Should be in descending order of length
339 : 13 : tout << "RAW" << endl;
340 : 13 : enq.set_query(Xapian::Query(&src));
341 : 13 : Xapian::MSet mset = enq.get_mset(0, 5);
342 : 13 : mset_expect_order(mset, 3, 1, 2, 8, 14);
343 : :
344 : : // In relevance order
345 : 13 : tout << "OP_FILTER" << endl;
346 : : Xapian::Query q(Xapian::Query::OP_FILTER,
347 : : Xapian::Query("leav"),
348 : 13 : Xapian::Query(&src));
349 : 13 : enq.set_query(q);
350 : 13 : mset = enq.get_mset(0, 5);
351 : 13 : mset_expect_order(mset, 8, 6, 4, 5, 7);
352 : :
353 : : // Should be in descending order of length
354 : 13 : tout << "OP_FILTER other way" << endl;
355 : : q = Xapian::Query(Xapian::Query::OP_FILTER,
356 : : Xapian::Query(&src),
357 : 13 : Xapian::Query("leav"));
358 : 13 : enq.set_query(q);
359 : 13 : mset = enq.get_mset(0, 5);
360 : 13 : mset_expect_order(mset, 8, 14, 9, 13, 7);
361 : :
362 : 13 : return true;
363 : : }
364 : :
365 : : // Check that valueweightsource gives the correct bounds for those databases
366 : : // which support value statistics.
367 : 9 : DEFINE_TESTCASE(valueweightsource2, valuestats) {
368 : 9 : Xapian::Database db(get_database("apitest_phrase"));
369 : 9 : Xapian::ValueWeightPostingSource src(11);
370 : 9 : src.init(db);
371 [ - + # # ]: 9 : TEST_EQUAL(src.get_termfreq_min(), 17);
372 [ - + ][ # # ]: 9 : TEST_EQUAL(src.get_termfreq_est(), 17);
373 [ - + ][ # # ]: 9 : TEST_EQUAL(src.get_termfreq_max(), 17);
374 [ - + ][ # # ]: 9 : TEST_EQUAL(src.get_maxweight(), 135);
375 : :
376 : 9 : return true;
377 : : }
378 : :
379 : : // Check that valueweightsource skip_to() can stay in the same position.
380 : 7 : DEFINE_TESTCASE(valueweightsource3, valuestats && !multi) {
381 : : // FIXME: multi doesn't support iterating valuestreams yet.
382 : 7 : Xapian::Database db(get_database("apitest_phrase"));
383 : 7 : Xapian::ValueWeightPostingSource src(11);
384 : 7 : src.init(db);
385 [ - + # # ]: 7 : TEST(!src.at_end());
386 : 7 : src.skip_to(8, 0.0);
387 [ - + # # ]: 7 : TEST(!src.at_end());
388 [ - + ][ # # ]: 7 : TEST_EQUAL(src.get_docid(), 8);
389 : 7 : src.skip_to(8, 0.0);
390 [ - + # # ]: 7 : TEST(!src.at_end());
391 [ - + ][ # # ]: 7 : TEST_EQUAL(src.get_docid(), 8);
392 : :
393 : 7 : return true;
394 : : }
395 : :
396 : : // Check that fixedweightsource works correctly.
397 : 13 : DEFINE_TESTCASE(fixedweightsource1, backend) {
398 : 13 : Xapian::Database db(get_database("apitest_phrase"));
399 : 13 : Xapian::Enquire enq(db);
400 : 13 : double wt = 5.6;
401 : :
402 : : {
403 : 13 : Xapian::FixedWeightPostingSource src(wt);
404 : :
405 : : // Should be in increasing order of docid.
406 : 13 : enq.set_query(Xapian::Query(&src));
407 : 13 : Xapian::MSet mset = enq.get_mset(0, 5);
408 : 13 : mset_expect_order(mset, 1, 2, 3, 4, 5);
409 : :
410 [ + + ]: 78 : for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
411 [ - + ][ # # ]: 65 : TEST_EQUAL(i.get_weight(), wt);
412 : 13 : }
413 : : }
414 : :
415 : : // Do some direct tests, to check the skip_to() and check() methods work.
416 : : {
417 : : // Check next and skip_to().
418 : 13 : Xapian::FixedWeightPostingSource src(wt);
419 : 13 : src.init(db);
420 : :
421 : 13 : src.next(1.0);
422 [ - + # # ]: 13 : TEST(!src.at_end());
423 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 1);
424 : 13 : src.next(1.0);
425 [ - + # # ]: 13 : TEST(!src.at_end());
426 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 2);
427 : 13 : src.skip_to(5, 1.0);
428 [ - + # # ]: 13 : TEST(!src.at_end());
429 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 5);
430 : 13 : src.next(wt * 2);
431 [ - + # # ]: 13 : TEST(src.at_end());
432 : : }
433 : : {
434 : : // Check check() as the first operation, followed by next.
435 : 13 : Xapian::FixedWeightPostingSource src(wt);
436 : 13 : src.init(db);
437 : :
438 [ - + # # ]: 13 : TEST_EQUAL(src.check(5, 1.0), true);
439 [ - + ][ # # ]: 13 : TEST(!src.at_end());
440 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 5);
441 : 13 : src.next(1.0);
442 [ - + # # ]: 13 : TEST(!src.at_end());
443 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 6);
444 : : }
445 : : {
446 : : // Check check() as the first operation, followed by skip_to().
447 : 13 : Xapian::FixedWeightPostingSource src(wt);
448 : 13 : src.init(db);
449 : :
450 [ - + # # ]: 13 : TEST_EQUAL(src.check(5, 1.0), true);
451 [ - + ][ # # ]: 13 : TEST(!src.at_end());
452 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 5);
453 : 13 : src.skip_to(6, 1.0);
454 [ - + # # ]: 13 : TEST(!src.at_end());
455 [ - + ][ # # ]: 13 : TEST_EQUAL(src.get_docid(), 6);
456 : 13 : src.skip_to(7, wt * 2);
457 [ - + # # ]: 13 : TEST(src.at_end());
458 : : }
459 : :
460 : 13 : return true;
461 : : }
462 : :
463 : : // A posting source which changes the maximum weight.
464 [ # # ][ - + ]: 8 : class ChangeMaxweightPostingSource : public Xapian::PostingSource {
465 : : Xapian::docid did;
466 : :
467 : : // Maximum docid that get_weight() should be called for.
468 : : Xapian::docid maxid_accessed;
469 : :
470 : : public:
471 : 8 : ChangeMaxweightPostingSource(Xapian::docid maxid_accessed_)
472 : 8 : : did(0), maxid_accessed(maxid_accessed_) { }
473 : :
474 : 8 : void init(const Xapian::Database &) { did = 0; }
475 : :
476 : 28 : Xapian::weight get_weight() const {
477 [ - + ]: 28 : if (did > maxid_accessed) {
478 [ # # ]: 0 : FAIL_TEST("ChangeMaxweightPostingSource::get_weight() called "
479 : : "for docid " + str(did) + ", max id accessed "
480 : : "should be " + str(maxid_accessed));
481 : : }
482 : 28 : return 5 - did;
483 : : }
484 : :
485 : 8 : Xapian::doccount get_termfreq_min() const { return 4; }
486 : 16 : Xapian::doccount get_termfreq_est() const { return 4; }
487 : 8 : Xapian::doccount get_termfreq_max() const { return 4; }
488 : :
489 : 32 : void next(Xapian::weight) {
490 : 32 : ++did;
491 : 32 : set_maxweight(5 - did);
492 : 32 : }
493 : :
494 : 0 : void skip_to(Xapian::docid to_did, Xapian::weight) {
495 : 0 : did = to_did;
496 : 0 : set_maxweight(5 - did);
497 : 0 : }
498 : :
499 : 40 : bool at_end() const { return did >= 5; }
500 : 32 : Xapian::docid get_docid() const { return did; }
501 : 0 : string get_description() const { return "ChangeMaxweightPostingSource"; }
502 : : };
503 : :
504 : : // Test a posting source with a variable maxweight.
505 : 4 : DEFINE_TESTCASE(changemaxweightsource1, backend && !remote && !multi) {
506 : : // The ChangeMaxweightPostingSource doesn't work with multi or remote.
507 : 4 : Xapian::Database db(get_database("apitest_phrase"));
508 : 4 : Xapian::Enquire enq(db);
509 : :
510 : : {
511 : 4 : ChangeMaxweightPostingSource src1(5);
512 : 4 : Xapian::FixedWeightPostingSource src2(2.5);
513 : :
514 : : Xapian::Query q(Xapian::Query::OP_AND,
515 : 4 : Xapian::Query(&src1), Xapian::Query(&src2));
516 : 4 : enq.set_query(q);
517 : : // Set descending docid order so that the matcher isn't able to
518 : : // terminate early after 4 documents just because weight == maxweight.
519 : 4 : enq.set_docid_order(enq.DESCENDING);
520 : :
521 : 4 : Xapian::MSet mset = enq.get_mset(0, 4);
522 [ - + # # ]: 4 : TEST(src1.at_end());
523 : 4 : mset_expect_order(mset, 1, 2, 3, 4);
524 [ + + ]: 20 : for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
525 [ - + ][ # # ]: 16 : TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
526 : 4 : }
527 : : }
528 : :
529 : : {
530 : 4 : ChangeMaxweightPostingSource src1(3);
531 : 4 : Xapian::FixedWeightPostingSource src2(2.5);
532 : :
533 : : Xapian::Query q(Xapian::Query::OP_AND,
534 : 4 : Xapian::Query(&src1), Xapian::Query(&src2));
535 : 4 : enq.set_query(q);
536 : :
537 : 4 : Xapian::MSet mset = enq.get_mset(0, 2);
538 [ - + # # ]: 4 : TEST(!src1.at_end());
539 [ - + ][ # # ]: 4 : TEST_EQUAL(src1.get_docid(), 3);
540 [ - + ][ # # ]: 4 : TEST_EQUAL_DOUBLE(src1.get_maxweight(), 2.0);
541 : 4 : mset_expect_order(mset, 1, 2);
542 [ + + ]: 12 : for (Xapian::MSetIterator i = mset.begin(); i != mset.end(); ++i) {
543 [ - + ][ # # ]: 8 : TEST_EQUAL_DOUBLE(i.get_weight(), 7.5 - *i);
544 : 4 : }
545 : : }
546 : :
547 : 4 : return true;
548 : : }
549 : :
550 : : // Test using a valueweightpostingsource which has no entries.
551 : 4 : DEFINE_TESTCASE(emptyvalwtsource1, backend && !remote && !multi) {
552 : 4 : Xapian::Database db(get_database("apitest_phrase"));
553 : 4 : Xapian::Enquire enq(db);
554 : :
555 : 4 : Xapian::ValueWeightPostingSource src2(11); // A non-empty slot.
556 : 4 : Xapian::ValueWeightPostingSource src3(100); // An empty slot.
557 : 4 : Xapian::Query q1("leav");
558 : 4 : Xapian::Query q2(&src2);
559 : 4 : Xapian::Query q3(&src3);
560 : 4 : Xapian::Query q(Xapian::Query::OP_OR, Xapian::Query(Xapian::Query::OP_AND_MAYBE, q1, q2), q3);
561 : :
562 : : // Perform search without ORring with the posting source.
563 : : Xapian::doccount size1;
564 : : {
565 : 4 : enq.set_query(q1);
566 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
567 [ - + # # ]: 4 : TEST_REL(mset.get_max_possible(), >, 0.0);
568 : 4 : size1 = mset.size();
569 [ - + # # ]: 4 : TEST_REL(size1, >, 0);
570 : : }
571 : :
572 : : // Perform a search with just the non-empty posting source, checking it
573 : : // returns something.
574 : : {
575 : 4 : enq.set_query(q2);
576 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
577 [ - + # # ]: 4 : TEST_REL(mset.get_max_possible(), >, 0.0);
578 [ - + ][ # # ]: 4 : TEST_REL(mset.size(), >, 0);
579 : : }
580 : :
581 : : // Perform a search with just the empty posting source, checking it returns
582 : : // nothing.
583 : : {
584 : 4 : enq.set_query(q3);
585 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
586 : :
587 : : // get_max_possible() returns 0 here for backends which track the upper
588 : : // bound on value slot entries, MAX_DBL for backends which don't.
589 : : // Either is valid.
590 [ - + # # ]: 4 : TEST_REL(mset.get_max_possible(), >=, 0.0);
591 : :
592 [ - + ][ # # ]: 4 : TEST_EQUAL(mset.size(), 0);
593 : : }
594 : :
595 : : // Perform a search with the posting source ORred with the normal query.
596 : : // This is a regression test - it used to return nothing.
597 : : {
598 : 4 : enq.set_query(q);
599 : 4 : Xapian::MSet mset = enq.get_mset(0, 10);
600 [ - + # # ]: 4 : TEST_REL(mset.get_max_possible(), >, 0.0);
601 [ - + ][ # # ]: 4 : TEST_REL(mset.size(), >, 0.0);
602 [ - + ][ # # ]: 4 : TEST_EQUAL(mset.size(), size1);
603 : : }
604 : :
605 : 4 : return true;
606 : : }
|