Qualify std::size_t and include <cstddef> for it
[xapian.git] / xapian-core / tests / api_none.cc
blobeaa701e0993aa1f73fa7e02ef9082a93e2262a6a
1 /** @file api_none.cc
2 * @brief tests which don't need a backend
3 */
4 /* Copyright (C) 2009 Richard Boulton
5 * Copyright (C) 2009,2010,2011,2013,2014,2015,2016,2017 Olly Betts
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
20 * USA
23 #include <config.h>
25 #include "api_none.h"
27 #define XAPIAN_DEPRECATED(D) D
28 #include <xapian.h>
30 #include "apitest.h"
31 #include "str.h"
32 #include "testsuite.h"
33 #include "testutils.h"
35 using namespace std;
37 // Check the version functions give consistent results.
38 DEFINE_TESTCASE(version1, !backend) {
39 string version = str(Xapian::major_version());
40 version += '.';
41 version += str(Xapian::minor_version());
42 version += '.';
43 version += str(Xapian::revision());
44 TEST_EQUAL(Xapian::version_string(), version);
45 return true;
48 // Regression test: various methods on Database() used to segfault or cause
49 // division by 0. Fixed in 1.1.4 and 1.0.18. Ticket#415.
50 DEFINE_TESTCASE(nosubdatabases1, !backend) {
51 Xapian::Database db;
52 TEST(db.get_metadata("foo").empty());
53 TEST_EQUAL(db.metadata_keys_begin(), db.metadata_keys_end());
54 TEST_EXCEPTION(Xapian::InvalidOperationError, db.termlist_begin(1));
55 TEST_EQUAL(db.allterms_begin(), db.allterms_end());
56 TEST_EQUAL(db.allterms_begin("foo"), db.allterms_end("foo"));
57 TEST_EXCEPTION(Xapian::InvalidOperationError, db.positionlist_begin(1, "foo"));
58 TEST_EQUAL(db.get_lastdocid(), 0);
59 TEST_EQUAL(db.valuestream_begin(7), db.valuestream_end(7));
60 TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_doclength(1));
61 TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_unique_terms(1));
62 TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_document(1));
63 return true;
66 /// Feature test for Document::add_boolean_term(), new in 1.0.18/1.1.4.
67 DEFINE_TESTCASE(document1, !backend) {
68 Xapian::Document doc;
69 doc.add_boolean_term("Hxapian.org");
70 TEST_EQUAL(doc.termlist_count(), 1);
71 Xapian::TermIterator t = doc.termlist_begin();
72 TEST(t != doc.termlist_end());
73 TEST_EQUAL(*t, "Hxapian.org");
74 TEST_EQUAL(t.get_wdf(), 0);
75 TEST(++t == doc.termlist_end());
76 doc.remove_term("Hxapian.org");
77 TEST_EQUAL(doc.termlist_count(), 0);
78 TEST(doc.termlist_begin() == doc.termlist_end());
79 return true;
82 /// Regression test - the docid wasn't initialised prior to 1.0.22/1.2.4.
83 DEFINE_TESTCASE(document2, !backend) {
84 Xapian::Document doc;
85 // The return value is uninitialised, so running under valgrind this
86 // will fail reliably prior to the fix.
87 TEST_EQUAL(doc.get_docid(), 0);
88 return true;
91 /// Feature tests for Document::clear_terms().
92 DEFINE_TESTCASE(documentclearterms1, !backend) {
94 Xapian::Document doc;
95 doc.add_boolean_term("Hlocalhost");
96 doc.add_term("hello");
97 doc.add_term("there", 2);
98 doc.add_posting("positional", 1);
99 doc.add_posting("information", 2, 3);
100 TEST_EQUAL(doc.termlist_count(), 5);
101 TEST(doc.termlist_begin() != doc.termlist_end());
102 doc.clear_terms();
103 TEST_EQUAL(doc.termlist_count(), 0);
104 TEST(doc.termlist_begin() == doc.termlist_end());
105 // Test clear_terms() when there are no terms.
106 doc.clear_terms();
107 TEST_EQUAL(doc.termlist_count(), 0);
108 TEST(doc.termlist_begin() == doc.termlist_end());
112 // Test clear_terms() when there have never been any terms.
113 Xapian::Document doc;
114 doc.clear_terms();
115 TEST_EQUAL(doc.termlist_count(), 0);
116 TEST(doc.termlist_begin() == doc.termlist_end());
119 return true;
122 /// Feature tests for Document::clear_values().
123 DEFINE_TESTCASE(documentclearvalues1, !backend) {
125 Xapian::Document doc;
126 doc.add_value(37, "hello");
127 doc.add_value(42, "world");
128 TEST_EQUAL(doc.values_count(), 2);
129 TEST(doc.values_begin() != doc.values_end());
130 doc.clear_values();
131 TEST_EQUAL(doc.values_count(), 0);
132 TEST(doc.values_begin() == doc.values_end());
133 // Test clear_values() when there are no values.
134 doc.clear_values();
135 TEST_EQUAL(doc.values_count(), 0);
136 TEST(doc.values_begin() == doc.values_end());
140 // Test clear_values() when there have never been any values.
141 Xapian::Document doc;
142 doc.clear_values();
143 TEST_EQUAL(doc.values_count(), 0);
144 TEST(doc.termlist_begin() == doc.termlist_end());
147 return true;
150 /// Feature tests for errors for empty terms.
151 DEFINE_TESTCASE(documentemptyterm1, !backend) {
152 Xapian::Document doc;
153 TEST_EXCEPTION(Xapian::InvalidArgumentError,
154 doc.add_boolean_term(string()));
155 TEST_EXCEPTION(Xapian::InvalidArgumentError,
156 doc.add_term(string()));
157 TEST_EXCEPTION(Xapian::InvalidArgumentError,
158 doc.add_posting(string(), 1));
159 TEST_EXCEPTION(Xapian::InvalidArgumentError,
160 doc.add_posting(string(), 2, 3));
161 TEST_EXCEPTION(Xapian::InvalidArgumentError,
162 doc.remove_term(string()));
163 TEST_EXCEPTION(Xapian::InvalidArgumentError,
164 doc.remove_posting(string(), 1));
165 TEST_EXCEPTION(Xapian::InvalidArgumentError,
166 doc.remove_posting(string(), 2, 3));
167 return true;
170 DEFINE_TESTCASE(emptyquery4, !backend) {
171 // Test we get an empty query from applying any of the following ops to
172 // an empty list of subqueries.
173 Xapian::Query q;
174 TEST(Xapian::Query(q.OP_AND, &q, &q).empty());
175 TEST(Xapian::Query(q.OP_OR, &q, &q).empty());
176 TEST(Xapian::Query(q.OP_AND_NOT, &q, &q).empty());
177 TEST(Xapian::Query(q.OP_XOR, &q, &q).empty());
178 TEST(Xapian::Query(q.OP_AND_MAYBE, &q, &q).empty());
179 TEST(Xapian::Query(q.OP_FILTER, &q, &q).empty());
180 TEST(Xapian::Query(q.OP_NEAR, &q, &q).empty());
181 TEST(Xapian::Query(q.OP_PHRASE, &q, &q).empty());
182 TEST(Xapian::Query(q.OP_ELITE_SET, &q, &q).empty());
183 TEST(Xapian::Query(q.OP_SYNONYM, &q, &q).empty());
184 TEST(Xapian::Query(q.OP_MAX, &q, &q).empty());
185 return true;
188 DEFINE_TESTCASE(singlesubquery1, !backend) {
189 // Test that we get just the subquery if we apply any of the following
190 // ops to just that subquery.
191 #define singlesubquery1_(OP) \
192 TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
193 "Query(test)")
194 Xapian::Query q[1] = { Xapian::Query("test") };
195 singlesubquery1_(OP_AND);
196 singlesubquery1_(OP_OR);
197 singlesubquery1_(OP_AND_NOT);
198 singlesubquery1_(OP_XOR);
199 singlesubquery1_(OP_AND_MAYBE);
200 singlesubquery1_(OP_FILTER);
201 singlesubquery1_(OP_NEAR);
202 singlesubquery1_(OP_PHRASE);
203 singlesubquery1_(OP_ELITE_SET);
204 singlesubquery1_(OP_SYNONYM);
205 singlesubquery1_(OP_MAX);
206 return true;
209 DEFINE_TESTCASE(singlesubquery2, !backend) {
210 // Like the previous test, but using MatchNothing as the subquery.
211 #define singlesubquery2_(OP) \
212 TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
213 "Query()")
214 Xapian::Query q[1] = { Xapian::Query::MatchNothing };
215 singlesubquery2_(OP_AND);
216 singlesubquery2_(OP_OR);
217 singlesubquery2_(OP_AND_NOT);
218 singlesubquery2_(OP_XOR);
219 singlesubquery2_(OP_AND_MAYBE);
220 singlesubquery2_(OP_FILTER);
221 singlesubquery2_(OP_NEAR);
222 singlesubquery2_(OP_PHRASE);
223 singlesubquery2_(OP_ELITE_SET);
224 singlesubquery2_(OP_SYNONYM);
225 singlesubquery2_(OP_MAX);
226 return true;
229 DEFINE_TESTCASE(singlesubquery3, !backend) {
230 // Like the previous test, but using MatchAll as the subquery.
231 #define singlesubquery3_(OP) \
232 TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
233 "Query(<alldocuments>)")
234 Xapian::Query q[1] = { Xapian::Query::MatchAll };
235 singlesubquery3_(OP_AND);
236 singlesubquery3_(OP_OR);
237 singlesubquery3_(OP_AND_NOT);
238 singlesubquery3_(OP_XOR);
239 singlesubquery3_(OP_AND_MAYBE);
240 singlesubquery3_(OP_FILTER);
241 // OP_NEAR and OP_PHRASE over MatchAll doesn't really make sense.
242 singlesubquery3_(OP_ELITE_SET);
243 singlesubquery3_(OP_SYNONYM);
244 singlesubquery3_(OP_MAX);
245 return true;
248 /// Check we no longer combine wqf for same term at the same position.
249 DEFINE_TESTCASE(combinewqfnomore1, !backend) {
250 Xapian::Query q(Xapian::Query::OP_OR,
251 Xapian::Query("beer", 1, 1),
252 Xapian::Query("beer", 1, 1));
253 // Prior to 1.3.0, we would have given beer@2, but we decided that wasn't
254 // really useful or helpful.
255 TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
256 return true;
259 class DestroyedFlag {
260 bool & destroyed;
262 public:
263 DestroyedFlag(bool & destroyed_) : destroyed(destroyed_) {
264 destroyed = false;
267 ~DestroyedFlag() {
268 destroyed = true;
272 class TestRangeProcessor : public Xapian::RangeProcessor {
273 DestroyedFlag destroyed;
275 public:
276 TestRangeProcessor(bool & destroyed_)
277 : Xapian::RangeProcessor(0), destroyed(destroyed_) { }
279 Xapian::Query operator()(const std::string&, const std::string&)
281 return Xapian::Query::MatchAll;
285 /// Check reference counting of user-subclassable classes.
286 DEFINE_TESTCASE(subclassablerefcount1, !backend) {
287 bool gone_auto, gone;
289 // Simple test of release().
291 Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
292 TEST(!gone);
293 Xapian::QueryParser qp;
294 qp.add_rangeprocessor(rp->release());
295 TEST(!gone);
297 TEST(gone);
299 // Check a second call to release() has no effect.
301 Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
302 TEST(!gone);
303 Xapian::QueryParser qp;
304 qp.add_rangeprocessor(rp->release());
305 rp->release();
306 TEST(!gone);
308 TEST(gone);
310 // Test reference counting works, and that a RangeProcessor with automatic
311 // storage works OK.
313 TestRangeProcessor rp_auto(gone_auto);
314 TEST(!gone_auto);
316 Xapian::QueryParser qp1;
318 Xapian::QueryParser qp2;
319 Xapian::RangeProcessor * rp;
320 rp = new TestRangeProcessor(gone);
321 TEST(!gone);
322 qp1.add_rangeprocessor(rp->release());
323 TEST(!gone);
324 qp2.add_rangeprocessor(rp);
325 TEST(!gone);
326 qp2.add_rangeprocessor(&rp_auto);
327 TEST(!gone);
328 TEST(!gone_auto);
330 TEST(!gone);
332 TEST(gone);
333 TEST(!gone_auto);
335 TEST(gone_auto);
337 // Regression test for initial implementation, where ~opt_intrusive_ptr()
338 // checked the reference of the object, which may have already been deleted
339 // if it wasn't been reference counted.
341 Xapian::QueryParser qp;
343 Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
344 TEST(!gone);
345 qp.add_rangeprocessor(rp);
346 delete rp;
347 TEST(gone);
349 // At the end of this block, qp is destroyed, but mustn't dereference
350 // the pointer it has to rp. If it does, that should get caught
351 // when tests are run under valgrind.
354 return true;
357 class TestFieldProcessor : public Xapian::FieldProcessor {
358 DestroyedFlag destroyed;
360 public:
361 TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
363 Xapian::Query operator()(const string &str) {
364 return Xapian::Query(str);
368 /// Check reference counting of user-subclassable classes.
369 DEFINE_TESTCASE(subclassablerefcount2, !backend) {
370 bool gone_auto, gone;
372 // Simple test of release().
374 Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
375 TEST(!gone);
376 Xapian::QueryParser qp;
377 qp.add_prefix("foo", proc->release());
378 TEST(!gone);
380 TEST(gone);
382 // Check a second call to release() has no effect.
384 Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
385 TEST(!gone);
386 Xapian::QueryParser qp;
387 qp.add_prefix("foo", proc->release());
388 proc->release();
389 TEST(!gone);
391 TEST(gone);
393 // Test reference counting works, and that a FieldProcessor with automatic
394 // storage works OK.
396 TestFieldProcessor proc_auto(gone_auto);
397 TEST(!gone_auto);
399 Xapian::QueryParser qp1;
401 Xapian::QueryParser qp2;
402 Xapian::FieldProcessor * proc;
403 proc = new TestFieldProcessor(gone);
404 TEST(!gone);
405 qp1.add_prefix("foo", proc->release());
406 TEST(!gone);
407 qp2.add_prefix("foo", proc);
408 TEST(!gone);
409 qp2.add_prefix("bar", &proc_auto);
410 TEST(!gone);
411 TEST(!gone_auto);
413 TEST(!gone);
415 TEST(gone);
416 TEST(!gone_auto);
418 TEST(gone_auto);
420 return true;
423 class TestMatchSpy : public Xapian::MatchSpy {
424 DestroyedFlag destroyed;
426 public:
427 TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
429 void operator()(const Xapian::Document &, double) { }
432 /// Check reference counting of MatchSpy.
433 DEFINE_TESTCASE(subclassablerefcount3, backend) {
434 Xapian::Database db = get_database("apitest_simpledata");
436 bool gone_auto, gone;
438 // Simple test of release().
440 Xapian::MatchSpy * spy = new TestMatchSpy(gone);
441 TEST(!gone);
442 Xapian::Enquire enquire(db);
443 enquire.add_matchspy(spy->release());
444 TEST(!gone);
446 TEST(gone);
448 // Check a second call to release() has no effect.
450 Xapian::MatchSpy * spy = new TestMatchSpy(gone);
451 TEST(!gone);
452 Xapian::Enquire enquire(db);
453 enquire.add_matchspy(spy->release());
454 spy->release();
455 TEST(!gone);
457 TEST(gone);
459 // Test reference counting works, and that a MatchSpy with automatic
460 // storage works OK.
462 TestMatchSpy spy_auto(gone_auto);
463 TEST(!gone_auto);
465 Xapian::Enquire enq1(db);
467 Xapian::Enquire enq2(db);
468 Xapian::MatchSpy * spy;
469 spy = new TestMatchSpy(gone);
470 TEST(!gone);
471 enq1.add_matchspy(spy->release());
472 TEST(!gone);
473 enq2.add_matchspy(spy);
474 TEST(!gone);
475 enq2.add_matchspy(&spy_auto);
476 TEST(!gone);
477 TEST(!gone_auto);
479 TEST(!gone);
481 TEST(gone);
482 TEST(!gone_auto);
484 TEST(gone_auto);
486 return true;
489 class TestStopper : public Xapian::Stopper {
490 DestroyedFlag destroyed;
492 public:
493 TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
495 bool operator()(const std::string&) const { return true; }
498 /// Check reference counting of Stopper with QueryParser.
499 DEFINE_TESTCASE(subclassablerefcount4, !backend) {
500 bool gone_auto, gone;
502 // Simple test of release().
504 Xapian::Stopper * stopper = new TestStopper(gone);
505 TEST(!gone);
506 Xapian::QueryParser qp;
507 qp.set_stopper(stopper->release());
508 TEST(!gone);
510 TEST(gone);
512 // Test that setting a new stopper causes the previous one to be released.
514 bool gone0;
515 Xapian::Stopper * stopper0 = new TestStopper(gone0);
516 TEST(!gone0);
517 Xapian::QueryParser qp;
518 qp.set_stopper(stopper0->release());
519 TEST(!gone0);
521 Xapian::Stopper * stopper = new TestStopper(gone);
522 TEST(!gone);
523 qp.set_stopper(stopper->release());
524 TEST(gone0);
525 TEST(!gone);
527 TEST(gone);
529 // Check a second call to release() has no effect.
531 Xapian::Stopper * stopper = new TestStopper(gone);
532 TEST(!gone);
533 Xapian::QueryParser qp;
534 qp.set_stopper(stopper->release());
535 stopper->release();
536 TEST(!gone);
538 TEST(gone);
540 // Test reference counting works, and that a Stopper with automatic
541 // storage works OK.
543 TestStopper stopper_auto(gone_auto);
544 TEST(!gone_auto);
546 Xapian::QueryParser qp1;
548 Xapian::QueryParser qp2;
549 Xapian::Stopper * stopper;
550 stopper = new TestStopper(gone);
551 TEST(!gone);
552 qp1.set_stopper(stopper->release());
553 TEST(!gone);
554 qp2.set_stopper(stopper);
555 TEST(!gone);
556 qp2.set_stopper(&stopper_auto);
557 TEST(!gone);
558 TEST(!gone_auto);
560 TEST(!gone);
562 TEST(gone);
563 TEST(!gone_auto);
565 TEST(gone_auto);
567 return true;
570 /// Check reference counting of Stopper with TermGenerator.
571 DEFINE_TESTCASE(subclassablerefcount5, !backend) {
572 bool gone_auto, gone;
574 // Simple test of release().
576 Xapian::Stopper * stopper = new TestStopper(gone);
577 TEST(!gone);
578 Xapian::TermGenerator indexer;
579 indexer.set_stopper(stopper->release());
580 TEST(!gone);
582 TEST(gone);
584 // Test that setting a new stopper causes the previous one to be released.
586 bool gone0;
587 Xapian::Stopper * stopper0 = new TestStopper(gone0);
588 TEST(!gone0);
589 Xapian::TermGenerator indexer;
590 indexer.set_stopper(stopper0->release());
591 TEST(!gone0);
593 Xapian::Stopper * stopper = new TestStopper(gone);
594 TEST(!gone);
595 indexer.set_stopper(stopper->release());
596 TEST(gone0);
597 TEST(!gone);
599 TEST(gone);
601 // Check a second call to release() has no effect.
603 Xapian::Stopper * stopper = new TestStopper(gone);
604 TEST(!gone);
605 Xapian::TermGenerator indexer;
606 indexer.set_stopper(stopper->release());
607 stopper->release();
608 TEST(!gone);
610 TEST(gone);
612 // Test reference counting works, and that a Stopper with automatic
613 // storage works OK.
615 TestStopper stopper_auto(gone_auto);
616 TEST(!gone_auto);
618 Xapian::TermGenerator indexer1;
620 Xapian::TermGenerator indexer2;
621 Xapian::Stopper * stopper;
622 stopper = new TestStopper(gone);
623 TEST(!gone);
624 indexer1.set_stopper(stopper->release());
625 TEST(!gone);
626 indexer2.set_stopper(stopper);
627 TEST(!gone);
628 indexer2.set_stopper(&stopper_auto);
629 TEST(!gone);
630 TEST(!gone_auto);
632 TEST(!gone);
634 TEST(gone);
635 TEST(!gone_auto);
637 TEST(gone_auto);
639 return true;
642 class TestKeyMaker : public Xapian::KeyMaker {
643 DestroyedFlag destroyed;
645 public:
646 TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
648 string operator()(const Xapian::Document&) const { return string(); }
651 /// Check reference counting of KeyMaker.
652 DEFINE_TESTCASE(subclassablerefcount6, backend) {
653 Xapian::Database db = get_database("apitest_simpledata");
655 bool gone_auto, gone;
657 // Simple test of release().
659 Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
660 TEST(!gone);
661 Xapian::Enquire enq(db);
662 enq.set_sort_by_key(keymaker->release(), false);
663 TEST(!gone);
665 TEST(gone);
667 // Test that setting a new keymaker causes the previous one to be released.
669 bool gone0;
670 Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
671 TEST(!gone0);
672 Xapian::Enquire enq(db);
673 enq.set_sort_by_key(keymaker0->release(), false);
674 TEST(!gone0);
676 Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
677 TEST(!gone);
678 enq.set_sort_by_key_then_relevance(keymaker->release(), false);
679 TEST(gone0);
680 TEST(!gone);
682 TEST(gone);
684 // Check a second call to release() has no effect.
686 Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
687 TEST(!gone);
688 Xapian::Enquire enq(db);
689 enq.set_sort_by_key(keymaker->release(), false);
690 keymaker->release();
691 TEST(!gone);
693 TEST(gone);
695 // Test reference counting works, and that a KeyMaker with automatic
696 // storage works OK.
698 TestKeyMaker keymaker_auto(gone_auto);
699 TEST(!gone_auto);
701 Xapian::Enquire enq1(db);
703 Xapian::Enquire enq2(db);
704 Xapian::KeyMaker * keymaker;
705 keymaker = new TestKeyMaker(gone);
706 TEST(!gone);
707 enq1.set_sort_by_key(keymaker->release(), false);
708 TEST(!gone);
709 enq2.set_sort_by_relevance_then_key(keymaker, false);
710 TEST(!gone);
711 enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
712 TEST(!gone);
713 TEST(!gone_auto);
715 TEST(!gone);
717 TEST(gone);
718 TEST(!gone_auto);
720 TEST(gone_auto);
722 return true;
725 class TestExpandDecider : public Xapian::ExpandDecider {
726 DestroyedFlag destroyed;
728 public:
729 TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
731 bool operator()(const string&) const { return true; }
734 /// Check reference counting of ExpandDecider.
735 DEFINE_TESTCASE(subclassablerefcount7, backend) {
736 Xapian::Database db = get_database("apitest_simpledata");
737 Xapian::Enquire enq(db);
738 Xapian::RSet rset;
739 rset.add_document(1);
741 bool gone_auto, gone;
743 for (int flags = 0;
744 flags <= Xapian::Enquire::INCLUDE_QUERY_TERMS;
745 flags += Xapian::Enquire::INCLUDE_QUERY_TERMS) {
746 // Test of auto lifetime ExpandDecider.
748 TestExpandDecider edecider_auto(gone_auto);
749 TEST(!gone_auto);
750 (void)enq.get_eset(5, rset, 0, &edecider_auto);
751 TEST(!gone_auto);
753 TEST(gone_auto);
755 // Simple test of release().
757 Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
758 TEST(!gone);
759 (void)enq.get_eset(5, rset, 0, edecider);
760 TEST(!gone);
761 delete edecider;
762 TEST(gone);
765 // Test that a released ExpandDecider gets cleaned up by get_eset().
767 Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
768 TEST(!gone);
769 (void)enq.get_eset(5, rset, 0, edecider->release());
770 TEST(gone);
773 // Check a second call to release() has no effect.
775 Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
776 TEST(!gone);
777 edecider->release();
778 TEST(!gone);
779 (void)enq.get_eset(5, rset, 0, edecider->release());
780 TEST(gone);
784 // Test combinations of released/non-released with ExpandDeciderAnd.
786 TestExpandDecider edecider_auto(gone_auto);
787 TEST(!gone_auto);
788 Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
789 TEST(!gone);
790 (void)enq.get_eset(5, rset, 0,
791 (new Xapian::ExpandDeciderAnd(
792 &edecider_auto,
793 edecider->release()))->release());
794 TEST(!gone_auto);
795 TEST(gone);
797 TEST(gone_auto);
799 TestExpandDecider edecider_auto(gone_auto);
800 TEST(!gone_auto);
801 Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
802 TEST(!gone);
803 (void)enq.get_eset(5, rset, 0,
804 (new Xapian::ExpandDeciderAnd(
805 edecider->release(),
806 &edecider_auto))->release());
807 TEST(!gone_auto);
808 TEST(gone);
810 TEST(gone_auto);
812 return true;
815 class TestValueRangeProcessor : public Xapian::ValueRangeProcessor {
816 DestroyedFlag destroyed;
818 public:
819 TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) { }
821 Xapian::valueno operator()(std::string &, std::string &) {
822 return 42;
826 /// Check reference counting of user-subclassable classes.
827 DEFINE_TESTCASE(subclassablerefcount8, !backend) {
828 bool gone_auto, gone;
830 // Simple test of release().
832 Xapian::ValueRangeProcessor * vrp = new TestValueRangeProcessor(gone);
833 TEST(!gone);
834 Xapian::QueryParser qp;
835 qp.add_valuerangeprocessor(vrp->release());
836 TEST(!gone);
838 TEST(gone);
840 // Check a second call to release() has no effect.
842 Xapian::ValueRangeProcessor * vrp = new TestValueRangeProcessor(gone);
843 TEST(!gone);
844 Xapian::QueryParser qp;
845 qp.add_valuerangeprocessor(vrp->release());
846 vrp->release();
847 TEST(!gone);
849 TEST(gone);
851 // Test reference counting works, and that a VRP with automatic storage
852 // works OK.
854 TestValueRangeProcessor vrp_auto(gone_auto);
855 TEST(!gone_auto);
857 Xapian::QueryParser qp1;
859 Xapian::QueryParser qp2;
860 Xapian::ValueRangeProcessor * vrp;
861 vrp = new TestValueRangeProcessor(gone);
862 TEST(!gone);
863 qp1.add_valuerangeprocessor(vrp->release());
864 TEST(!gone);
865 qp2.add_valuerangeprocessor(vrp);
866 TEST(!gone);
867 qp2.add_valuerangeprocessor(&vrp_auto);
868 TEST(!gone);
869 TEST(!gone_auto);
871 TEST(!gone);
873 TEST(gone);
874 TEST(!gone_auto);
876 TEST(gone_auto);
878 // Regression test for initial implementation, where ~opt_intrusive_ptr()
879 // checked the reference of the object, which may have already been deleted
880 // if it wasn't been reference counted.
882 Xapian::QueryParser qp;
884 Xapian::ValueRangeProcessor * vrp =
885 new TestValueRangeProcessor(gone);
886 TEST(!gone);
887 qp.add_valuerangeprocessor(vrp);
888 delete vrp;
889 TEST(gone);
891 // At the end of this block, qp is destroyed, but mustn't dereference
892 // the pointer it has to vrp. If it does, that should get caught
893 // when tests are run under valgrind.
896 return true;
899 /// Check encoding of non-UTF8 document data.
900 DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
901 Xapian::Document doc;
902 doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
903 TEST_EQUAL(doc.get_description(),
904 "Document(docid=0, data=\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff)");
905 doc.set_data(string("\x00\x1f", 2));
906 TEST_EQUAL(doc.get_description(),
907 "Document(docid=0, data=\\x00\\x1f)");
908 // Check that backslashes are encoded so output isn't ambiguous.
909 doc.set_data("back\\slash");
910 TEST_EQUAL(doc.get_description(),
911 "Document(docid=0, data=back\\x5cslash)");
912 return true;
915 DEFINE_TESTCASE(orphaneddoctermitor1, !backend) {
916 Xapian::TermIterator t;
918 Xapian::Document doc;
919 doc.add_term("foo");
920 t = doc.termlist_begin();
922 TEST_EQUAL(*t, "foo");
923 return true;