xapian-core  1.4.25
api_none.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2009 Richard Boulton
5  * Copyright (C) 2009,2010,2011,2013,2014,2015,2016,2017,2018 Olly Betts
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_none.h"
26 
27 #define XAPIAN_DEPRECATED(D) D
28 #include <xapian.h>
29 
30 #include "apitest.h"
31 #include "str.h"
32 #include "testsuite.h"
33 #include "testutils.h"
34 
35 using namespace std;
36 
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());
45 }
46 
47 // Regression test: various methods on Database() used to segfault or cause
48 // division by 0. Fixed in 1.1.4 and 1.0.18. Ticket#415.
49 DEFINE_TESTCASE(nosubdatabases1, !backend) {
51  TEST(db.get_metadata("foo").empty());
55  TEST_EQUAL(db.allterms_begin("foo"), db.allterms_end("foo"));
57  TEST_EQUAL(db.get_lastdocid(), 0);
62 
64  TEST_EXCEPTION(Xapian::InvalidOperationError, wdb.begin_transaction());
65  TEST_EXCEPTION(Xapian::InvalidOperationError, wdb.commit_transaction());
66  TEST_EXCEPTION(Xapian::InvalidOperationError, wdb.cancel_transaction());
67 }
68 
70 DEFINE_TESTCASE(document1, !backend) {
71  Xapian::Document doc;
72  doc.add_boolean_term("Hxapian.org");
73  TEST_EQUAL(doc.termlist_count(), 1);
75  TEST(t != doc.termlist_end());
76  TEST_EQUAL(*t, "Hxapian.org");
77  TEST_EQUAL(t.get_wdf(), 0);
78  TEST(++t == doc.termlist_end());
79  doc.remove_term("Hxapian.org");
80  TEST_EQUAL(doc.termlist_count(), 0);
81  TEST(doc.termlist_begin() == doc.termlist_end());
82 }
83 
85 DEFINE_TESTCASE(document2, !backend) {
86  Xapian::Document doc;
87  // The return value is uninitialised, so running under valgrind this
88  // will fail reliably prior to the fix.
89  TEST_EQUAL(doc.get_docid(), 0);
90 }
91 
93 DEFINE_TESTCASE(documentclearterms1, !backend) {
94  {
95  Xapian::Document doc;
96  doc.add_boolean_term("Hlocalhost");
97  doc.add_term("hello");
98  doc.add_term("there", 2);
99  doc.add_posting("positional", 1);
100  doc.add_posting("information", 2, 3);
101  TEST_EQUAL(doc.termlist_count(), 5);
102  TEST(doc.termlist_begin() != doc.termlist_end());
103  doc.clear_terms();
104  TEST_EQUAL(doc.termlist_count(), 0);
105  TEST(doc.termlist_begin() == doc.termlist_end());
106  // Test clear_terms() when there are no terms.
107  doc.clear_terms();
108  TEST_EQUAL(doc.termlist_count(), 0);
109  TEST(doc.termlist_begin() == doc.termlist_end());
110  }
111 
112  {
113  // Test clear_terms() when there have never been any terms.
114  Xapian::Document doc;
115  doc.clear_terms();
116  TEST_EQUAL(doc.termlist_count(), 0);
117  TEST(doc.termlist_begin() == doc.termlist_end());
118  }
119 }
120 
122 DEFINE_TESTCASE(documentclearvalues1, !backend) {
123  {
124  Xapian::Document doc;
125  doc.add_value(37, "hello");
126  doc.add_value(42, "world");
127  TEST_EQUAL(doc.values_count(), 2);
128  TEST(doc.values_begin() != doc.values_end());
129  doc.clear_values();
130  TEST_EQUAL(doc.values_count(), 0);
131  TEST(doc.values_begin() == doc.values_end());
132  // Test clear_values() when there are no values.
133  doc.clear_values();
134  TEST_EQUAL(doc.values_count(), 0);
135  TEST(doc.values_begin() == doc.values_end());
136  }
137 
138  {
139  // Test clear_values() when there have never been any values.
140  Xapian::Document doc;
141  doc.clear_values();
142  TEST_EQUAL(doc.values_count(), 0);
143  TEST(doc.termlist_begin() == doc.termlist_end());
144  }
145 }
146 
148 DEFINE_TESTCASE(documentemptyterm1, !backend) {
149  Xapian::Document doc;
151  doc.add_boolean_term(string()));
153  doc.add_term(string()));
155  doc.add_posting(string(), 1));
157  doc.add_posting(string(), 2, 3));
159  doc.remove_term(string()));
161  doc.remove_posting(string(), 1));
163  doc.remove_posting(string(), 2, 3));
165  doc.remove_postings(string(), 2, 3));
167  doc.remove_postings(string(), 2, 3, 4));
168 }
169 
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 }
186 
187 DEFINE_TESTCASE(singlesubquery1, !backend) {
188  // Test that we get just the subquery if we apply any of the following
189  // ops to just that subquery.
190 #define singlesubquery1_(OP) \
191  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
192  "Query(test)")
193  Xapian::Query q[1] = { Xapian::Query("test") };
194  singlesubquery1_(OP_AND);
195  singlesubquery1_(OP_OR);
196  singlesubquery1_(OP_AND_NOT);
197  singlesubquery1_(OP_XOR);
198  singlesubquery1_(OP_AND_MAYBE);
199  singlesubquery1_(OP_FILTER);
200  singlesubquery1_(OP_NEAR);
201  singlesubquery1_(OP_PHRASE);
202  singlesubquery1_(OP_ELITE_SET);
203  singlesubquery1_(OP_SYNONYM);
204  singlesubquery1_(OP_MAX);
205 }
206 
207 DEFINE_TESTCASE(singlesubquery2, !backend) {
208  // Like the previous test, but using MatchNothing as the subquery.
209 #define singlesubquery2_(OP) \
210  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
211  "Query()")
213  singlesubquery2_(OP_AND);
214  singlesubquery2_(OP_OR);
215  singlesubquery2_(OP_AND_NOT);
216  singlesubquery2_(OP_XOR);
217  singlesubquery2_(OP_AND_MAYBE);
218  singlesubquery2_(OP_FILTER);
219  singlesubquery2_(OP_NEAR);
220  singlesubquery2_(OP_PHRASE);
221  singlesubquery2_(OP_ELITE_SET);
222  singlesubquery2_(OP_SYNONYM);
223  singlesubquery2_(OP_MAX);
224 }
225 
226 DEFINE_TESTCASE(singlesubquery3, !backend) {
227  // Like the previous test, but using MatchAll as the subquery.
228 #define singlesubquery3_(OP) \
229  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
230  "Query(<alldocuments>)")
232  singlesubquery3_(OP_AND);
233  singlesubquery3_(OP_OR);
234  singlesubquery3_(OP_AND_NOT);
235  singlesubquery3_(OP_XOR);
236  singlesubquery3_(OP_AND_MAYBE);
237  singlesubquery3_(OP_FILTER);
238  // OP_NEAR and OP_PHRASE over MatchAll doesn't really make sense.
239  singlesubquery3_(OP_ELITE_SET);
240  singlesubquery3_(OP_SYNONYM);
241  singlesubquery3_(OP_MAX);
242 }
243 
245 DEFINE_TESTCASE(combinewqfnomore1, !backend) {
247  Xapian::Query("beer", 1, 1),
248  Xapian::Query("beer", 1, 1));
249  // Prior to 1.3.0, we would have given beer@2, but we decided that wasn't
250  // really useful or helpful.
251  TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
252 }
253 
255  bool & destroyed;
256 
257  public:
258  DestroyedFlag(bool & destroyed_) : destroyed(destroyed_) {
259  destroyed = false;
260  }
261 
263  destroyed = true;
264  }
265 };
266 
269 
270  public:
271  TestRangeProcessor(bool & destroyed_)
272  : Xapian::RangeProcessor(0), destroyed(destroyed_) { }
273 
274  Xapian::Query operator()(const std::string&, const std::string&)
275  {
277  }
278 };
279 
281 DEFINE_TESTCASE(subclassablerefcount1, !backend) {
282  bool gone_auto, gone;
283 
284  // Simple test of release().
285  {
287  TEST(!gone);
289  qp.add_rangeprocessor(rp->release());
290  TEST(!gone);
291  }
292  TEST(gone);
293 
294  // Check a second call to release() has no effect.
295  {
297  TEST(!gone);
299  qp.add_rangeprocessor(rp->release());
300  rp->release();
301  TEST(!gone);
302  }
303  TEST(gone);
304 
305  // Test reference counting works, and that a RangeProcessor with automatic
306  // storage works OK.
307  {
308  TestRangeProcessor rp_auto(gone_auto);
309  TEST(!gone_auto);
310  {
312  {
315  rp = new TestRangeProcessor(gone);
316  TEST(!gone);
317  qp1.add_rangeprocessor(rp->release());
318  TEST(!gone);
319  qp2.add_rangeprocessor(rp);
320  TEST(!gone);
321  qp2.add_rangeprocessor(&rp_auto);
322  TEST(!gone);
323  TEST(!gone_auto);
324  }
325  TEST(!gone);
326  }
327  TEST(gone);
328  TEST(!gone_auto);
329  }
330  TEST(gone_auto);
331 
332  // Regression test for initial implementation, where ~opt_intrusive_ptr()
333  // checked the reference of the object, which may have already been deleted
334  // if it wasn't been reference counted.
335  {
337  {
339  TEST(!gone);
340  qp.add_rangeprocessor(rp);
341  delete rp;
342  TEST(gone);
343  }
344  // At the end of this block, qp is destroyed, but mustn't dereference
345  // the pointer it has to rp. If it does, that should get caught
346  // when tests are run under valgrind.
347  }
348 }
349 
352 
353  public:
354  TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
355 
356  Xapian::Query operator()(const string &str) {
357  return Xapian::Query(str);
358  }
359 };
360 
362 DEFINE_TESTCASE(subclassablerefcount2, !backend) {
363  bool gone_auto, gone;
364 
365  // Simple test of release().
366  {
367  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
368  TEST(!gone);
370  qp.add_prefix("foo", proc->release());
371  TEST(!gone);
372  }
373  TEST(gone);
374 
375  // Check a second call to release() has no effect.
376  {
377  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
378  TEST(!gone);
380  qp.add_prefix("foo", proc->release());
381  proc->release();
382  TEST(!gone);
383  }
384  TEST(gone);
385 
386  // Test reference counting works, and that a FieldProcessor with automatic
387  // storage works OK.
388  {
389  TestFieldProcessor proc_auto(gone_auto);
390  TEST(!gone_auto);
391  {
393  {
395  Xapian::FieldProcessor * proc;
396  proc = new TestFieldProcessor(gone);
397  TEST(!gone);
398  qp1.add_prefix("foo", proc->release());
399  TEST(!gone);
400  qp2.add_prefix("foo", proc);
401  TEST(!gone);
402  qp2.add_prefix("bar", &proc_auto);
403  TEST(!gone);
404  TEST(!gone_auto);
405  }
406  TEST(!gone);
407  }
408  TEST(gone);
409  TEST(!gone_auto);
410  }
411  TEST(gone_auto);
412 }
413 
416 
417  public:
418  TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
419 
420  void operator()(const Xapian::Document &, double) { }
421 };
422 
424 DEFINE_TESTCASE(subclassablerefcount3, backend) {
425  Xapian::Database db = get_database("apitest_simpledata");
426 
427  bool gone_auto, gone;
428 
429  // Simple test of release().
430  {
431  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
432  TEST(!gone);
433  Xapian::Enquire enquire(db);
434  enquire.add_matchspy(spy->release());
435  TEST(!gone);
436  }
437  TEST(gone);
438 
439  // Check a second call to release() has no effect.
440  {
441  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
442  TEST(!gone);
443  Xapian::Enquire enquire(db);
444  enquire.add_matchspy(spy->release());
445  spy->release();
446  TEST(!gone);
447  }
448  TEST(gone);
449 
450  // Test reference counting works, and that a MatchSpy with automatic
451  // storage works OK.
452  {
453  TestMatchSpy spy_auto(gone_auto);
454  TEST(!gone_auto);
455  {
456  Xapian::Enquire enq1(db);
457  {
458  Xapian::Enquire enq2(db);
459  Xapian::MatchSpy * spy;
460  spy = new TestMatchSpy(gone);
461  TEST(!gone);
462  enq1.add_matchspy(spy->release());
463  TEST(!gone);
464  enq2.add_matchspy(spy);
465  TEST(!gone);
466  enq2.add_matchspy(&spy_auto);
467  TEST(!gone);
468  TEST(!gone_auto);
469  }
470  TEST(!gone);
471  }
472  TEST(gone);
473  TEST(!gone_auto);
474  }
475  TEST(gone_auto);
476 }
477 
478 class TestStopper : public Xapian::Stopper {
480 
481  public:
482  TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
483 
484  bool operator()(const std::string&) const { return true; }
485 };
486 
488 DEFINE_TESTCASE(subclassablerefcount4, !backend) {
489  bool gone_auto, gone;
490 
491  // Simple test of release().
492  {
493  Xapian::Stopper * stopper = new TestStopper(gone);
494  TEST(!gone);
496  qp.set_stopper(stopper->release());
497  TEST(!gone);
498  }
499  TEST(gone);
500 
501  // Test that setting a new stopper causes the previous one to be released.
502  {
503  bool gone0;
504  Xapian::Stopper * stopper0 = new TestStopper(gone0);
505  TEST(!gone0);
507  qp.set_stopper(stopper0->release());
508  TEST(!gone0);
509 
510  Xapian::Stopper * stopper = new TestStopper(gone);
511  TEST(!gone);
512  qp.set_stopper(stopper->release());
513  TEST(gone0);
514  TEST(!gone);
515  }
516  TEST(gone);
517 
518  // Check a second call to release() has no effect.
519  {
520  Xapian::Stopper * stopper = new TestStopper(gone);
521  TEST(!gone);
523  qp.set_stopper(stopper->release());
524  stopper->release();
525  TEST(!gone);
526  }
527  TEST(gone);
528 
529  // Test reference counting works, and that a Stopper with automatic
530  // storage works OK.
531  {
532  TestStopper stopper_auto(gone_auto);
533  TEST(!gone_auto);
534  {
536  {
538  Xapian::Stopper * stopper;
539  stopper = new TestStopper(gone);
540  TEST(!gone);
541  qp1.set_stopper(stopper->release());
542  TEST(!gone);
543  qp2.set_stopper(stopper);
544  TEST(!gone);
545  qp2.set_stopper(&stopper_auto);
546  TEST(!gone);
547  TEST(!gone_auto);
548  }
549  TEST(!gone);
550  }
551  TEST(gone);
552  TEST(!gone_auto);
553  }
554  TEST(gone_auto);
555 }
556 
558 DEFINE_TESTCASE(subclassablerefcount5, !backend) {
559  bool gone_auto, gone;
560 
561  // Simple test of release().
562  {
563  Xapian::Stopper * stopper = new TestStopper(gone);
564  TEST(!gone);
565  Xapian::TermGenerator indexer;
566  indexer.set_stopper(stopper->release());
567  TEST(!gone);
568  }
569  TEST(gone);
570 
571  // Test that setting a new stopper causes the previous one to be released.
572  {
573  bool gone0;
574  Xapian::Stopper * stopper0 = new TestStopper(gone0);
575  TEST(!gone0);
576  Xapian::TermGenerator indexer;
577  indexer.set_stopper(stopper0->release());
578  TEST(!gone0);
579 
580  Xapian::Stopper * stopper = new TestStopper(gone);
581  TEST(!gone);
582  indexer.set_stopper(stopper->release());
583  TEST(gone0);
584  TEST(!gone);
585  }
586  TEST(gone);
587 
588  // Check a second call to release() has no effect.
589  {
590  Xapian::Stopper * stopper = new TestStopper(gone);
591  TEST(!gone);
592  Xapian::TermGenerator indexer;
593  indexer.set_stopper(stopper->release());
594  stopper->release();
595  TEST(!gone);
596  }
597  TEST(gone);
598 
599  // Test reference counting works, and that a Stopper with automatic
600  // storage works OK.
601  {
602  TestStopper stopper_auto(gone_auto);
603  TEST(!gone_auto);
604  {
605  Xapian::TermGenerator indexer1;
606  {
607  Xapian::TermGenerator indexer2;
608  Xapian::Stopper * stopper;
609  stopper = new TestStopper(gone);
610  TEST(!gone);
611  indexer1.set_stopper(stopper->release());
612  TEST(!gone);
613  indexer2.set_stopper(stopper);
614  TEST(!gone);
615  indexer2.set_stopper(&stopper_auto);
616  TEST(!gone);
617  TEST(!gone_auto);
618  }
619  TEST(!gone);
620  }
621  TEST(gone);
622  TEST(!gone_auto);
623  }
624  TEST(gone_auto);
625 }
626 
629 
630  public:
631  TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
632 
633  string operator()(const Xapian::Document&) const { return string(); }
634 };
635 
637 DEFINE_TESTCASE(subclassablerefcount6, backend) {
638  Xapian::Database db = get_database("apitest_simpledata");
639 
640  bool gone_auto, gone;
641 
642  // Simple test of release().
643  {
644  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
645  TEST(!gone);
646  Xapian::Enquire enq(db);
647  enq.set_sort_by_key(keymaker->release(), false);
648  TEST(!gone);
649  }
650  TEST(gone);
651 
652  // Test that setting a new keymaker causes the previous one to be released.
653  {
654  bool gone0;
655  Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
656  TEST(!gone0);
657  Xapian::Enquire enq(db);
658  enq.set_sort_by_key(keymaker0->release(), false);
659  TEST(!gone0);
660 
661  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
662  TEST(!gone);
663  enq.set_sort_by_key_then_relevance(keymaker->release(), false);
664  TEST(gone0);
665  TEST(!gone);
666  }
667  TEST(gone);
668 
669  // Check a second call to release() has no effect.
670  {
671  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
672  TEST(!gone);
673  Xapian::Enquire enq(db);
674  enq.set_sort_by_key(keymaker->release(), false);
675  keymaker->release();
676  TEST(!gone);
677  }
678  TEST(gone);
679 
680  // Test reference counting works, and that a KeyMaker with automatic
681  // storage works OK.
682  {
683  TestKeyMaker keymaker_auto(gone_auto);
684  TEST(!gone_auto);
685  {
686  Xapian::Enquire enq1(db);
687  {
688  Xapian::Enquire enq2(db);
689  Xapian::KeyMaker * keymaker;
690  keymaker = new TestKeyMaker(gone);
691  TEST(!gone);
692  enq1.set_sort_by_key(keymaker->release(), false);
693  TEST(!gone);
694  enq2.set_sort_by_relevance_then_key(keymaker, false);
695  TEST(!gone);
696  enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
697  TEST(!gone);
698  TEST(!gone_auto);
699  }
700  TEST(!gone);
701  }
702  TEST(gone);
703  TEST(!gone_auto);
704  }
705  TEST(gone_auto);
706 }
707 
710 
711  public:
712  TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
713 
714  bool operator()(const string&) const { return true; }
715 };
716 
718 DEFINE_TESTCASE(subclassablerefcount7, backend) {
719  Xapian::Database db = get_database("apitest_simpledata");
720  Xapian::Enquire enq(db);
721  Xapian::RSet rset;
722  rset.add_document(1);
723 
724  bool gone_auto, gone;
725 
726  for (int flags = 0;
729  // Test of auto lifetime ExpandDecider.
730  {
731  TestExpandDecider edecider_auto(gone_auto);
732  TEST(!gone_auto);
733  (void)enq.get_eset(5, rset, 0, &edecider_auto);
734  TEST(!gone_auto);
735  }
736  TEST(gone_auto);
737 
738  // Simple test of release().
739  {
740  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
741  TEST(!gone);
742  (void)enq.get_eset(5, rset, 0, edecider);
743  TEST(!gone);
744  delete edecider;
745  TEST(gone);
746  }
747 
748  // Test that a released ExpandDecider gets cleaned up by get_eset().
749  {
750  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
751  TEST(!gone);
752  (void)enq.get_eset(5, rset, 0, edecider->release());
753  TEST(gone);
754  }
755 
756  // Check a second call to release() has no effect.
757  {
758  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
759  TEST(!gone);
760  edecider->release();
761  TEST(!gone);
762  (void)enq.get_eset(5, rset, 0, edecider->release());
763  TEST(gone);
764  }
765  }
766 
767  // Test combinations of released/non-released with ExpandDeciderAnd.
768  {
769  TestExpandDecider edecider_auto(gone_auto);
770  TEST(!gone_auto);
771  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
772  TEST(!gone);
773  (void)enq.get_eset(5, rset, 0,
775  &edecider_auto,
776  edecider->release()))->release());
777  TEST(!gone_auto);
778  TEST(gone);
779  }
780  TEST(gone_auto);
781  {
782  TestExpandDecider edecider_auto(gone_auto);
783  TEST(!gone_auto);
784  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
785  TEST(!gone);
786  (void)enq.get_eset(5, rset, 0,
788  edecider->release(),
789  &edecider_auto))->release());
790  TEST(!gone_auto);
791  TEST(gone);
792  }
793  TEST(gone_auto);
794 }
795 
798 
799  public:
800  TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) { }
801 
802  Xapian::valueno operator()(std::string &, std::string &) {
803  return 42;
804  }
805 };
806 
808 DEFINE_TESTCASE(subclassablerefcount8, !backend) {
809  bool gone_auto, gone;
810 
811  // Simple test of release().
812  {
814  TEST(!gone);
816  qp.add_valuerangeprocessor(vrp->release());
817  TEST(!gone);
818  }
819  TEST(gone);
820 
821  // Check a second call to release() has no effect.
822  {
824  TEST(!gone);
826  qp.add_valuerangeprocessor(vrp->release());
827  vrp->release();
828  TEST(!gone);
829  }
830  TEST(gone);
831 
832  // Test reference counting works, and that a VRP with automatic storage
833  // works OK.
834  {
835  TestValueRangeProcessor vrp_auto(gone_auto);
836  TEST(!gone_auto);
837  {
839  {
842  vrp = new TestValueRangeProcessor(gone);
843  TEST(!gone);
844  qp1.add_valuerangeprocessor(vrp->release());
845  TEST(!gone);
846  qp2.add_valuerangeprocessor(vrp);
847  TEST(!gone);
848  qp2.add_valuerangeprocessor(&vrp_auto);
849  TEST(!gone);
850  TEST(!gone_auto);
851  }
852  TEST(!gone);
853  }
854  TEST(gone);
855  TEST(!gone_auto);
856  }
857  TEST(gone_auto);
858 
859  // Regression test for initial implementation, where ~opt_intrusive_ptr()
860  // checked the reference of the object, which may have already been deleted
861  // if it wasn't been reference counted.
862  {
864  {
866  new TestValueRangeProcessor(gone);
867  TEST(!gone);
868  qp.add_valuerangeprocessor(vrp);
869  delete vrp;
870  TEST(gone);
871  }
872  // At the end of this block, qp is destroyed, but mustn't dereference
873  // the pointer it has to vrp. If it does, that should get caught
874  // when tests are run under valgrind.
875  }
876 }
877 
879 DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
880  Xapian::Document doc;
881  doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
883  "Document(data='\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff')");
884  doc.set_data(string("\x00\x1f", 2));
886  "Document(data='\\x00\\x1f')");
887  // Check that backslashes are encoded so output isn't ambiguous.
888  doc.set_data("back\\slash");
890  "Document(data='back\\x5cslash')");
891 }
892 
899 DEFINE_TESTCASE(deletewhileiterating1, !backend) {
900  for (bool preinc : { false, true }) {
901  Xapian::Document doc;
902  Xapian::TermGenerator indexer;
903  indexer.set_document(doc);
904  indexer.index_text("Pull the rug out from under ourselves", 1, "S");
905  Xapian::TermIterator term_iterator = doc.termlist_begin();
906  term_iterator.skip_to("S");
907  while (term_iterator != doc.termlist_end()) {
908  const string& term = *term_iterator;
909  if (!startswith(term, "S")) {
910  break;
911  }
912  if (preinc) ++term_iterator;
913  doc.remove_term(term);
914  if (!preinc) ++term_iterator;
915  }
916  TEST_EQUAL(doc.termlist_count(), 0);
917  TEST(doc.termlist_begin() == doc.termlist_end());
918  }
919 }
920 
922 DEFINE_TESTCASE(removepostings, !backend) {
923  Xapian::Document doc;
924  // Add Fibonacci sequence as positions.
925  Xapian::termpos prev_pos = 1;
926  Xapian::termpos pos = 1;
927  while (pos < 1000) {
928  doc.add_posting("foo", pos);
929  auto new_pos = prev_pos + pos;
930  prev_pos = pos;
931  pos = new_pos;
932  }
933 
934  // Check we added exactly one term.
935  TEST_EQUAL(doc.termlist_count(), 1);
936 
938  auto num_pos = t.positionlist_count();
939  TEST_EQUAL(t.get_wdf(), num_pos);
940 
941  // Out of order is a no-op.
942  TEST_EQUAL(doc.remove_postings("foo", 2, 1), 0);
943  t = doc.termlist_begin();
944  TEST_EQUAL(t.positionlist_count(), num_pos);
945  TEST_EQUAL(t.get_wdf(), num_pos);
946 
947  // 6 and 7 aren't in the sequence.
948  TEST_EQUAL(doc.remove_postings("foo", 6, 7), 0);
949  t = doc.termlist_begin();
950  TEST_EQUAL(t.positionlist_count(), num_pos);
951  TEST_EQUAL(t.get_wdf(), num_pos);
952 
953  // Beyond the end of the positions.
954  TEST_EQUAL(doc.remove_postings("foo", 1000, 2000), 0);
955  t = doc.termlist_begin();
956  TEST_EQUAL(t.positionlist_count(), num_pos);
957  TEST_EQUAL(t.get_wdf(), num_pos);
958 
959  // 1, 2, 3 are in the sequence, 4 isn't.
960  TEST_EQUAL(doc.remove_postings("foo", 1, 4), 3);
961  t = doc.termlist_begin();
962  TEST_EQUAL(t.positionlist_count(), num_pos - 3);
963  TEST_EQUAL(t.get_wdf(), num_pos - 3);
964 
965  // Remove the end position.
966  TEST_EQUAL(doc.remove_postings("foo", 876, 987), 1);
967  t = doc.termlist_begin();
968  TEST_EQUAL(t.positionlist_count(), num_pos - 4);
969  TEST_EQUAL(t.get_wdf(), num_pos - 4);
970 
971  // Remove a range in the middle.
972  TEST_EQUAL(doc.remove_postings("foo", 33, 233), 5);
973  t = doc.termlist_begin();
974  TEST_EQUAL(t.positionlist_count(), num_pos - 9);
975  TEST_EQUAL(t.get_wdf(), num_pos - 9);
976 
977  // Check the expected positions are left.
978  t = doc.termlist_begin();
979  static const Xapian::termpos expected[] = { 5, 8, 13, 21, 377, 610, 9999 };
980  const Xapian::termpos* expect = expected;
981  for (auto p = t.positionlist_begin(); p != t.positionlist_end(); ++p) {
982  TEST_EQUAL(*p, *expect);
983  ++expect;
984  }
985 }
986 
987 static void
989 {
990  // GCC 9 was giving a warning on the next line with -Wdeprecated-copy
991  // (which is enabled by -Wextra).
992  throw error;
993 }
994 
996 DEFINE_TESTCASE(errorcopyctor, !backend) {
997  Xapian::RangeError e("test");
998  try {
1000  } catch (Xapian::Error&) {
1001  return;
1002  }
1003  FAIL_TEST("Expected exception to be thrown");
1004 }
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:80
DestroyedFlag destroyed
Definition: api_none.cc:351
Xapian::Document get_document(Xapian::docid did) const
Get a document from the database, given its document id.
Definition: omdatabase.cc:490
std::string get_description() const
Return a string describing this object.
Definition: omdocument.cc:101
void operator()(const Xapian::Document &, double)
Register a document with the match spy.
Definition: api_none.cc:420
void add_value(Xapian::valueno slot, const std::string &value)
Add a new value.
Definition: omdocument.cc:107
TestFieldProcessor(bool &destroyed_)
Definition: api_none.cc:354
TermIterator termlist_begin(Xapian::docid did) const
An iterator pointing to the start of the termlist for a given document.
Definition: omdatabase.cc:198
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:275
DestroyedFlag destroyed
Definition: api_none.cc:268
This class is used to access a database, or a group of databases.
Definition: database.h:68
bool operator()(const string &) const
Do we want this term in the ESet?
Definition: api_none.cc:714
Xapian::termcount termlist_count() const
The length of the termlist - i.e.
Definition: omdocument.cc:191
MatchSpy * release()
Start reference counting this object.
Definition: matchspy.h:184
static const Xapian::Query MatchAll
A query matching all documents.
Definition: query.h:75
Match documents which an odd number of subqueries match.
Definition: query.h:107
InvalidOperationError indicates the API was used in an invalid way.
Definition: error.h:283
void add_valuerangeprocessor(Xapian::ValueRangeProcessor *vrproc)
Register a ValueRangeProcessor.
Definition: queryparser.h:1283
PositionIterator positionlist_begin(Xapian::docid did, const std::string &tname) const
An iterator pointing to the start of the position list for a given term in a given document...
Definition: omdatabase.cc:250
void set_document(const Xapian::Document &doc)
Set the current document.
Abstract base class for match spies.
Definition: matchspy.h:49
void set_stopper(const Stopper *stop=NULL)
Set the stopper.
Definition: queryparser.cc:96
Parses a piece of text and generate terms.
Definition: termgenerator.h:48
ValueIterator values_begin() const
Iterator for the values in this document.
Definition: omdocument.cc:210
TermIterator allterms_end(const std::string &=std::string()) const
Corresponding end iterator to allterms_begin(prefix).
Definition: database.h:269
FieldProcessor * release()
Start reference counting this object.
Definition: queryparser.h:759
string operator()(const Xapian::Document &) const
Build a key string for a Document.
Definition: api_none.cc:633
Xapian::docid get_lastdocid() const
Get the highest document id which has been used in the database.
Definition: omdatabase.cc:279
Build a Xapian::Query object from a user query string.
Definition: queryparser.h:778
a generic test suite engine
DestroyedFlag(bool &destroyed_)
Definition: api_none.cc:258
void remove_term(const std::string &tname)
Remove a term and all postings associated with it.
Definition: omdocument.cc:177
ExpandDecider subclass which rejects terms using two ExpandDeciders.
Definition: expanddecider.h:88
void skip_to(const std::string &term)
Advance the iterator to term term.
STL namespace.
Pick the maximum weight of any subquery.
Definition: query.h:249
Convert types to std::string.
Virtual base class for expand decider functor.
Definition: expanddecider.h:37
int revision()
Report the revision of the library which the program is linked with.
Definition: xapian.h:142
Xapian::Query operator()(const string &str)
Convert a field-prefixed string to a Query object.
Definition: api_none.cc:356
ValueRangeProcessor * release()
Start reference counting this object.
Definition: queryparser.h:442
Xapian::valueno operator()(std::string &, std::string &)
Check for a valid range of this type.
Definition: api_none.cc:802
TestKeyMaker(bool &destroyed_)
Definition: api_none.cc:631
void clear_terms()
Remove all terms (and postings) from the document.
Definition: omdocument.cc:184
TermIterator termlist_end() const
Equivalent end iterator for termlist_begin().
Definition: document.h:270
Base class for value range processors.
Definition: queryparser.h:404
std::string get_metadata(const std::string &key) const
Get the user-specified metadata associated with a given key.
Definition: omdatabase.cc:758
static const int INCLUDE_QUERY_TERMS
Terms in the query may be returned by get_eset().
Definition: enquire.h:593
void index_text(const Xapian::Utf8Iterator &itor, Xapian::termcount wdf_inc=1, const std::string &prefix=std::string())
Index some text.
void add_rangeprocessor(Xapian::RangeProcessor *range_proc, const std::string *grouping=NULL)
Register a RangeProcessor.
Definition: queryparser.cc:234
DestroyedFlag destroyed
Definition: api_none.cc:797
docid get_docid() const
Get the document id which is associated with this document (if any).
Definition: omdocument.cc:220
test functionality of the Xapian API
Stopper * release()
Start reference counting this object.
Definition: queryparser.h:81
ExpandDecider * release()
Start reference counting this object.
Definition: expanddecider.h:65
const char * version_string()
Report the version string of the library which the program is linked with.
Definition: xapian.h:115
static void errorcopyctor_helper(Xapian::Error &error)
Definition: api_none.cc:988
Class for iterating over a list of terms.
Definition: termiterator.h:41
ESet get_eset(Xapian::termcount maxitems, const RSet &omrset, int flags=0, const Xapian::ExpandDecider *edecider=0, double min_wt=0.0) const
Get the expand set for the given rset.
Definition: omenquire.cc:941
TestMatchSpy(bool &destroyed_)
Definition: api_none.cc:418
RangeError indicates an attempt to access outside the bounds of a container.
Definition: error.h:971
InvalidArgumentError indicates an invalid parameter value was passed to the API.
Definition: error.h:241
DestroyedFlag destroyed
Definition: api_none.cc:709
ValueIterator valuestream_end(Xapian::valueno) const
Return end iterator corresponding to valuestream_begin().
Definition: database.h:363
#define singlesubquery3_(OP)
void clear_values()
Remove all values associated with the document.
Definition: omdocument.cc:121
Base class for field processors.
Definition: queryparser.h:729
Pick the best N subqueries and combine with OP_OR.
Definition: query.h:215
This class provides read/write access to a database.
Definition: database.h:789
int major_version()
Report the major version of the library which the program is linked with.
Definition: xapian.h:124
Xapian::termpos remove_postings(const std::string &term, Xapian::termpos term_pos_first, Xapian::termpos term_pos_last, Xapian::termcount wdf_dec=1)
Remove a range of postings for a term.
Definition: omdocument.cc:161
Match only documents where all subqueries match near and in order.
Definition: query.h:152
Match the first subquery taking extra weight from other subqueries.
Definition: query.h:118
#define singlesubquery2_(OP)
#define singlesubquery1_(OP)
Public interfaces for the Xapian library.
Match like OP_AND but only taking weight from the first subquery.
Definition: query.h:128
#define TEST_EXCEPTION(TYPE, CODE)
Check that CODE throws exactly Xapian exception TYPE.
Definition: testutils.h:109
string str(int value)
Convert int to std::string.
Definition: str.cc:90
Xapian::termcount get_doclength(Xapian::docid did) const
Get the length of a document.
Definition: omdatabase.cc:461
Xapian::termcount values_count() const
Count the values in this document.
Definition: omdocument.cc:204
bool startswith(const std::string &s, char pfx)
Definition: stringutils.h:51
void set_sort_by_relevance_then_key(Xapian::KeyMaker *sorter, bool reverse)
Set the sorting to be by relevance, then by keys generated from values.
Definition: omenquire.cc:916
ValueIterator values_end() const
Equivalent end iterator for values_begin().
Definition: document.h:281
TermIterator allterms_begin(const std::string &prefix=std::string()) const
An iterator which runs across all terms with a given prefix.
Definition: omdatabase.cc:223
void set_stopper(const Xapian::Stopper *stop=NULL)
Set the Xapian::Stopper object to be used for identifying stopwords.
bool & destroyed
Definition: api_none.cc:255
ValueIterator valuestream_begin(Xapian::valueno slot) const
Return an iterator over the value in slot slot for each document.
Definition: omdatabase.cc:450
Base class for range processors.
Definition: queryparser.h:140
TestStopper(bool &destroyed_)
Definition: api_none.cc:482
Match like OP_OR but weighting as if a single term.
Definition: query.h:239
void set_sort_by_key_then_relevance(Xapian::KeyMaker *sorter, bool reverse)
Set the sorting to be by keys generated from values, then by relevance for documents with identical k...
Definition: omenquire.cc:906
void add_posting(const std::string &tname, Xapian::termpos tpos, Xapian::termcount wdfinc=1)
Add an occurrence of a term at a particular position.
Definition: omdocument.cc:128
TestRangeProcessor(bool &destroyed_)
Definition: api_none.cc:271
void add_document(Xapian::docid did)
Add a document to the relevance set.
Definition: omenquire.cc:104
#define FAIL_TEST(MSG)
Fail the current testcase with message MSG.
Definition: testsuite.h:68
Match only documents which all subqueries match.
Definition: query.h:84
Xapian::Database get_database(const string &dbname)
Definition: apitest.cc:48
Xapian::Query operator()(const std::string &, const std::string &)
Check for a valid range of this type.
Definition: api_none.cc:274
void add_matchspy(MatchSpy *spy)
Add a matchspy.
Definition: omenquire.cc:807
std::string get_description() const
Return a string describing this object.
Definition: query.cc:232
This class provides an interface to the information retrieval system for the purpose of searching...
Definition: enquire.h:152
DEFINE_TESTCASE(version1, !backend)
Definition: api_none.cc:38
Match only documents where all subqueries match near each other.
Definition: query.h:140
RangeProcessor * release()
Start reference counting this object.
Definition: queryparser.h:231
TestValueRangeProcessor(bool &destroyed_)
Definition: api_none.cc:800
bool empty() const
Check if this query is Xapian::Query::MatchNothing.
Definition: query.h:524
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:43
Match documents which the first subquery matches but no others do.
Definition: query.h:99
Match documents which at least one subquery matches.
Definition: query.h:92
unsigned valueno
The number for a value slot in a document.
Definition: types.h:108
Xapian-specific test helper functions and macros.
unsigned XAPIAN_TERMPOS_BASE_TYPE termpos
A term position within a document or query.
Definition: types.h:83
static const Xapian::Query MatchNothing
A query matching no documents.
Definition: query.h:65
DestroyedFlag destroyed
Definition: api_none.cc:628
DestroyedFlag destroyed
Definition: api_none.cc:415
Xapian::TermIterator metadata_keys_begin(const std::string &prefix=std::string()) const
An iterator which returns all user-specified metadata keys.
Definition: omdatabase.cc:768
KeyMaker * release()
Start reference counting this object.
Definition: keymaker.h:71
Abstract base class for stop-word decision functor.
Definition: queryparser.h:50
bool operator()(const std::string &) const
Is term a stop-word?
Definition: api_none.cc:484
void add_boolean_term(const std::string &term)
Add a boolean filter term to the document.
Definition: document.h:192
DestroyedFlag destroyed
Definition: api_none.cc:479
Class representing a query.
Definition: query.h:46
void add_prefix(const std::string &field, const std::string &prefix)
Add a free-text field term prefix.
Definition: queryparser.cc:183
TestExpandDecider(bool &destroyed_)
Definition: api_none.cc:712
#define TEST_EQUAL(a, b)
Test for equality of two things.
Definition: testsuite.h:278
Xapian::termcount get_unique_terms(Xapian::docid did) const
Get the number of unique terms in document.
Definition: omdatabase.cc:476
void set_data(const std::string &data)
Set data stored in the document.
Definition: omdocument.cc:78
int minor_version()
Report the minor version of the library which the program is linked with.
Definition: xapian.h:133
TermIterator termlist_begin() const
Start iterating the terms in this document.
Definition: omdocument.cc:197
A handle representing a document in a Xapian database.
Definition: document.h:61
void remove_posting(const std::string &tname, Xapian::termpos tpos, Xapian::termcount wdfdec=1)
Remove a posting of a term from the document.
Definition: omdocument.cc:150
Xapian::termcount positionlist_count() const
Return the length of the position list for the current position.
void set_sort_by_key(Xapian::KeyMaker *sorter, bool reverse)
Set the sorting to be by key generated from values only.
Definition: omenquire.cc:896
Virtual base class for key making functors.
Definition: keymaker.h:41
A relevance set (R-Set).
Definition: enquire.h:60
void add_term(const std::string &tname, Xapian::termcount wdfinc=1)
Add a term to the document, without positional information.
Definition: omdocument.cc:140
Xapian::TermIterator metadata_keys_end(const std::string &=std::string()) const
Corresponding end iterator to metadata_keys_begin().
Definition: database.h:510