xapian-core  1.4.18
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 }
63 
65 DEFINE_TESTCASE(document1, !backend) {
66  Xapian::Document doc;
67  doc.add_boolean_term("Hxapian.org");
68  TEST_EQUAL(doc.termlist_count(), 1);
70  TEST(t != doc.termlist_end());
71  TEST_EQUAL(*t, "Hxapian.org");
72  TEST_EQUAL(t.get_wdf(), 0);
73  TEST(++t == doc.termlist_end());
74  doc.remove_term("Hxapian.org");
75  TEST_EQUAL(doc.termlist_count(), 0);
76  TEST(doc.termlist_begin() == doc.termlist_end());
77 }
78 
80 DEFINE_TESTCASE(document2, !backend) {
81  Xapian::Document doc;
82  // The return value is uninitialised, so running under valgrind this
83  // will fail reliably prior to the fix.
84  TEST_EQUAL(doc.get_docid(), 0);
85 }
86 
88 DEFINE_TESTCASE(documentclearterms1, !backend) {
89  {
90  Xapian::Document doc;
91  doc.add_boolean_term("Hlocalhost");
92  doc.add_term("hello");
93  doc.add_term("there", 2);
94  doc.add_posting("positional", 1);
95  doc.add_posting("information", 2, 3);
96  TEST_EQUAL(doc.termlist_count(), 5);
97  TEST(doc.termlist_begin() != doc.termlist_end());
98  doc.clear_terms();
99  TEST_EQUAL(doc.termlist_count(), 0);
100  TEST(doc.termlist_begin() == doc.termlist_end());
101  // Test clear_terms() when there are no terms.
102  doc.clear_terms();
103  TEST_EQUAL(doc.termlist_count(), 0);
104  TEST(doc.termlist_begin() == doc.termlist_end());
105  }
106 
107  {
108  // Test clear_terms() when there have never been any terms.
109  Xapian::Document doc;
110  doc.clear_terms();
111  TEST_EQUAL(doc.termlist_count(), 0);
112  TEST(doc.termlist_begin() == doc.termlist_end());
113  }
114 }
115 
117 DEFINE_TESTCASE(documentclearvalues1, !backend) {
118  {
119  Xapian::Document doc;
120  doc.add_value(37, "hello");
121  doc.add_value(42, "world");
122  TEST_EQUAL(doc.values_count(), 2);
123  TEST(doc.values_begin() != doc.values_end());
124  doc.clear_values();
125  TEST_EQUAL(doc.values_count(), 0);
126  TEST(doc.values_begin() == doc.values_end());
127  // Test clear_values() when there are no values.
128  doc.clear_values();
129  TEST_EQUAL(doc.values_count(), 0);
130  TEST(doc.values_begin() == doc.values_end());
131  }
132 
133  {
134  // Test clear_values() when there have never been any values.
135  Xapian::Document doc;
136  doc.clear_values();
137  TEST_EQUAL(doc.values_count(), 0);
138  TEST(doc.termlist_begin() == doc.termlist_end());
139  }
140 }
141 
143 DEFINE_TESTCASE(documentemptyterm1, !backend) {
144  Xapian::Document doc;
146  doc.add_boolean_term(string()));
148  doc.add_term(string()));
150  doc.add_posting(string(), 1));
152  doc.add_posting(string(), 2, 3));
154  doc.remove_term(string()));
156  doc.remove_posting(string(), 1));
158  doc.remove_posting(string(), 2, 3));
160  doc.remove_postings(string(), 2, 3));
162  doc.remove_postings(string(), 2, 3, 4));
163 }
164 
165 DEFINE_TESTCASE(emptyquery4, !backend) {
166  // Test we get an empty query from applying any of the following ops to
167  // an empty list of subqueries.
168  Xapian::Query q;
169  TEST(Xapian::Query(q.OP_AND, &q, &q).empty());
170  TEST(Xapian::Query(q.OP_OR, &q, &q).empty());
171  TEST(Xapian::Query(q.OP_AND_NOT, &q, &q).empty());
172  TEST(Xapian::Query(q.OP_XOR, &q, &q).empty());
173  TEST(Xapian::Query(q.OP_AND_MAYBE, &q, &q).empty());
174  TEST(Xapian::Query(q.OP_FILTER, &q, &q).empty());
175  TEST(Xapian::Query(q.OP_NEAR, &q, &q).empty());
176  TEST(Xapian::Query(q.OP_PHRASE, &q, &q).empty());
177  TEST(Xapian::Query(q.OP_ELITE_SET, &q, &q).empty());
178  TEST(Xapian::Query(q.OP_SYNONYM, &q, &q).empty());
179  TEST(Xapian::Query(q.OP_MAX, &q, &q).empty());
180 }
181 
182 DEFINE_TESTCASE(singlesubquery1, !backend) {
183  // Test that we get just the subquery if we apply any of the following
184  // ops to just that subquery.
185 #define singlesubquery1_(OP) \
186  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
187  "Query(test)")
188  Xapian::Query q[1] = { Xapian::Query("test") };
189  singlesubquery1_(OP_AND);
190  singlesubquery1_(OP_OR);
191  singlesubquery1_(OP_AND_NOT);
192  singlesubquery1_(OP_XOR);
193  singlesubquery1_(OP_AND_MAYBE);
194  singlesubquery1_(OP_FILTER);
195  singlesubquery1_(OP_NEAR);
196  singlesubquery1_(OP_PHRASE);
197  singlesubquery1_(OP_ELITE_SET);
198  singlesubquery1_(OP_SYNONYM);
199  singlesubquery1_(OP_MAX);
200 }
201 
202 DEFINE_TESTCASE(singlesubquery2, !backend) {
203  // Like the previous test, but using MatchNothing as the subquery.
204 #define singlesubquery2_(OP) \
205  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
206  "Query()")
208  singlesubquery2_(OP_AND);
209  singlesubquery2_(OP_OR);
210  singlesubquery2_(OP_AND_NOT);
211  singlesubquery2_(OP_XOR);
212  singlesubquery2_(OP_AND_MAYBE);
213  singlesubquery2_(OP_FILTER);
214  singlesubquery2_(OP_NEAR);
215  singlesubquery2_(OP_PHRASE);
216  singlesubquery2_(OP_ELITE_SET);
217  singlesubquery2_(OP_SYNONYM);
218  singlesubquery2_(OP_MAX);
219 }
220 
221 DEFINE_TESTCASE(singlesubquery3, !backend) {
222  // Like the previous test, but using MatchAll as the subquery.
223 #define singlesubquery3_(OP) \
224  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
225  "Query(<alldocuments>)")
227  singlesubquery3_(OP_AND);
228  singlesubquery3_(OP_OR);
229  singlesubquery3_(OP_AND_NOT);
230  singlesubquery3_(OP_XOR);
231  singlesubquery3_(OP_AND_MAYBE);
232  singlesubquery3_(OP_FILTER);
233  // OP_NEAR and OP_PHRASE over MatchAll doesn't really make sense.
234  singlesubquery3_(OP_ELITE_SET);
235  singlesubquery3_(OP_SYNONYM);
236  singlesubquery3_(OP_MAX);
237 }
238 
240 DEFINE_TESTCASE(combinewqfnomore1, !backend) {
242  Xapian::Query("beer", 1, 1),
243  Xapian::Query("beer", 1, 1));
244  // Prior to 1.3.0, we would have given beer@2, but we decided that wasn't
245  // really useful or helpful.
246  TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
247 }
248 
250  bool & destroyed;
251 
252  public:
253  DestroyedFlag(bool & destroyed_) : destroyed(destroyed_) {
254  destroyed = false;
255  }
256 
258  destroyed = true;
259  }
260 };
261 
264 
265  public:
266  TestRangeProcessor(bool & destroyed_)
267  : Xapian::RangeProcessor(0), destroyed(destroyed_) { }
268 
269  Xapian::Query operator()(const std::string&, const std::string&)
270  {
272  }
273 };
274 
276 DEFINE_TESTCASE(subclassablerefcount1, !backend) {
277  bool gone_auto, gone;
278 
279  // Simple test of release().
280  {
282  TEST(!gone);
284  qp.add_rangeprocessor(rp->release());
285  TEST(!gone);
286  }
287  TEST(gone);
288 
289  // Check a second call to release() has no effect.
290  {
292  TEST(!gone);
294  qp.add_rangeprocessor(rp->release());
295  rp->release();
296  TEST(!gone);
297  }
298  TEST(gone);
299 
300  // Test reference counting works, and that a RangeProcessor with automatic
301  // storage works OK.
302  {
303  TestRangeProcessor rp_auto(gone_auto);
304  TEST(!gone_auto);
305  {
307  {
310  rp = new TestRangeProcessor(gone);
311  TEST(!gone);
312  qp1.add_rangeprocessor(rp->release());
313  TEST(!gone);
314  qp2.add_rangeprocessor(rp);
315  TEST(!gone);
316  qp2.add_rangeprocessor(&rp_auto);
317  TEST(!gone);
318  TEST(!gone_auto);
319  }
320  TEST(!gone);
321  }
322  TEST(gone);
323  TEST(!gone_auto);
324  }
325  TEST(gone_auto);
326 
327  // Regression test for initial implementation, where ~opt_intrusive_ptr()
328  // checked the reference of the object, which may have already been deleted
329  // if it wasn't been reference counted.
330  {
332  {
334  TEST(!gone);
335  qp.add_rangeprocessor(rp);
336  delete rp;
337  TEST(gone);
338  }
339  // At the end of this block, qp is destroyed, but mustn't dereference
340  // the pointer it has to rp. If it does, that should get caught
341  // when tests are run under valgrind.
342  }
343 }
344 
347 
348  public:
349  TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
350 
351  Xapian::Query operator()(const string &str) {
352  return Xapian::Query(str);
353  }
354 };
355 
357 DEFINE_TESTCASE(subclassablerefcount2, !backend) {
358  bool gone_auto, gone;
359 
360  // Simple test of release().
361  {
362  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
363  TEST(!gone);
365  qp.add_prefix("foo", proc->release());
366  TEST(!gone);
367  }
368  TEST(gone);
369 
370  // Check a second call to release() has no effect.
371  {
372  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
373  TEST(!gone);
375  qp.add_prefix("foo", proc->release());
376  proc->release();
377  TEST(!gone);
378  }
379  TEST(gone);
380 
381  // Test reference counting works, and that a FieldProcessor with automatic
382  // storage works OK.
383  {
384  TestFieldProcessor proc_auto(gone_auto);
385  TEST(!gone_auto);
386  {
388  {
390  Xapian::FieldProcessor * proc;
391  proc = new TestFieldProcessor(gone);
392  TEST(!gone);
393  qp1.add_prefix("foo", proc->release());
394  TEST(!gone);
395  qp2.add_prefix("foo", proc);
396  TEST(!gone);
397  qp2.add_prefix("bar", &proc_auto);
398  TEST(!gone);
399  TEST(!gone_auto);
400  }
401  TEST(!gone);
402  }
403  TEST(gone);
404  TEST(!gone_auto);
405  }
406  TEST(gone_auto);
407 }
408 
411 
412  public:
413  TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
414 
415  void operator()(const Xapian::Document &, double) { }
416 };
417 
419 DEFINE_TESTCASE(subclassablerefcount3, backend) {
420  Xapian::Database db = get_database("apitest_simpledata");
421 
422  bool gone_auto, gone;
423 
424  // Simple test of release().
425  {
426  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
427  TEST(!gone);
428  Xapian::Enquire enquire(db);
429  enquire.add_matchspy(spy->release());
430  TEST(!gone);
431  }
432  TEST(gone);
433 
434  // Check a second call to release() has no effect.
435  {
436  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
437  TEST(!gone);
438  Xapian::Enquire enquire(db);
439  enquire.add_matchspy(spy->release());
440  spy->release();
441  TEST(!gone);
442  }
443  TEST(gone);
444 
445  // Test reference counting works, and that a MatchSpy with automatic
446  // storage works OK.
447  {
448  TestMatchSpy spy_auto(gone_auto);
449  TEST(!gone_auto);
450  {
451  Xapian::Enquire enq1(db);
452  {
453  Xapian::Enquire enq2(db);
454  Xapian::MatchSpy * spy;
455  spy = new TestMatchSpy(gone);
456  TEST(!gone);
457  enq1.add_matchspy(spy->release());
458  TEST(!gone);
459  enq2.add_matchspy(spy);
460  TEST(!gone);
461  enq2.add_matchspy(&spy_auto);
462  TEST(!gone);
463  TEST(!gone_auto);
464  }
465  TEST(!gone);
466  }
467  TEST(gone);
468  TEST(!gone_auto);
469  }
470  TEST(gone_auto);
471 }
472 
473 class TestStopper : public Xapian::Stopper {
475 
476  public:
477  TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
478 
479  bool operator()(const std::string&) const { return true; }
480 };
481 
483 DEFINE_TESTCASE(subclassablerefcount4, !backend) {
484  bool gone_auto, gone;
485 
486  // Simple test of release().
487  {
488  Xapian::Stopper * stopper = new TestStopper(gone);
489  TEST(!gone);
491  qp.set_stopper(stopper->release());
492  TEST(!gone);
493  }
494  TEST(gone);
495 
496  // Test that setting a new stopper causes the previous one to be released.
497  {
498  bool gone0;
499  Xapian::Stopper * stopper0 = new TestStopper(gone0);
500  TEST(!gone0);
502  qp.set_stopper(stopper0->release());
503  TEST(!gone0);
504 
505  Xapian::Stopper * stopper = new TestStopper(gone);
506  TEST(!gone);
507  qp.set_stopper(stopper->release());
508  TEST(gone0);
509  TEST(!gone);
510  }
511  TEST(gone);
512 
513  // Check a second call to release() has no effect.
514  {
515  Xapian::Stopper * stopper = new TestStopper(gone);
516  TEST(!gone);
518  qp.set_stopper(stopper->release());
519  stopper->release();
520  TEST(!gone);
521  }
522  TEST(gone);
523 
524  // Test reference counting works, and that a Stopper with automatic
525  // storage works OK.
526  {
527  TestStopper stopper_auto(gone_auto);
528  TEST(!gone_auto);
529  {
531  {
533  Xapian::Stopper * stopper;
534  stopper = new TestStopper(gone);
535  TEST(!gone);
536  qp1.set_stopper(stopper->release());
537  TEST(!gone);
538  qp2.set_stopper(stopper);
539  TEST(!gone);
540  qp2.set_stopper(&stopper_auto);
541  TEST(!gone);
542  TEST(!gone_auto);
543  }
544  TEST(!gone);
545  }
546  TEST(gone);
547  TEST(!gone_auto);
548  }
549  TEST(gone_auto);
550 }
551 
553 DEFINE_TESTCASE(subclassablerefcount5, !backend) {
554  bool gone_auto, gone;
555 
556  // Simple test of release().
557  {
558  Xapian::Stopper * stopper = new TestStopper(gone);
559  TEST(!gone);
560  Xapian::TermGenerator indexer;
561  indexer.set_stopper(stopper->release());
562  TEST(!gone);
563  }
564  TEST(gone);
565 
566  // Test that setting a new stopper causes the previous one to be released.
567  {
568  bool gone0;
569  Xapian::Stopper * stopper0 = new TestStopper(gone0);
570  TEST(!gone0);
571  Xapian::TermGenerator indexer;
572  indexer.set_stopper(stopper0->release());
573  TEST(!gone0);
574 
575  Xapian::Stopper * stopper = new TestStopper(gone);
576  TEST(!gone);
577  indexer.set_stopper(stopper->release());
578  TEST(gone0);
579  TEST(!gone);
580  }
581  TEST(gone);
582 
583  // Check a second call to release() has no effect.
584  {
585  Xapian::Stopper * stopper = new TestStopper(gone);
586  TEST(!gone);
587  Xapian::TermGenerator indexer;
588  indexer.set_stopper(stopper->release());
589  stopper->release();
590  TEST(!gone);
591  }
592  TEST(gone);
593 
594  // Test reference counting works, and that a Stopper with automatic
595  // storage works OK.
596  {
597  TestStopper stopper_auto(gone_auto);
598  TEST(!gone_auto);
599  {
600  Xapian::TermGenerator indexer1;
601  {
602  Xapian::TermGenerator indexer2;
603  Xapian::Stopper * stopper;
604  stopper = new TestStopper(gone);
605  TEST(!gone);
606  indexer1.set_stopper(stopper->release());
607  TEST(!gone);
608  indexer2.set_stopper(stopper);
609  TEST(!gone);
610  indexer2.set_stopper(&stopper_auto);
611  TEST(!gone);
612  TEST(!gone_auto);
613  }
614  TEST(!gone);
615  }
616  TEST(gone);
617  TEST(!gone_auto);
618  }
619  TEST(gone_auto);
620 }
621 
624 
625  public:
626  TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
627 
628  string operator()(const Xapian::Document&) const { return string(); }
629 };
630 
632 DEFINE_TESTCASE(subclassablerefcount6, backend) {
633  Xapian::Database db = get_database("apitest_simpledata");
634 
635  bool gone_auto, gone;
636 
637  // Simple test of release().
638  {
639  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
640  TEST(!gone);
641  Xapian::Enquire enq(db);
642  enq.set_sort_by_key(keymaker->release(), false);
643  TEST(!gone);
644  }
645  TEST(gone);
646 
647  // Test that setting a new keymaker causes the previous one to be released.
648  {
649  bool gone0;
650  Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
651  TEST(!gone0);
652  Xapian::Enquire enq(db);
653  enq.set_sort_by_key(keymaker0->release(), false);
654  TEST(!gone0);
655 
656  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
657  TEST(!gone);
658  enq.set_sort_by_key_then_relevance(keymaker->release(), false);
659  TEST(gone0);
660  TEST(!gone);
661  }
662  TEST(gone);
663 
664  // Check a second call to release() has no effect.
665  {
666  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
667  TEST(!gone);
668  Xapian::Enquire enq(db);
669  enq.set_sort_by_key(keymaker->release(), false);
670  keymaker->release();
671  TEST(!gone);
672  }
673  TEST(gone);
674 
675  // Test reference counting works, and that a KeyMaker with automatic
676  // storage works OK.
677  {
678  TestKeyMaker keymaker_auto(gone_auto);
679  TEST(!gone_auto);
680  {
681  Xapian::Enquire enq1(db);
682  {
683  Xapian::Enquire enq2(db);
684  Xapian::KeyMaker * keymaker;
685  keymaker = new TestKeyMaker(gone);
686  TEST(!gone);
687  enq1.set_sort_by_key(keymaker->release(), false);
688  TEST(!gone);
689  enq2.set_sort_by_relevance_then_key(keymaker, false);
690  TEST(!gone);
691  enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
692  TEST(!gone);
693  TEST(!gone_auto);
694  }
695  TEST(!gone);
696  }
697  TEST(gone);
698  TEST(!gone_auto);
699  }
700  TEST(gone_auto);
701 }
702 
705 
706  public:
707  TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
708 
709  bool operator()(const string&) const { return true; }
710 };
711 
713 DEFINE_TESTCASE(subclassablerefcount7, backend) {
714  Xapian::Database db = get_database("apitest_simpledata");
715  Xapian::Enquire enq(db);
716  Xapian::RSet rset;
717  rset.add_document(1);
718 
719  bool gone_auto, gone;
720 
721  for (int flags = 0;
724  // Test of auto lifetime ExpandDecider.
725  {
726  TestExpandDecider edecider_auto(gone_auto);
727  TEST(!gone_auto);
728  (void)enq.get_eset(5, rset, 0, &edecider_auto);
729  TEST(!gone_auto);
730  }
731  TEST(gone_auto);
732 
733  // Simple test of release().
734  {
735  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
736  TEST(!gone);
737  (void)enq.get_eset(5, rset, 0, edecider);
738  TEST(!gone);
739  delete edecider;
740  TEST(gone);
741  }
742 
743  // Test that a released ExpandDecider gets cleaned up by get_eset().
744  {
745  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
746  TEST(!gone);
747  (void)enq.get_eset(5, rset, 0, edecider->release());
748  TEST(gone);
749  }
750 
751  // Check a second call to release() has no effect.
752  {
753  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
754  TEST(!gone);
755  edecider->release();
756  TEST(!gone);
757  (void)enq.get_eset(5, rset, 0, edecider->release());
758  TEST(gone);
759  }
760  }
761 
762  // Test combinations of released/non-released with ExpandDeciderAnd.
763  {
764  TestExpandDecider edecider_auto(gone_auto);
765  TEST(!gone_auto);
766  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
767  TEST(!gone);
768  (void)enq.get_eset(5, rset, 0,
770  &edecider_auto,
771  edecider->release()))->release());
772  TEST(!gone_auto);
773  TEST(gone);
774  }
775  TEST(gone_auto);
776  {
777  TestExpandDecider edecider_auto(gone_auto);
778  TEST(!gone_auto);
779  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
780  TEST(!gone);
781  (void)enq.get_eset(5, rset, 0,
783  edecider->release(),
784  &edecider_auto))->release());
785  TEST(!gone_auto);
786  TEST(gone);
787  }
788  TEST(gone_auto);
789 }
790 
793 
794  public:
795  TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) { }
796 
797  Xapian::valueno operator()(std::string &, std::string &) {
798  return 42;
799  }
800 };
801 
803 DEFINE_TESTCASE(subclassablerefcount8, !backend) {
804  bool gone_auto, gone;
805 
806  // Simple test of release().
807  {
809  TEST(!gone);
811  qp.add_valuerangeprocessor(vrp->release());
812  TEST(!gone);
813  }
814  TEST(gone);
815 
816  // Check a second call to release() has no effect.
817  {
819  TEST(!gone);
821  qp.add_valuerangeprocessor(vrp->release());
822  vrp->release();
823  TEST(!gone);
824  }
825  TEST(gone);
826 
827  // Test reference counting works, and that a VRP with automatic storage
828  // works OK.
829  {
830  TestValueRangeProcessor vrp_auto(gone_auto);
831  TEST(!gone_auto);
832  {
834  {
837  vrp = new TestValueRangeProcessor(gone);
838  TEST(!gone);
839  qp1.add_valuerangeprocessor(vrp->release());
840  TEST(!gone);
841  qp2.add_valuerangeprocessor(vrp);
842  TEST(!gone);
843  qp2.add_valuerangeprocessor(&vrp_auto);
844  TEST(!gone);
845  TEST(!gone_auto);
846  }
847  TEST(!gone);
848  }
849  TEST(gone);
850  TEST(!gone_auto);
851  }
852  TEST(gone_auto);
853 
854  // Regression test for initial implementation, where ~opt_intrusive_ptr()
855  // checked the reference of the object, which may have already been deleted
856  // if it wasn't been reference counted.
857  {
859  {
861  new TestValueRangeProcessor(gone);
862  TEST(!gone);
863  qp.add_valuerangeprocessor(vrp);
864  delete vrp;
865  TEST(gone);
866  }
867  // At the end of this block, qp is destroyed, but mustn't dereference
868  // the pointer it has to vrp. If it does, that should get caught
869  // when tests are run under valgrind.
870  }
871 }
872 
874 DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
875  Xapian::Document doc;
876  doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
878  "Document(data='\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff')");
879  doc.set_data(string("\x00\x1f", 2));
881  "Document(data='\\x00\\x1f')");
882  // Check that backslashes are encoded so output isn't ambiguous.
883  doc.set_data("back\\slash");
885  "Document(data='back\\x5cslash')");
886 }
887 
894 DEFINE_TESTCASE(deletewhileiterating1, !backend) {
895  for (bool preinc : { false, true }) {
896  Xapian::Document doc;
897  Xapian::TermGenerator indexer;
898  indexer.set_document(doc);
899  indexer.index_text("Pull the rug out from under ourselves", 1, "S");
900  Xapian::TermIterator term_iterator = doc.termlist_begin();
901  term_iterator.skip_to("S");
902  while (term_iterator != doc.termlist_end()) {
903  const string& term = *term_iterator;
904  if (!startswith(term, "S")) {
905  break;
906  }
907  if (preinc) ++term_iterator;
908  doc.remove_term(term);
909  if (!preinc) ++term_iterator;
910  }
911  TEST_EQUAL(doc.termlist_count(), 0);
912  TEST(doc.termlist_begin() == doc.termlist_end());
913  }
914 }
915 
917 DEFINE_TESTCASE(removepostings, !backend) {
918  Xapian::Document doc;
919  // Add Fibonacci sequence as positions.
920  Xapian::termpos prev_pos = 1;
921  Xapian::termpos pos = 1;
922  while (pos < 1000) {
923  doc.add_posting("foo", pos);
924  auto new_pos = prev_pos + pos;
925  prev_pos = pos;
926  pos = new_pos;
927  }
928 
929  // Check we added exactly one term.
930  TEST_EQUAL(doc.termlist_count(), 1);
931 
933  auto num_pos = t.positionlist_count();
934  TEST_EQUAL(t.get_wdf(), num_pos);
935 
936  // Out of order is a no-op.
937  TEST_EQUAL(doc.remove_postings("foo", 2, 1), 0);
938  t = doc.termlist_begin();
939  TEST_EQUAL(t.positionlist_count(), num_pos);
940  TEST_EQUAL(t.get_wdf(), num_pos);
941 
942  // 6 and 7 aren't in the sequence.
943  TEST_EQUAL(doc.remove_postings("foo", 6, 7), 0);
944  t = doc.termlist_begin();
945  TEST_EQUAL(t.positionlist_count(), num_pos);
946  TEST_EQUAL(t.get_wdf(), num_pos);
947 
948  // Beyond the end of the positions.
949  TEST_EQUAL(doc.remove_postings("foo", 1000, 2000), 0);
950  t = doc.termlist_begin();
951  TEST_EQUAL(t.positionlist_count(), num_pos);
952  TEST_EQUAL(t.get_wdf(), num_pos);
953 
954  // 1, 2, 3 are in the sequence, 4 isn't.
955  TEST_EQUAL(doc.remove_postings("foo", 1, 4), 3);
956  t = doc.termlist_begin();
957  TEST_EQUAL(t.positionlist_count(), num_pos - 3);
958  TEST_EQUAL(t.get_wdf(), num_pos - 3);
959 
960  // Remove the end position.
961  TEST_EQUAL(doc.remove_postings("foo", 876, 987), 1);
962  t = doc.termlist_begin();
963  TEST_EQUAL(t.positionlist_count(), num_pos - 4);
964  TEST_EQUAL(t.get_wdf(), num_pos - 4);
965 
966  // Remove a range in the middle.
967  TEST_EQUAL(doc.remove_postings("foo", 33, 233), 5);
968  t = doc.termlist_begin();
969  TEST_EQUAL(t.positionlist_count(), num_pos - 9);
970  TEST_EQUAL(t.get_wdf(), num_pos - 9);
971 
972  // Check the expected positions are left.
973  t = doc.termlist_begin();
974  static const Xapian::termpos expected[] = { 5, 8, 13, 21, 377, 610, 9999 };
975  const Xapian::termpos* expect = expected;
976  for (auto p = t.positionlist_begin(); p != t.positionlist_end(); ++p) {
977  TEST_EQUAL(*p, *expect);
978  ++expect;
979  }
980 }
981 
982 static void
984 {
985  // GCC 9 was giving a warning on the next line with -Wdeprecated-copy
986  // (which is enabled by -Wextra).
987  throw error;
988 }
989 
991 DEFINE_TESTCASE(errorcopyctor, !backend) {
992  Xapian::RangeError e("test");
993  try {
995  FAIL_TEST("Expected exception to be thrown");
996  } catch (Xapian::Error&) {
997  return;
998  }
999  FAIL_TEST("Expected RangeError wasn't caught");
1000 }
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:80
DestroyedFlag destroyed
Definition: api_none.cc:346
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:415
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:349
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:263
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:709
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:1246
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:265
FieldProcessor * release()
Start reference counting this object.
Definition: queryparser.h:751
string operator()(const Xapian::Document &) const
Build a key string for a Document.
Definition: api_none.cc:628
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:770
a generic test suite engine
DestroyedFlag(bool &destroyed_)
Definition: api_none.cc:253
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:240
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:351
ValueRangeProcessor * release()
Start reference counting this object.
Definition: queryparser.h:434
Xapian::valueno operator()(std::string &, std::string &)
Check for a valid range of this type.
Definition: api_none.cc:797
TestKeyMaker(bool &destroyed_)
Definition: api_none.cc:626
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:260
Base class for value range processors.
Definition: queryparser.h:396
std::string get_metadata(const std::string &key) const
Get the user-specified metadata associated with a given key.
Definition: omdatabase.cc:755
static const int INCLUDE_QUERY_TERMS
Terms in the query may be returned by get_eset().
Definition: enquire.h:591
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:792
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:77
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:983
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:413
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:704
ValueIterator valuestream_end(Xapian::valueno) const
Return end iterator corresponding to valuestream_begin().
Definition: database.h:359
#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:721
Pick the best N subqueries and combine with OP_OR.
Definition: query.h:206
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:46
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:271
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:250
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:132
TestStopper(bool &destroyed_)
Definition: api_none.cc:477
Match like OP_OR but weighting as if a single term.
Definition: query.h:230
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:266
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:269
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:223
TestValueRangeProcessor(bool &destroyed_)
Definition: api_none.cc:795
bool empty() const
Check if this query is Xapian::Query::MatchNothing.
Definition: query.h:515
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:623
DestroyedFlag destroyed
Definition: api_none.cc:410
Xapian::TermIterator metadata_keys_begin(const std::string &prefix=std::string()) const
An iterator which returns all user-specified metadata keys.
Definition: omdatabase.cc:765
KeyMaker * release()
Start reference counting this object.
Definition: keymaker.h:71
Base class for stop-word decision functor.
Definition: queryparser.h:46
bool operator()(const std::string &) const
Is term a stop-word?
Definition: api_none.cc:479
void add_boolean_term(const std::string &term)
Add a boolean filter term to the document.
Definition: document.h:191
DestroyedFlag destroyed
Definition: api_none.cc:474
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:707
#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
Iterator for 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:506