xapian-core  1.4.27
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&) override {
276  }
277 };
278 
280 DEFINE_TESTCASE(subclassablerefcount1, !backend) {
281  bool gone_auto, gone;
282 
283  // Simple test of release().
284  {
286  TEST(!gone);
288  qp.add_rangeprocessor(rp->release());
289  TEST(!gone);
290  }
291  TEST(gone);
292 
293  // Check a second call to release() has no effect.
294  {
296  TEST(!gone);
298  qp.add_rangeprocessor(rp->release());
299  rp->release();
300  TEST(!gone);
301  }
302  TEST(gone);
303 
304  // Test reference counting works, and that a RangeProcessor with automatic
305  // storage works OK.
306  {
307  TestRangeProcessor rp_auto(gone_auto);
308  TEST(!gone_auto);
309  {
311  {
314  rp = new TestRangeProcessor(gone);
315  TEST(!gone);
316  qp1.add_rangeprocessor(rp->release());
317  TEST(!gone);
318  qp2.add_rangeprocessor(rp);
319  TEST(!gone);
320  qp2.add_rangeprocessor(&rp_auto);
321  TEST(!gone);
322  TEST(!gone_auto);
323  }
324  TEST(!gone);
325  }
326  TEST(gone);
327  TEST(!gone_auto);
328  }
329  TEST(gone_auto);
330 
331  // Regression test for initial implementation, where ~opt_intrusive_ptr()
332  // checked the reference of the object, which may have already been deleted
333  // if it wasn't been reference counted.
334  {
336  {
338  TEST(!gone);
339  qp.add_rangeprocessor(rp);
340  delete rp;
341  TEST(gone);
342  }
343  // At the end of this block, qp is destroyed, but mustn't dereference
344  // the pointer it has to rp. If it does, that should get caught
345  // when tests are run under valgrind.
346  }
347 }
348 
351 
352  public:
353  TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
354 
355  Xapian::Query operator()(const string& str) override {
356  return Xapian::Query(str);
357  }
358 };
359 
361 DEFINE_TESTCASE(subclassablerefcount2, !backend) {
362  bool gone_auto, gone;
363 
364  // Simple test of release().
365  {
366  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
367  TEST(!gone);
369  qp.add_prefix("foo", proc->release());
370  TEST(!gone);
371  }
372  TEST(gone);
373 
374  // Check a second call to release() has no effect.
375  {
376  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
377  TEST(!gone);
379  qp.add_prefix("foo", proc->release());
380  proc->release();
381  TEST(!gone);
382  }
383  TEST(gone);
384 
385  // Test reference counting works, and that a FieldProcessor with automatic
386  // storage works OK.
387  {
388  TestFieldProcessor proc_auto(gone_auto);
389  TEST(!gone_auto);
390  {
392  {
394  Xapian::FieldProcessor * proc;
395  proc = new TestFieldProcessor(gone);
396  TEST(!gone);
397  qp1.add_prefix("foo", proc->release());
398  TEST(!gone);
399  qp2.add_prefix("foo", proc);
400  TEST(!gone);
401  qp2.add_prefix("bar", &proc_auto);
402  TEST(!gone);
403  TEST(!gone_auto);
404  }
405  TEST(!gone);
406  }
407  TEST(gone);
408  TEST(!gone_auto);
409  }
410  TEST(gone_auto);
411 }
412 
415 
416  public:
417  TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
418 
419  void operator()(const Xapian::Document&, double) override { }
420 };
421 
423 DEFINE_TESTCASE(subclassablerefcount3, backend) {
424  Xapian::Database db = get_database("apitest_simpledata");
425 
426  bool gone_auto, gone;
427 
428  // Simple test of release().
429  {
430  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
431  TEST(!gone);
432  Xapian::Enquire enquire(db);
433  enquire.add_matchspy(spy->release());
434  TEST(!gone);
435  }
436  TEST(gone);
437 
438  // Check a second call to release() has no effect.
439  {
440  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
441  TEST(!gone);
442  Xapian::Enquire enquire(db);
443  enquire.add_matchspy(spy->release());
444  spy->release();
445  TEST(!gone);
446  }
447  TEST(gone);
448 
449  // Test reference counting works, and that a MatchSpy with automatic
450  // storage works OK.
451  {
452  TestMatchSpy spy_auto(gone_auto);
453  TEST(!gone_auto);
454  {
455  Xapian::Enquire enq1(db);
456  {
457  Xapian::Enquire enq2(db);
458  Xapian::MatchSpy * spy;
459  spy = new TestMatchSpy(gone);
460  TEST(!gone);
461  enq1.add_matchspy(spy->release());
462  TEST(!gone);
463  enq2.add_matchspy(spy);
464  TEST(!gone);
465  enq2.add_matchspy(&spy_auto);
466  TEST(!gone);
467  TEST(!gone_auto);
468  }
469  TEST(!gone);
470  }
471  TEST(gone);
472  TEST(!gone_auto);
473  }
474  TEST(gone_auto);
475 }
476 
477 class TestStopper : public Xapian::Stopper {
479 
480  public:
481  TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
482 
483  bool operator()(const std::string&) const override { return true; }
484 };
485 
487 DEFINE_TESTCASE(subclassablerefcount4, !backend) {
488  bool gone_auto, gone;
489 
490  // Simple test of release().
491  {
492  Xapian::Stopper * stopper = new TestStopper(gone);
493  TEST(!gone);
495  qp.set_stopper(stopper->release());
496  TEST(!gone);
497  }
498  TEST(gone);
499 
500  // Test that setting a new stopper causes the previous one to be released.
501  {
502  bool gone0;
503  Xapian::Stopper * stopper0 = new TestStopper(gone0);
504  TEST(!gone0);
506  qp.set_stopper(stopper0->release());
507  TEST(!gone0);
508 
509  Xapian::Stopper * stopper = new TestStopper(gone);
510  TEST(!gone);
511  qp.set_stopper(stopper->release());
512  TEST(gone0);
513  TEST(!gone);
514  }
515  TEST(gone);
516 
517  // Check a second call to release() has no effect.
518  {
519  Xapian::Stopper * stopper = new TestStopper(gone);
520  TEST(!gone);
522  qp.set_stopper(stopper->release());
523  stopper->release();
524  TEST(!gone);
525  }
526  TEST(gone);
527 
528  // Test reference counting works, and that a Stopper with automatic
529  // storage works OK.
530  {
531  TestStopper stopper_auto(gone_auto);
532  TEST(!gone_auto);
533  {
535  {
537  Xapian::Stopper * stopper;
538  stopper = new TestStopper(gone);
539  TEST(!gone);
540  qp1.set_stopper(stopper->release());
541  TEST(!gone);
542  qp2.set_stopper(stopper);
543  TEST(!gone);
544  qp2.set_stopper(&stopper_auto);
545  TEST(!gone);
546  TEST(!gone_auto);
547  }
548  TEST(!gone);
549  }
550  TEST(gone);
551  TEST(!gone_auto);
552  }
553  TEST(gone_auto);
554 }
555 
557 DEFINE_TESTCASE(subclassablerefcount5, !backend) {
558  bool gone_auto, gone;
559 
560  // Simple test of release().
561  {
562  Xapian::Stopper * stopper = new TestStopper(gone);
563  TEST(!gone);
564  Xapian::TermGenerator indexer;
565  indexer.set_stopper(stopper->release());
566  TEST(!gone);
567  }
568  TEST(gone);
569 
570  // Test that setting a new stopper causes the previous one to be released.
571  {
572  bool gone0;
573  Xapian::Stopper * stopper0 = new TestStopper(gone0);
574  TEST(!gone0);
575  Xapian::TermGenerator indexer;
576  indexer.set_stopper(stopper0->release());
577  TEST(!gone0);
578 
579  Xapian::Stopper * stopper = new TestStopper(gone);
580  TEST(!gone);
581  indexer.set_stopper(stopper->release());
582  TEST(gone0);
583  TEST(!gone);
584  }
585  TEST(gone);
586 
587  // Check a second call to release() has no effect.
588  {
589  Xapian::Stopper * stopper = new TestStopper(gone);
590  TEST(!gone);
591  Xapian::TermGenerator indexer;
592  indexer.set_stopper(stopper->release());
593  stopper->release();
594  TEST(!gone);
595  }
596  TEST(gone);
597 
598  // Test reference counting works, and that a Stopper with automatic
599  // storage works OK.
600  {
601  TestStopper stopper_auto(gone_auto);
602  TEST(!gone_auto);
603  {
604  Xapian::TermGenerator indexer1;
605  {
606  Xapian::TermGenerator indexer2;
607  Xapian::Stopper * stopper;
608  stopper = new TestStopper(gone);
609  TEST(!gone);
610  indexer1.set_stopper(stopper->release());
611  TEST(!gone);
612  indexer2.set_stopper(stopper);
613  TEST(!gone);
614  indexer2.set_stopper(&stopper_auto);
615  TEST(!gone);
616  TEST(!gone_auto);
617  }
618  TEST(!gone);
619  }
620  TEST(gone);
621  TEST(!gone_auto);
622  }
623  TEST(gone_auto);
624 }
625 
628 
629  public:
630  TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
631 
632  string operator()(const Xapian::Document&) const override {
633  return string();
634  }
635 };
636 
638 DEFINE_TESTCASE(subclassablerefcount6, backend) {
639  Xapian::Database db = get_database("apitest_simpledata");
640 
641  bool gone_auto, gone;
642 
643  // Simple test of release().
644  {
645  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
646  TEST(!gone);
647  Xapian::Enquire enq(db);
648  enq.set_sort_by_key(keymaker->release(), false);
649  TEST(!gone);
650  }
651  TEST(gone);
652 
653  // Test that setting a new keymaker causes the previous one to be released.
654  {
655  bool gone0;
656  Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
657  TEST(!gone0);
658  Xapian::Enquire enq(db);
659  enq.set_sort_by_key(keymaker0->release(), false);
660  TEST(!gone0);
661 
662  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
663  TEST(!gone);
664  enq.set_sort_by_key_then_relevance(keymaker->release(), false);
665  TEST(gone0);
666  TEST(!gone);
667  }
668  TEST(gone);
669 
670  // Check a second call to release() has no effect.
671  {
672  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
673  TEST(!gone);
674  Xapian::Enquire enq(db);
675  enq.set_sort_by_key(keymaker->release(), false);
676  keymaker->release();
677  TEST(!gone);
678  }
679  TEST(gone);
680 
681  // Test reference counting works, and that a KeyMaker with automatic
682  // storage works OK.
683  {
684  TestKeyMaker keymaker_auto(gone_auto);
685  TEST(!gone_auto);
686  {
687  Xapian::Enquire enq1(db);
688  {
689  Xapian::Enquire enq2(db);
690  Xapian::KeyMaker * keymaker;
691  keymaker = new TestKeyMaker(gone);
692  TEST(!gone);
693  enq1.set_sort_by_key(keymaker->release(), false);
694  TEST(!gone);
695  enq2.set_sort_by_relevance_then_key(keymaker, false);
696  TEST(!gone);
697  enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
698  TEST(!gone);
699  TEST(!gone_auto);
700  }
701  TEST(!gone);
702  }
703  TEST(gone);
704  TEST(!gone_auto);
705  }
706  TEST(gone_auto);
707 }
708 
711 
712  public:
713  TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
714 
715  bool operator()(const string&) const override { return true; }
716 };
717 
719 DEFINE_TESTCASE(subclassablerefcount7, backend) {
720  Xapian::Database db = get_database("apitest_simpledata");
721  Xapian::Enquire enq(db);
722  Xapian::RSet rset;
723  rset.add_document(1);
724 
725  bool gone_auto, gone;
726 
727  for (int flags = 0;
730  // Test of auto lifetime ExpandDecider.
731  {
732  TestExpandDecider edecider_auto(gone_auto);
733  TEST(!gone_auto);
734  (void)enq.get_eset(5, rset, 0, &edecider_auto);
735  TEST(!gone_auto);
736  }
737  TEST(gone_auto);
738 
739  // Simple test of release().
740  {
741  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
742  TEST(!gone);
743  (void)enq.get_eset(5, rset, 0, edecider);
744  TEST(!gone);
745  delete edecider;
746  TEST(gone);
747  }
748 
749  // Test that a released ExpandDecider gets cleaned up by get_eset().
750  {
751  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
752  TEST(!gone);
753  (void)enq.get_eset(5, rset, 0, edecider->release());
754  TEST(gone);
755  }
756 
757  // Check a second call to release() has no effect.
758  {
759  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
760  TEST(!gone);
761  edecider->release();
762  TEST(!gone);
763  (void)enq.get_eset(5, rset, 0, edecider->release());
764  TEST(gone);
765  }
766  }
767 
768  // Test combinations of released/non-released with ExpandDeciderAnd.
769  {
770  TestExpandDecider edecider_auto(gone_auto);
771  TEST(!gone_auto);
772  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
773  TEST(!gone);
774  (void)enq.get_eset(5, rset, 0,
776  &edecider_auto,
777  edecider->release()))->release());
778  TEST(!gone_auto);
779  TEST(gone);
780  }
781  TEST(gone_auto);
782  {
783  TestExpandDecider edecider_auto(gone_auto);
784  TEST(!gone_auto);
785  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
786  TEST(!gone);
787  (void)enq.get_eset(5, rset, 0,
789  edecider->release(),
790  &edecider_auto))->release());
791  TEST(!gone_auto);
792  TEST(gone);
793  }
794  TEST(gone_auto);
795 }
796 
799 
800  public:
801  TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) { }
802 
803  Xapian::valueno operator()(std::string &, std::string &) {
804  return 42;
805  }
806 };
807 
809 DEFINE_TESTCASE(subclassablerefcount8, !backend) {
810  bool gone_auto, gone;
811 
812  // Simple test of release().
813  {
815  TEST(!gone);
817  qp.add_valuerangeprocessor(vrp->release());
818  TEST(!gone);
819  }
820  TEST(gone);
821 
822  // Check a second call to release() has no effect.
823  {
825  TEST(!gone);
827  qp.add_valuerangeprocessor(vrp->release());
828  vrp->release();
829  TEST(!gone);
830  }
831  TEST(gone);
832 
833  // Test reference counting works, and that a VRP with automatic storage
834  // works OK.
835  {
836  TestValueRangeProcessor vrp_auto(gone_auto);
837  TEST(!gone_auto);
838  {
840  {
843  vrp = new TestValueRangeProcessor(gone);
844  TEST(!gone);
845  qp1.add_valuerangeprocessor(vrp->release());
846  TEST(!gone);
847  qp2.add_valuerangeprocessor(vrp);
848  TEST(!gone);
849  qp2.add_valuerangeprocessor(&vrp_auto);
850  TEST(!gone);
851  TEST(!gone_auto);
852  }
853  TEST(!gone);
854  }
855  TEST(gone);
856  TEST(!gone_auto);
857  }
858  TEST(gone_auto);
859 
860  // Regression test for initial implementation, where ~opt_intrusive_ptr()
861  // checked the reference of the object, which may have already been deleted
862  // if it wasn't been reference counted.
863  {
865  {
867  new TestValueRangeProcessor(gone);
868  TEST(!gone);
869  qp.add_valuerangeprocessor(vrp);
870  delete vrp;
871  TEST(gone);
872  }
873  // At the end of this block, qp is destroyed, but mustn't dereference
874  // the pointer it has to vrp. If it does, that should get caught
875  // when tests are run under valgrind.
876  }
877 }
878 
880 DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
881  Xapian::Document doc;
882  doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
884  "Document(data='\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff')");
885  doc.set_data(string("\x00\x1f", 2));
887  "Document(data='\\x00\\x1f')");
888  // Check that backslashes are encoded so output isn't ambiguous.
889  doc.set_data("back\\slash");
891  "Document(data='back\\x5cslash')");
892 }
893 
900 DEFINE_TESTCASE(deletewhileiterating1, !backend) {
901  for (bool preinc : { false, true }) {
902  Xapian::Document doc;
903  Xapian::TermGenerator indexer;
904  indexer.set_document(doc);
905  indexer.index_text("Pull the rug out from under ourselves", 1, "S");
906  Xapian::TermIterator term_iterator = doc.termlist_begin();
907  term_iterator.skip_to("S");
908  while (term_iterator != doc.termlist_end()) {
909  const string& term = *term_iterator;
910  if (!startswith(term, "S")) {
911  break;
912  }
913  if (preinc) ++term_iterator;
914  doc.remove_term(term);
915  if (!preinc) ++term_iterator;
916  }
917  TEST_EQUAL(doc.termlist_count(), 0);
918  TEST(doc.termlist_begin() == doc.termlist_end());
919  }
920 }
921 
923 DEFINE_TESTCASE(removepostings, !backend) {
924  Xapian::Document doc;
925  // Add Fibonacci sequence as positions.
926  Xapian::termpos prev_pos = 1;
927  Xapian::termpos pos = 1;
928  while (pos < 1000) {
929  doc.add_posting("foo", pos);
930  auto new_pos = prev_pos + pos;
931  prev_pos = pos;
932  pos = new_pos;
933  }
934 
935  // Check we added exactly one term.
936  TEST_EQUAL(doc.termlist_count(), 1);
937 
939  auto num_pos = t.positionlist_count();
940  TEST_EQUAL(t.get_wdf(), num_pos);
941 
942  // Out of order is a no-op.
943  TEST_EQUAL(doc.remove_postings("foo", 2, 1), 0);
944  t = doc.termlist_begin();
945  TEST_EQUAL(t.positionlist_count(), num_pos);
946  TEST_EQUAL(t.get_wdf(), num_pos);
947 
948  // 6 and 7 aren't in the sequence.
949  TEST_EQUAL(doc.remove_postings("foo", 6, 7), 0);
950  t = doc.termlist_begin();
951  TEST_EQUAL(t.positionlist_count(), num_pos);
952  TEST_EQUAL(t.get_wdf(), num_pos);
953 
954  // Beyond the end of the positions.
955  TEST_EQUAL(doc.remove_postings("foo", 1000, 2000), 0);
956  t = doc.termlist_begin();
957  TEST_EQUAL(t.positionlist_count(), num_pos);
958  TEST_EQUAL(t.get_wdf(), num_pos);
959 
960  // 1, 2, 3 are in the sequence, 4 isn't.
961  TEST_EQUAL(doc.remove_postings("foo", 1, 4), 3);
962  t = doc.termlist_begin();
963  TEST_EQUAL(t.positionlist_count(), num_pos - 3);
964  TEST_EQUAL(t.get_wdf(), num_pos - 3);
965 
966  // Remove the end position.
967  TEST_EQUAL(doc.remove_postings("foo", 876, 987), 1);
968  t = doc.termlist_begin();
969  TEST_EQUAL(t.positionlist_count(), num_pos - 4);
970  TEST_EQUAL(t.get_wdf(), num_pos - 4);
971 
972  // Remove a range in the middle.
973  TEST_EQUAL(doc.remove_postings("foo", 33, 233), 5);
974  t = doc.termlist_begin();
975  TEST_EQUAL(t.positionlist_count(), num_pos - 9);
976  TEST_EQUAL(t.get_wdf(), num_pos - 9);
977 
978  // Check the expected positions are left.
979  t = doc.termlist_begin();
980  static const Xapian::termpos expected[] = { 5, 8, 13, 21, 377, 610, 9999 };
981  const Xapian::termpos* expect = expected;
982  for (auto p = t.positionlist_begin(); p != t.positionlist_end(); ++p) {
983  TEST_EQUAL(*p, *expect);
984  ++expect;
985  }
986 }
987 
988 static void
990 {
991  // GCC 9 was giving a warning on the next line with -Wdeprecated-copy
992  // (which is enabled by -Wextra).
993  throw error;
994 }
995 
997 DEFINE_TESTCASE(errorcopyctor, !backend) {
998  Xapian::RangeError e("test");
999  try {
1001  } catch (Xapian::Error&) {
1002  return;
1003  }
1004  FAIL_TEST("Expected exception to be thrown");
1005 }
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:80
DestroyedFlag destroyed
Definition: api_none.cc:350
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 add_value(Xapian::valueno slot, const std::string &value)
Add a new value.
Definition: omdocument.cc:107
Xapian::Query operator()(const std::string &, const std::string &) override
Check for a valid range of this type.
Definition: api_none.cc:274
TestFieldProcessor(bool &destroyed_)
Definition: api_none.cc:353
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
Xapian::Query operator()(const string &str) override
Convert a field-prefixed string to a Query object.
Definition: api_none.cc:355
This class is used to access a database, or a group of databases.
Definition: database.h:68
bool operator()(const std::string &) const override
Is term a stop-word?
Definition: api_none.cc:483
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:1300
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:97
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
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
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:803
TestKeyMaker(bool &destroyed_)
Definition: api_none.cc:630
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:595
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:253
DestroyedFlag destroyed
Definition: api_none.cc:798
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:989
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:947
TestMatchSpy(bool &destroyed_)
Definition: api_none.cc:417
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:710
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
bool operator()(const string &) const override
Do we want this term in the ESet?
Definition: api_none.cc:715
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
string operator()(const Xapian::Document &) const override
Build a key string for a Document.
Definition: api_none.cc:632
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:922
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
void operator()(const Xapian::Document &, double) override
Register a document with the match spy.
Definition: api_none.cc:419
TestStopper(bool &destroyed_)
Definition: api_none.cc:481
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:912
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
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:801
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:627
DestroyedFlag destroyed
Definition: api_none.cc:414
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
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:478
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:184
TestExpandDecider(bool &destroyed_)
Definition: api_none.cc:713
#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:902
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