1 /** @file api_valuestream.cc
2 * @brief Tests of valuestream functionality.
4 /* Copyright (C) 2008,2009,2010 Olly Betts
5 * Copyright (C) 2009 Lemur Consulting Ltd
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.
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.
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
25 #include "api_valuestream.h"
28 #include "testsuite.h"
29 #include "testutils.h"
35 /// Feature test simple valuestream iteration.
36 DEFINE_TESTCASE(valuestream1
, backend
&& !multi
) {
37 // FIXME: enable for multi once support is in place.
38 Xapian::Database db
= get_database("apitest_simpledata");
40 for (Xapian::valueno slot
= 0; slot
< 15; ++slot
) {
41 tout
<< "testing valuestream iteration for slot " << slot
<< endl
;
42 Xapian::ValueIterator it
= db
.valuestream_begin(slot
);
43 while (it
!= db
.valuestream_end(slot
)) {
44 TEST_EQUAL(it
.get_valueno(), slot
);
46 Xapian::docid did
= it
.get_docid();
48 Xapian::Document doc
= db
.get_document(did
);
49 TEST_EQUAL(doc
.get_value(slot
), value
);
58 /// Test skip_to() on a valuestream iterator.
59 DEFINE_TESTCASE(valuestream2
, backend
) {
60 Xapian::Database db
= get_database("etext");
62 for (Xapian::valueno slot
= 0; slot
< 15; ++slot
) {
63 unsigned interval
= 1;
64 while (interval
< 1999) {
66 tout
<< "testing valuestream skip_to for slot " << slot
67 << " with interval " << interval
<< endl
;
68 Xapian::docid did
= 1;
69 Xapian::ValueIterator it
= db
.valuestream_begin(slot
);
70 if (it
== db
.valuestream_end(slot
)) break;
71 while (it
.skip_to(did
), it
!= db
.valuestream_end(slot
)) {
72 TEST_EQUAL(it
.get_valueno(), slot
);
75 // Check that the skipped documents had no values.
76 Xapian::docid actual_did
= it
.get_docid();
77 TEST_REL(actual_did
,>=,did
);
78 while (did
< actual_did
) {
79 Xapian::Document doc
= db
.get_document(did
);
80 TEST(doc
.get_value(slot
).empty());
84 Xapian::Document doc
= db
.get_document(actual_did
);
85 TEST_EQUAL(doc
.get_value(slot
), value
);
88 interval
= interval
* 3 - 1;
95 /// Test check() on a valuestream iterator.
96 DEFINE_TESTCASE(valuestream3
, backend
) {
97 Xapian::Database db
= get_database("etext");
99 // Check combinations of check with other operations.
101 CHECK
, CHECK_AND_NEXT
, CHECK2
, SKIP_TO
, CHECK_AND_LOOP
103 test_op operation
= CHECK
;
105 for (Xapian::valueno slot
= 0; slot
< 15; ++slot
) {
106 unsigned interval
= 1;
107 while (interval
< 1999) {
108 tout
<< "testing valuestream check for slot " << slot
109 << " with interval " << interval
<< endl
;
110 Xapian::docid did
= 1;
111 Xapian::ValueIterator it
= db
.valuestream_begin(slot
);
112 if (it
== db
.valuestream_end(slot
)) break;
114 bool positioned
= true;
119 case CHECK
: case CHECK2
:
120 positioned
= it
.check(did
);
122 case CHECK_AND_NEXT
: {
123 bool was_skip_to
= it
.check(did
);
124 if (!was_skip_to
) ++it
;
131 operation
= test_op(operation
+ 1);
133 if (it
== db
.valuestream_end(slot
)) break;
134 TEST_EQUAL(it
.get_valueno(), slot
);
137 // Check that the skipped documents had no values.
138 Xapian::docid actual_did
= it
.get_docid();
139 while (did
< actual_did
) {
140 Xapian::Document doc
= db
.get_document(did
);
141 TEST(doc
.get_value(slot
).empty());
145 Xapian::Document doc
= db
.get_document(actual_did
);
146 TEST_EQUAL(doc
.get_value(slot
), value
);
150 interval
= interval
* 3 - 1;
157 /** Check that valueweightsource handles last_docid of 0xffffffff.
159 * The original implementation went into an infinite loop in this case.
161 DEFINE_TESTCASE(valueweightsource5
, writable
&& valuestats
) {
162 // inmemory's memory use is currently O(last_docid)!
163 SKIP_TEST_FOR_BACKEND("inmemory");
164 // remote's value slot iteration is very slow for this case currently
165 // because it throws and catches DocNotFoundError across the link 2^32-3
167 SKIP_TEST_FOR_BACKEND("remote");
168 Xapian::WritableDatabase db
= get_writable_database();
169 Xapian::Document doc
;
170 doc
.add_value(1, Xapian::sortable_serialise(3.14));
171 db
.replace_document(1, doc
);
172 db
.replace_document(0xffffffff, doc
);
175 Xapian::ValueWeightPostingSource
src(1);
179 TEST_EQUAL(src
.get_docid(), 1);
182 TEST_EQUAL(src
.get_docid(), 0xffffffff);
189 // Check that ValueMapPostingSource works correctly.
190 // the test db has value 13 set to:
209 DEFINE_TESTCASE(valuemapsource1
, backend
) {
210 Xapian::Database
db(get_database("apitest_phrase"));
211 Xapian::Enquire
enq(db
);
213 Xapian::ValueMapPostingSource
src(13);
214 src
.add_mapping("Thi", 2.0);
215 src
.add_mapping("The", 1.0);
216 src
.add_mapping("You", 3.0);
217 src
.add_mapping("War", 4.0);
218 src
.add_mapping("Fri", 5.0);
220 // check mset size and order
221 enq
.set_query(Xapian::Query(&src
));
222 Xapian::MSet mset
= enq
.get_mset(0, 5);
224 TEST(mset
.size() == 5);
225 mset_expect_order(mset
, 5, 4, 3, 1, 2);
227 // and with default weight
228 src
.clear_mappings();
229 src
.set_default_weight(3.5);
230 src
.add_mapping("Thi", 2.0);
231 src
.add_mapping("The", 1.0);
232 src
.add_mapping("You", 3.0);
233 src
.add_mapping("War", 4.0);
234 src
.add_mapping("Fri", 5.0);
236 enq
.set_query(Xapian::Query(&src
));
237 mset
= enq
.get_mset(0, 5);
239 TEST(mset
.size() == 5);
240 mset_expect_order(mset
, 5, 4, 6, 7, 8);
245 // Regression test for valuepostingsource subclasses: used to segfault if skip_to()
246 // called on an empty list.
247 DEFINE_TESTCASE(valuemapsource2
, backend
&& !multi
) {
248 Xapian::Database
db(get_database("apitest_phrase"));
251 Xapian::ValueMapPostingSource
src(100);
253 TEST(src
.at_end() == false);
255 TEST(src
.at_end() == true);
259 Xapian::ValueMapPostingSource
src(100);
261 TEST(src
.at_end() == false);
263 TEST(src
.at_end() == true);
267 Xapian::ValueMapPostingSource
src(100);
269 TEST(src
.at_end() == false);
271 TEST(src
.at_end() == true);
277 // Regression test for fixedweightpostingsource: used to segfault if skip_to()
278 // called on an empty list.
279 DEFINE_TESTCASE(fixedweightsource2
, !backend
) {
283 Xapian::FixedWeightPostingSource
src(5.0);
285 TEST(src
.at_end() == false);
287 TEST(src
.at_end() == true);
291 Xapian::FixedWeightPostingSource
src(5.0);
293 TEST(src
.at_end() == false);
295 TEST(src
.at_end() == true);
298 // No need to test behaviour of check() - check is only allowed to be
299 // called with document IDs which exist, so can never be called for a
300 // FixedWeightPostingSource with an empty database.
305 // Test DecreasingValueWeightPostingSource.
306 DEFINE_TESTCASE(decvalwtsource1
, writable
) {
307 Xapian::WritableDatabase db
= get_writable_database();
309 Xapian::Document doc
;
310 doc
.add_value(1, Xapian::sortable_serialise(3));
311 db
.add_document(doc
);
312 doc
.add_value(1, Xapian::sortable_serialise(2));
313 db
.add_document(doc
);
314 doc
.add_value(1, Xapian::sortable_serialise(1));
315 db
.add_document(doc
);
318 // Check basic function
320 Xapian::DecreasingValueWeightPostingSource
src(1);
325 TEST_EQUAL(src
.get_docid(), 1);
329 TEST_EQUAL(src
.get_docid(), 2);
333 TEST_EQUAL(src
.get_docid(), 3);
339 // Check skipping to end of list due to weight
341 Xapian::DecreasingValueWeightPostingSource
src(1);
346 TEST_EQUAL(src
.get_docid(), 1);
350 TEST_EQUAL(src
.get_docid(), 2);
356 // Check behaviour with a restricted range
357 doc
.add_value(1, Xapian::sortable_serialise(2));
358 db
.add_document(doc
);
361 Xapian::DecreasingValueWeightPostingSource
src(1, 1, 3);
366 TEST_EQUAL(src
.get_docid(), 1);
370 TEST_EQUAL(src
.get_docid(), 2);
374 TEST_EQUAL(src
.get_docid(), 4);
381 Xapian::DecreasingValueWeightPostingSource
src(1, 1, 3);
386 TEST_EQUAL(src
.get_docid(), 1);
390 TEST_EQUAL(src
.get_docid(), 4);
397 Xapian::DecreasingValueWeightPostingSource
src(1, 1, 3);
402 TEST_EQUAL(src
.get_docid(), 1);
404 TEST(src
.check(3, 1.5));
406 TEST_EQUAL(src
.get_docid(), 4);
415 // Test DecreasingValueWeightPostingSource with out-of-order sections at
416 // start, and with repeated weights.
417 DEFINE_TESTCASE(decvalwtsource2
, writable
) {
418 Xapian::WritableDatabase db
= get_writable_database();
420 Xapian::Document doc
;
421 doc
.add_value(1, Xapian::sortable_serialise(1));
422 db
.add_document(doc
);
423 doc
.add_value(1, Xapian::sortable_serialise(3));
424 db
.add_document(doc
);
425 doc
.add_value(1, Xapian::sortable_serialise(3));
426 db
.add_document(doc
);
427 doc
.add_value(1, Xapian::sortable_serialise(1));
428 db
.add_document(doc
);
431 // Check basic function
433 Xapian::DecreasingValueWeightPostingSource
src(1);
438 TEST_EQUAL(src
.get_docid(), 1);
442 TEST_EQUAL(src
.get_docid(), 2);
446 TEST_EQUAL(src
.get_docid(), 3);
450 TEST_EQUAL(src
.get_docid(), 4);
456 // Check skipping to end of list due to weight
458 Xapian::DecreasingValueWeightPostingSource
src(1, 2);
463 TEST_EQUAL(src
.get_docid(), 1);
467 TEST_EQUAL(src
.get_docid(), 2);
471 TEST_EQUAL(src
.get_docid(), 3);
477 // Check behaviour with a restricted range
478 doc
.add_value(1, Xapian::sortable_serialise(2));
479 db
.add_document(doc
);
482 Xapian::DecreasingValueWeightPostingSource
src(1, 2, 4);
487 TEST_EQUAL(src
.get_docid(), 1);
491 TEST_EQUAL(src
.get_docid(), 2);
495 TEST_EQUAL(src
.get_docid(), 3);
499 TEST_EQUAL(src
.get_docid(), 5);
506 Xapian::DecreasingValueWeightPostingSource
src(1, 2, 4);
509 TEST(src
.check(1, 1.5));
511 TEST_EQUAL(src
.get_docid(), 1);
515 TEST_EQUAL(src
.get_docid(), 2);
519 TEST_EQUAL(src
.get_docid(), 5);
526 Xapian::DecreasingValueWeightPostingSource
src(1, 2, 4);
529 TEST(src
.check(1, 1.5));
531 TEST_EQUAL(src
.get_docid(), 1);
535 TEST_EQUAL(src
.get_docid(), 2);
537 TEST(src
.check(4, 1.5));
539 TEST_EQUAL(src
.get_docid(), 5);
548 // Test DecreasingValueWeightPostingSource with an actual query.
549 DEFINE_TESTCASE(decvalwtsource3
, writable
) {
550 Xapian::WritableDatabase db
= get_writable_database();
552 Xapian::Document doc
;
554 doc
.add_value(1, Xapian::sortable_serialise(1));
555 db
.add_document(doc
);
556 doc
.add_value(1, Xapian::sortable_serialise(3));
557 db
.add_document(doc
);
559 doc
.add_value(1, Xapian::sortable_serialise(3));
560 db
.add_document(doc
);
561 doc
.add_value(1, Xapian::sortable_serialise(1));
562 db
.add_document(doc
);
565 Xapian::DecreasingValueWeightPostingSource
ps(1, 2, 5);
566 Xapian::Query
q(&ps
);
567 Xapian::Enquire
enq(db
);
570 Xapian::MSet
mset1(enq
.get_mset(0, 1));
571 Xapian::MSet
mset2(enq
.get_mset(0, 2));
572 Xapian::MSet
mset3(enq
.get_mset(0, 3));
573 Xapian::MSet
mset4(enq
.get_mset(0, 4));
575 TEST_EQUAL(mset1
.size(), 1);
576 TEST_EQUAL(mset2
.size(), 2);
577 TEST_EQUAL(mset3
.size(), 3);
578 TEST_EQUAL(mset4
.size(), 4);
580 TEST(mset_range_is_same(mset1
, 0, mset2
, 0, 1));
581 TEST(mset_range_is_same(mset2
, 0, mset3
, 0, 2));
582 TEST(mset_range_is_same(mset3
, 0, mset4
, 0, 3));
587 // Test DecreasingValueWeightPostingSource with an actual query on a fixed
588 // dataset (so we can cover the remote backend too).
589 DEFINE_TESTCASE(decvalwtsource4
, backend
&& !multi
) {
590 Xapian::Database db
= get_database("apitest_declen");
592 Xapian::DecreasingValueWeightPostingSource
ps(11, 2, 5);
593 Xapian::Query
q(&ps
);
594 Xapian::Enquire
enq(db
);
597 Xapian::MSet
mset1(enq
.get_mset(0, 1));
598 Xapian::MSet
mset2(enq
.get_mset(0, 2));
599 Xapian::MSet
mset3(enq
.get_mset(0, 3));
600 Xapian::MSet
mset4(enq
.get_mset(0, 4));
602 TEST_EQUAL(mset1
.size(), 1);
603 TEST_EQUAL(mset2
.size(), 2);
604 TEST_EQUAL(mset3
.size(), 3);
605 TEST_EQUAL(mset4
.size(), 4);
607 TEST(mset_range_is_same(mset1
, 0, mset2
, 0, 1));
608 TEST(mset_range_is_same(mset2
, 0, mset3
, 0, 2));
609 TEST(mset_range_is_same(mset3
, 0, mset4
, 0, 3));
614 // Regression test - used to get segfaults if
615 // DecreasingValueWeightPostingSource was pointed at an empty slot.
616 DEFINE_TESTCASE(decvalwtsource5
, writable
) {
617 Xapian::WritableDatabase db
= get_writable_database();
619 Xapian::Document doc
;
620 doc
.add_value(1, Xapian::sortable_serialise(1));
621 db
.add_document(doc
);
622 doc
.add_value(2, Xapian::sortable_serialise(1));
623 db
.add_document(doc
);
627 Xapian::DecreasingValueWeightPostingSource
ps(1);
628 Xapian::Query
q(&ps
);
629 Xapian::Enquire
enq(db
);
631 Xapian::MSet
mset1(enq
.get_mset(0, 3));
632 TEST_EQUAL(mset1
.size(), 2);
635 Xapian::DecreasingValueWeightPostingSource
ps(2);
636 Xapian::Query
q(&ps
);
637 Xapian::Enquire
enq(db
);
639 Xapian::MSet
mset1(enq
.get_mset(0, 3));
640 TEST_EQUAL(mset1
.size(), 1);
643 Xapian::DecreasingValueWeightPostingSource
ps(3);
644 Xapian::Query
q(&ps
);
645 Xapian::Enquire
enq(db
);
647 Xapian::MSet
mset1(enq
.get_mset(0, 3));
648 TEST_EQUAL(mset1
.size(), 0);