xapian-core  1.4.31
api_none.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2009 Richard Boulton
5  * Copyright (C) 2009-2026 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 #include <vector>
36 
37 using namespace std;
38 
39 // Check the version functions give consistent results.
40 DEFINE_TESTCASE(version1, !backend) {
41  string version = str(Xapian::major_version());
42  version += '.';
43  version += str(Xapian::minor_version());
44  version += '.';
45  version += str(Xapian::revision());
47 }
48 
49 // Regression test: various methods on Database() used to segfault or cause
50 // division by 0. Fixed in 1.1.4 and 1.0.18. Ticket#415.
51 DEFINE_TESTCASE(nosubdatabases1, !backend) {
53  TEST(db.get_metadata("foo").empty());
57  TEST_EQUAL(db.allterms_begin("foo"), db.allterms_end("foo"));
59  TEST_EQUAL(db.get_lastdocid(), 0);
64 
69 }
70 
72 DEFINE_TESTCASE(document1, !backend) {
73  Xapian::Document doc;
74  doc.add_boolean_term("Hxapian.org");
75  TEST_EQUAL(doc.termlist_count(), 1);
77  TEST(t != doc.termlist_end());
78  TEST_EQUAL(*t, "Hxapian.org");
79  TEST_EQUAL(t.get_wdf(), 0);
80  TEST(++t == doc.termlist_end());
81  doc.remove_term("Hxapian.org");
82  TEST_EQUAL(doc.termlist_count(), 0);
83  TEST(doc.termlist_begin() == doc.termlist_end());
84 }
85 
87 DEFINE_TESTCASE(document2, !backend) {
88  Xapian::Document doc;
89  // The return value is uninitialised, so running under valgrind this
90  // will fail reliably prior to the fix.
91  TEST_EQUAL(doc.get_docid(), 0);
92 }
93 
95 DEFINE_TESTCASE(documentclearterms1, !backend) {
96  {
97  Xapian::Document doc;
98  doc.add_boolean_term("Hlocalhost");
99  doc.add_term("hello");
100  doc.add_term("there", 2);
101  doc.add_posting("positional", 1);
102  doc.add_posting("information", 2, 3);
103  TEST_EQUAL(doc.termlist_count(), 5);
104  TEST(doc.termlist_begin() != doc.termlist_end());
105  doc.clear_terms();
106  TEST_EQUAL(doc.termlist_count(), 0);
107  TEST(doc.termlist_begin() == doc.termlist_end());
108  // Test clear_terms() when there are no terms.
109  doc.clear_terms();
110  TEST_EQUAL(doc.termlist_count(), 0);
111  TEST(doc.termlist_begin() == doc.termlist_end());
112  }
113 
114  {
115  // Test clear_terms() when there have never been any terms.
116  Xapian::Document doc;
117  doc.clear_terms();
118  TEST_EQUAL(doc.termlist_count(), 0);
119  TEST(doc.termlist_begin() == doc.termlist_end());
120  }
121 }
122 
124 DEFINE_TESTCASE(documentclearvalues1, !backend) {
125  {
126  Xapian::Document doc;
127  doc.add_value(37, "hello");
128  doc.add_value(42, "world");
129  TEST_EQUAL(doc.values_count(), 2);
130  TEST(doc.values_begin() != doc.values_end());
131  doc.clear_values();
132  TEST_EQUAL(doc.values_count(), 0);
133  TEST(doc.values_begin() == doc.values_end());
134  // Test clear_values() when there are no values.
135  doc.clear_values();
136  TEST_EQUAL(doc.values_count(), 0);
137  TEST(doc.values_begin() == doc.values_end());
138  }
139 
140  {
141  // Test clear_values() when there have never been any values.
142  Xapian::Document doc;
143  doc.clear_values();
144  TEST_EQUAL(doc.values_count(), 0);
145  TEST(doc.termlist_begin() == doc.termlist_end());
146  }
147 }
148 
150 DEFINE_TESTCASE(documentemptyterm1, !backend) {
151  Xapian::Document doc;
153  doc.add_boolean_term(string()));
155  doc.add_term(string()));
157  doc.add_posting(string(), 1));
159  doc.add_posting(string(), 2, 3));
161  doc.remove_term(string()));
163  doc.remove_posting(string(), 1));
165  doc.remove_posting(string(), 2, 3));
167  doc.remove_postings(string(), 2, 3));
169  doc.remove_postings(string(), 2, 3, 4));
170 }
171 
172 DEFINE_TESTCASE(emptyquery4, !backend) {
173  // Test we get an empty query from applying any of the following ops to
174  // an empty list of subqueries.
175  Xapian::Query q;
176  TEST(Xapian::Query(q.OP_AND, &q, &q).empty());
177  TEST(Xapian::Query(q.OP_OR, &q, &q).empty());
178  TEST(Xapian::Query(q.OP_AND_NOT, &q, &q).empty());
179  TEST(Xapian::Query(q.OP_XOR, &q, &q).empty());
180  TEST(Xapian::Query(q.OP_AND_MAYBE, &q, &q).empty());
181  TEST(Xapian::Query(q.OP_FILTER, &q, &q).empty());
182  TEST(Xapian::Query(q.OP_NEAR, &q, &q).empty());
183  TEST(Xapian::Query(q.OP_PHRASE, &q, &q).empty());
184  TEST(Xapian::Query(q.OP_ELITE_SET, &q, &q).empty());
185  TEST(Xapian::Query(q.OP_SYNONYM, &q, &q).empty());
186  TEST(Xapian::Query(q.OP_MAX, &q, &q).empty());
187 }
188 
189 DEFINE_TESTCASE(singlesubquery1, !backend) {
190  // Test that we get just the subquery if we apply any of the following
191  // ops to just that subquery.
192 #define singlesubquery1_(OP) \
193  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
194  "Query(test)")
195  Xapian::Query q[1] = { Xapian::Query("test") };
196  singlesubquery1_(OP_AND);
197  singlesubquery1_(OP_OR);
198  singlesubquery1_(OP_AND_NOT);
199  singlesubquery1_(OP_XOR);
200  singlesubquery1_(OP_AND_MAYBE);
201  singlesubquery1_(OP_FILTER);
202  singlesubquery1_(OP_NEAR);
203  singlesubquery1_(OP_PHRASE);
204  singlesubquery1_(OP_ELITE_SET);
205  singlesubquery1_(OP_SYNONYM);
206  singlesubquery1_(OP_MAX);
207 }
208 
209 DEFINE_TESTCASE(singlesubquery2, !backend) {
210  // Like the previous test, but using MatchNothing as the subquery.
211 #define singlesubquery2_(OP) \
212  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
213  "Query()")
215  singlesubquery2_(OP_AND);
216  singlesubquery2_(OP_OR);
217  singlesubquery2_(OP_AND_NOT);
218  singlesubquery2_(OP_XOR);
219  singlesubquery2_(OP_AND_MAYBE);
220  singlesubquery2_(OP_FILTER);
221  singlesubquery2_(OP_NEAR);
222  singlesubquery2_(OP_PHRASE);
223  singlesubquery2_(OP_ELITE_SET);
224  singlesubquery2_(OP_SYNONYM);
225  singlesubquery2_(OP_MAX);
226 }
227 
228 DEFINE_TESTCASE(singlesubquery3, !backend) {
229  // Like the previous test, but using MatchAll as the subquery.
230 #define singlesubquery3_(OP) \
231  TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
232  "Query(<alldocuments>)")
234  singlesubquery3_(OP_AND);
235  singlesubquery3_(OP_OR);
236  singlesubquery3_(OP_AND_NOT);
237  singlesubquery3_(OP_XOR);
238  singlesubquery3_(OP_AND_MAYBE);
239  singlesubquery3_(OP_FILTER);
240  // OP_NEAR and OP_PHRASE over MatchAll doesn't really make sense.
241  singlesubquery3_(OP_ELITE_SET);
242  singlesubquery3_(OP_SYNONYM);
243  singlesubquery3_(OP_MAX);
244 }
245 
246 DEFINE_TESTCASE(pairwisequery1, !backend) {
247  // Test that constructing from char* and const char* gives the same result
248  // as explicitly constructing Query objects for the subqueries. This
249  // serves as a regression test for using char*/const char* not compiling
250  // with Xapian <= 1.4.30.
251 #define lit_a "a"
252 #define lit_b "b"
253  char aa[] = lit_a;
254  char ab[] = lit_b;
255  const char* ca = aa;
256  const char* cb = ab;
257  Xapian::Query qa(aa);
258  Xapian::Query qb(ab);
259 
260 #define pairwisequery1_(OP) do {\
261  auto expect = Xapian::Query(qa.OP, lit_a, lit_b).get_description(); \
262  TEST_STRINGS_EQUAL(expect, \
263  Xapian::Query(qa.OP, aa, ab).get_description()); \
264  TEST_STRINGS_EQUAL(expect, \
265  Xapian::Query(qa.OP, ca, cb).get_description()); \
266  TEST_STRINGS_EQUAL(expect, \
267  Xapian::Query(qa.OP, qa, qb).get_description()); \
268  } while (false)
269 
270  pairwisequery1_(OP_AND);
271  pairwisequery1_(OP_OR);
272  pairwisequery1_(OP_AND_NOT);
273  pairwisequery1_(OP_XOR);
274  pairwisequery1_(OP_AND_MAYBE);
275  pairwisequery1_(OP_FILTER);
276  pairwisequery1_(OP_NEAR);
277  pairwisequery1_(OP_PHRASE);
278  pairwisequery1_(OP_ELITE_SET);
279  pairwisequery1_(OP_SYNONYM);
280  pairwisequery1_(OP_MAX);
281 }
282 
284 DEFINE_TESTCASE(combinewqfnomore1, !backend) {
286  Xapian::Query("beer", 1, 1),
287  Xapian::Query("beer", 1, 1));
288  // Prior to 1.3.0, we would have given beer@2, but we decided that wasn't
289  // really useful or helpful.
290  TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
291 }
292 
294  bool & destroyed;
295 
296  public:
297  DestroyedFlag(bool & destroyed_) : destroyed(destroyed_) {
298  destroyed = false;
299  }
300 
302  destroyed = true;
303  }
304 };
305 
308 
309  public:
310  TestRangeProcessor(bool & destroyed_)
311  : Xapian::RangeProcessor(0), destroyed(destroyed_) { }
312 
313  Xapian::Query operator()(const std::string&, const std::string&) override {
315  }
316 };
317 
319 DEFINE_TESTCASE(subclassablerefcount1, !backend) {
320  bool gone_auto, gone;
321 
322  // Simple test of release().
323  {
325  TEST(!gone);
327  qp.add_rangeprocessor(rp->release());
328  TEST(!gone);
329  }
330  TEST(gone);
331 
332  // Check a second call to release() has no effect.
333  {
335  TEST(!gone);
337  qp.add_rangeprocessor(rp->release());
338  rp->release();
339  TEST(!gone);
340  }
341  TEST(gone);
342 
343  // Test reference counting works, and that a RangeProcessor with automatic
344  // storage works OK.
345  {
346  TestRangeProcessor rp_auto(gone_auto);
347  TEST(!gone_auto);
348  {
350  {
353  rp = new TestRangeProcessor(gone);
354  TEST(!gone);
355  qp1.add_rangeprocessor(rp->release());
356  TEST(!gone);
357  qp2.add_rangeprocessor(rp);
358  TEST(!gone);
359  qp2.add_rangeprocessor(&rp_auto);
360  TEST(!gone);
361  TEST(!gone_auto);
362  }
363  TEST(!gone);
364  }
365  TEST(gone);
366  TEST(!gone_auto);
367  }
368  TEST(gone_auto);
369 
370  // Regression test for initial implementation, where ~opt_intrusive_ptr()
371  // checked the reference of the object, which may have already been deleted
372  // if it wasn't been reference counted.
373  {
375  {
377  TEST(!gone);
378  qp.add_rangeprocessor(rp);
379  delete rp;
380  TEST(gone);
381  }
382  // At the end of this block, qp is destroyed, but mustn't dereference
383  // the pointer it has to rp. If it does, that should get caught
384  // when tests are run under valgrind.
385  }
386 }
387 
390 
391  public:
392  TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
393 
394  Xapian::Query operator()(const string& str) override {
395  return Xapian::Query(str);
396  }
397 };
398 
400 DEFINE_TESTCASE(subclassablerefcount2, !backend) {
401  bool gone_auto, gone;
402 
403  // Simple test of release().
404  {
405  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
406  TEST(!gone);
408  qp.add_prefix("foo", proc->release());
409  TEST(!gone);
410  }
411  TEST(gone);
412 
413  // Check a second call to release() has no effect.
414  {
415  Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
416  TEST(!gone);
418  qp.add_prefix("foo", proc->release());
419  proc->release();
420  TEST(!gone);
421  }
422  TEST(gone);
423 
424  // Test reference counting works, and that a FieldProcessor with automatic
425  // storage works OK.
426  {
427  TestFieldProcessor proc_auto(gone_auto);
428  TEST(!gone_auto);
429  {
431  {
433  Xapian::FieldProcessor * proc;
434  proc = new TestFieldProcessor(gone);
435  TEST(!gone);
436  qp1.add_prefix("foo", proc->release());
437  TEST(!gone);
438  qp2.add_prefix("foo", proc);
439  TEST(!gone);
440  qp2.add_prefix("bar", &proc_auto);
441  TEST(!gone);
442  TEST(!gone_auto);
443  }
444  TEST(!gone);
445  }
446  TEST(gone);
447  TEST(!gone_auto);
448  }
449  TEST(gone_auto);
450 }
451 
454 
455  public:
456  TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
457 
458  void operator()(const Xapian::Document&, double) override { }
459 };
460 
462 DEFINE_TESTCASE(subclassablerefcount3, backend) {
463  Xapian::Database db = get_database("apitest_simpledata");
464 
465  bool gone_auto, gone;
466 
467  // Simple test of release().
468  {
469  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
470  TEST(!gone);
471  Xapian::Enquire enquire(db);
472  enquire.add_matchspy(spy->release());
473  TEST(!gone);
474  }
475  TEST(gone);
476 
477  // Check a second call to release() has no effect.
478  {
479  Xapian::MatchSpy * spy = new TestMatchSpy(gone);
480  TEST(!gone);
481  Xapian::Enquire enquire(db);
482  enquire.add_matchspy(spy->release());
483  spy->release();
484  TEST(!gone);
485  }
486  TEST(gone);
487 
488  // Test reference counting works, and that a MatchSpy with automatic
489  // storage works OK.
490  {
491  TestMatchSpy spy_auto(gone_auto);
492  TEST(!gone_auto);
493  {
494  Xapian::Enquire enq1(db);
495  {
496  Xapian::Enquire enq2(db);
497  Xapian::MatchSpy * spy;
498  spy = new TestMatchSpy(gone);
499  TEST(!gone);
500  enq1.add_matchspy(spy->release());
501  TEST(!gone);
502  enq2.add_matchspy(spy);
503  TEST(!gone);
504  enq2.add_matchspy(&spy_auto);
505  TEST(!gone);
506  TEST(!gone_auto);
507  }
508  TEST(!gone);
509  }
510  TEST(gone);
511  TEST(!gone_auto);
512  }
513  TEST(gone_auto);
514 }
515 
516 class TestStopper : public Xapian::Stopper {
518 
519  public:
520  TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
521 
522  bool operator()(const std::string&) const override { return true; }
523 };
524 
526 DEFINE_TESTCASE(subclassablerefcount4, !backend) {
527  bool gone_auto, gone;
528 
529  // Simple test of release().
530  {
531  Xapian::Stopper * stopper = new TestStopper(gone);
532  TEST(!gone);
534  qp.set_stopper(stopper->release());
535  TEST(!gone);
536  }
537  TEST(gone);
538 
539  // Test that setting a new stopper causes the previous one to be released.
540  {
541  bool gone0;
542  Xapian::Stopper * stopper0 = new TestStopper(gone0);
543  TEST(!gone0);
545  qp.set_stopper(stopper0->release());
546  TEST(!gone0);
547 
548  Xapian::Stopper * stopper = new TestStopper(gone);
549  TEST(!gone);
550  qp.set_stopper(stopper->release());
551  TEST(gone0);
552  TEST(!gone);
553  }
554  TEST(gone);
555 
556  // Check a second call to release() has no effect.
557  {
558  Xapian::Stopper * stopper = new TestStopper(gone);
559  TEST(!gone);
561  qp.set_stopper(stopper->release());
562  stopper->release();
563  TEST(!gone);
564  }
565  TEST(gone);
566 
567  // Test reference counting works, and that a Stopper with automatic
568  // storage works OK.
569  {
570  TestStopper stopper_auto(gone_auto);
571  TEST(!gone_auto);
572  {
574  {
576  Xapian::Stopper * stopper;
577  stopper = new TestStopper(gone);
578  TEST(!gone);
579  qp1.set_stopper(stopper->release());
580  TEST(!gone);
581  qp2.set_stopper(stopper);
582  TEST(!gone);
583  qp2.set_stopper(&stopper_auto);
584  TEST(!gone);
585  TEST(!gone_auto);
586  }
587  TEST(!gone);
588  }
589  TEST(gone);
590  TEST(!gone_auto);
591  }
592  TEST(gone_auto);
593 }
594 
596 DEFINE_TESTCASE(subclassablerefcount5, !backend) {
597  bool gone_auto, gone;
598 
599  // Simple test of release().
600  {
601  Xapian::Stopper * stopper = new TestStopper(gone);
602  TEST(!gone);
603  Xapian::TermGenerator indexer;
604  indexer.set_stopper(stopper->release());
605  TEST(!gone);
606  }
607  TEST(gone);
608 
609  // Test that setting a new stopper causes the previous one to be released.
610  {
611  bool gone0;
612  Xapian::Stopper * stopper0 = new TestStopper(gone0);
613  TEST(!gone0);
614  Xapian::TermGenerator indexer;
615  indexer.set_stopper(stopper0->release());
616  TEST(!gone0);
617 
618  Xapian::Stopper * stopper = new TestStopper(gone);
619  TEST(!gone);
620  indexer.set_stopper(stopper->release());
621  TEST(gone0);
622  TEST(!gone);
623  }
624  TEST(gone);
625 
626  // Check a second call to release() has no effect.
627  {
628  Xapian::Stopper * stopper = new TestStopper(gone);
629  TEST(!gone);
630  Xapian::TermGenerator indexer;
631  indexer.set_stopper(stopper->release());
632  stopper->release();
633  TEST(!gone);
634  }
635  TEST(gone);
636 
637  // Test reference counting works, and that a Stopper with automatic
638  // storage works OK.
639  {
640  TestStopper stopper_auto(gone_auto);
641  TEST(!gone_auto);
642  {
643  Xapian::TermGenerator indexer1;
644  {
645  Xapian::TermGenerator indexer2;
646  Xapian::Stopper * stopper;
647  stopper = new TestStopper(gone);
648  TEST(!gone);
649  indexer1.set_stopper(stopper->release());
650  TEST(!gone);
651  indexer2.set_stopper(stopper);
652  TEST(!gone);
653  indexer2.set_stopper(&stopper_auto);
654  TEST(!gone);
655  TEST(!gone_auto);
656  }
657  TEST(!gone);
658  }
659  TEST(gone);
660  TEST(!gone_auto);
661  }
662  TEST(gone_auto);
663 }
664 
667 
668  public:
669  TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
670 
671  string operator()(const Xapian::Document&) const override {
672  return string();
673  }
674 };
675 
677 DEFINE_TESTCASE(subclassablerefcount6, backend) {
678  Xapian::Database db = get_database("apitest_simpledata");
679 
680  bool gone_auto, gone;
681 
682  // Simple test of release().
683  {
684  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
685  TEST(!gone);
686  Xapian::Enquire enq(db);
687  enq.set_sort_by_key(keymaker->release(), false);
688  TEST(!gone);
689  }
690  TEST(gone);
691 
692  // Test that setting a new keymaker causes the previous one to be released.
693  {
694  bool gone0;
695  Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
696  TEST(!gone0);
697  Xapian::Enquire enq(db);
698  enq.set_sort_by_key(keymaker0->release(), false);
699  TEST(!gone0);
700 
701  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
702  TEST(!gone);
703  enq.set_sort_by_key_then_relevance(keymaker->release(), false);
704  TEST(gone0);
705  TEST(!gone);
706  }
707  TEST(gone);
708 
709  // Check a second call to release() has no effect.
710  {
711  Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
712  TEST(!gone);
713  Xapian::Enquire enq(db);
714  enq.set_sort_by_key(keymaker->release(), false);
715  keymaker->release();
716  TEST(!gone);
717  }
718  TEST(gone);
719 
720  // Test reference counting works, and that a KeyMaker with automatic
721  // storage works OK.
722  {
723  TestKeyMaker keymaker_auto(gone_auto);
724  TEST(!gone_auto);
725  {
726  Xapian::Enquire enq1(db);
727  {
728  Xapian::Enquire enq2(db);
729  Xapian::KeyMaker * keymaker;
730  keymaker = new TestKeyMaker(gone);
731  TEST(!gone);
732  enq1.set_sort_by_key(keymaker->release(), false);
733  TEST(!gone);
734  enq2.set_sort_by_relevance_then_key(keymaker, false);
735  TEST(!gone);
736  enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
737  TEST(!gone);
738  TEST(!gone_auto);
739  }
740  TEST(!gone);
741  }
742  TEST(gone);
743  TEST(!gone_auto);
744  }
745  TEST(gone_auto);
746 }
747 
750 
751  public:
752  TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
753 
754  bool operator()(const string&) const override { return true; }
755 };
756 
758 DEFINE_TESTCASE(subclassablerefcount7, backend) {
759  Xapian::Database db = get_database("apitest_simpledata");
760  Xapian::Enquire enq(db);
761  Xapian::RSet rset;
762  rset.add_document(1);
763 
764  bool gone_auto, gone;
765 
766  for (int flags = 0;
769  // Test of auto lifetime ExpandDecider.
770  {
771  TestExpandDecider edecider_auto(gone_auto);
772  TEST(!gone_auto);
773  (void)enq.get_eset(5, rset, 0, &edecider_auto);
774  TEST(!gone_auto);
775  }
776  TEST(gone_auto);
777 
778  // Simple test of release().
779  {
780  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
781  TEST(!gone);
782  (void)enq.get_eset(5, rset, 0, edecider);
783  TEST(!gone);
784  delete edecider;
785  TEST(gone);
786  }
787 
788  // Test that a released ExpandDecider gets cleaned up by get_eset().
789  {
790  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
791  TEST(!gone);
792  (void)enq.get_eset(5, rset, 0, edecider->release());
793  TEST(gone);
794  }
795 
796  // Check a second call to release() has no effect.
797  {
798  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
799  TEST(!gone);
800  edecider->release();
801  TEST(!gone);
802  (void)enq.get_eset(5, rset, 0, edecider->release());
803  TEST(gone);
804  }
805  }
806 
807  // Test combinations of released/non-released with ExpandDeciderAnd.
808  {
809  TestExpandDecider edecider_auto(gone_auto);
810  TEST(!gone_auto);
811  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
812  TEST(!gone);
813  (void)enq.get_eset(5, rset, 0,
815  &edecider_auto,
816  edecider->release()))->release());
817  TEST(!gone_auto);
818  TEST(gone);
819  }
820  TEST(gone_auto);
821  {
822  TestExpandDecider edecider_auto(gone_auto);
823  TEST(!gone_auto);
824  Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
825  TEST(!gone);
826  (void)enq.get_eset(5, rset, 0,
828  edecider->release(),
829  &edecider_auto))->release());
830  TEST(!gone_auto);
831  TEST(gone);
832  }
833  TEST(gone_auto);
834 }
835 
838 
839  public:
840  TestValueRangeProcessor(bool & destroyed_) : destroyed(destroyed_) { }
841 
842  Xapian::valueno operator()(std::string &, std::string &) {
843  return 42;
844  }
845 };
846 
848 DEFINE_TESTCASE(subclassablerefcount8, !backend) {
849  bool gone_auto, gone;
850 
851  // Simple test of release().
852  {
854  TEST(!gone);
856  qp.add_valuerangeprocessor(vrp->release());
857  TEST(!gone);
858  }
859  TEST(gone);
860 
861  // Check a second call to release() has no effect.
862  {
864  TEST(!gone);
866  qp.add_valuerangeprocessor(vrp->release());
867  vrp->release();
868  TEST(!gone);
869  }
870  TEST(gone);
871 
872  // Test reference counting works, and that a VRP with automatic storage
873  // works OK.
874  {
875  TestValueRangeProcessor vrp_auto(gone_auto);
876  TEST(!gone_auto);
877  {
879  {
882  vrp = new TestValueRangeProcessor(gone);
883  TEST(!gone);
884  qp1.add_valuerangeprocessor(vrp->release());
885  TEST(!gone);
886  qp2.add_valuerangeprocessor(vrp);
887  TEST(!gone);
888  qp2.add_valuerangeprocessor(&vrp_auto);
889  TEST(!gone);
890  TEST(!gone_auto);
891  }
892  TEST(!gone);
893  }
894  TEST(gone);
895  TEST(!gone_auto);
896  }
897  TEST(gone_auto);
898 
899  // Regression test for initial implementation, where ~opt_intrusive_ptr()
900  // checked the reference of the object, which may have already been deleted
901  // if it wasn't been reference counted.
902  {
904  {
906  new TestValueRangeProcessor(gone);
907  TEST(!gone);
908  qp.add_valuerangeprocessor(vrp);
909  delete vrp;
910  TEST(gone);
911  }
912  // At the end of this block, qp is destroyed, but mustn't dereference
913  // the pointer it has to vrp. If it does, that should get caught
914  // when tests are run under valgrind.
915  }
916 }
917 
919 DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
920  Xapian::Document doc;
921  doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
923  "Document(data='\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff')");
924  doc.set_data(string("\x00\x1f", 2));
926  "Document(data='\\x00\\x1f')");
927  // Check that backslashes are encoded so output isn't ambiguous.
928  doc.set_data("back\\slash");
930  "Document(data='back\\x5cslash')");
931 }
932 
939 DEFINE_TESTCASE(deletewhileiterating1, !backend) {
940  for (bool preinc : { false, true }) {
941  Xapian::Document doc;
942  Xapian::TermGenerator indexer;
943  indexer.set_document(doc);
944  indexer.index_text("Pull the rug out from under ourselves", 1, "S");
945  Xapian::TermIterator term_iterator = doc.termlist_begin();
946  term_iterator.skip_to("S");
947  while (term_iterator != doc.termlist_end()) {
948  const string& term = *term_iterator;
949  if (!startswith(term, "S")) {
950  break;
951  }
952  if (preinc) ++term_iterator;
953  doc.remove_term(term);
954  if (!preinc) ++term_iterator;
955  }
956  TEST_EQUAL(doc.termlist_count(), 0);
957  TEST(doc.termlist_begin() == doc.termlist_end());
958  }
959 }
960 
962 DEFINE_TESTCASE(removepostings, !backend) {
963  Xapian::Document doc;
964  // Add Fibonacci sequence as positions.
965  Xapian::termpos prev_pos = 1;
966  Xapian::termpos pos = 1;
967  while (pos < 1000) {
968  doc.add_posting("foo", pos);
969  auto new_pos = prev_pos + pos;
970  prev_pos = pos;
971  pos = new_pos;
972  }
973 
974  // Check we added exactly one term.
975  TEST_EQUAL(doc.termlist_count(), 1);
976 
978  auto num_pos = t.positionlist_count();
979  TEST_EQUAL(t.get_wdf(), num_pos);
980 
981  // Out of order is a no-op.
982  TEST_EQUAL(doc.remove_postings("foo", 2, 1), 0);
983  t = doc.termlist_begin();
984  TEST_EQUAL(t.positionlist_count(), num_pos);
985  TEST_EQUAL(t.get_wdf(), num_pos);
986 
987  // 6 and 7 aren't in the sequence.
988  TEST_EQUAL(doc.remove_postings("foo", 6, 7), 0);
989  t = doc.termlist_begin();
990  TEST_EQUAL(t.positionlist_count(), num_pos);
991  TEST_EQUAL(t.get_wdf(), num_pos);
992 
993  // Beyond the end of the positions.
994  TEST_EQUAL(doc.remove_postings("foo", 1000, 2000), 0);
995  t = doc.termlist_begin();
996  TEST_EQUAL(t.positionlist_count(), num_pos);
997  TEST_EQUAL(t.get_wdf(), num_pos);
998 
999  // 1, 2, 3 are in the sequence, 4 isn't.
1000  TEST_EQUAL(doc.remove_postings("foo", 1, 4), 3);
1001  t = doc.termlist_begin();
1002  TEST_EQUAL(t.positionlist_count(), num_pos - 3);
1003  TEST_EQUAL(t.get_wdf(), num_pos - 3);
1004 
1005  // Remove the end position.
1006  TEST_EQUAL(doc.remove_postings("foo", 876, 987), 1);
1007  t = doc.termlist_begin();
1008  TEST_EQUAL(t.positionlist_count(), num_pos - 4);
1009  TEST_EQUAL(t.get_wdf(), num_pos - 4);
1010 
1011  // Remove a range in the middle.
1012  TEST_EQUAL(doc.remove_postings("foo", 33, 233), 5);
1013  t = doc.termlist_begin();
1014  TEST_EQUAL(t.positionlist_count(), num_pos - 9);
1015  TEST_EQUAL(t.get_wdf(), num_pos - 9);
1016 
1017  // Check the expected positions are left.
1018  t = doc.termlist_begin();
1019  static const Xapian::termpos expected[] = { 5, 8, 13, 21, 377, 610, 9999 };
1020  const Xapian::termpos* expect = expected;
1021  for (auto p = t.positionlist_begin(); p != t.positionlist_end(); ++p) {
1022  TEST_EQUAL(*p, *expect);
1023  ++expect;
1024  }
1025 }
1026 
1027 static void
1029 {
1030  // GCC 9 was giving a warning on the next line with -Wdeprecated-copy
1031  // (which is enabled by -Wextra).
1032  throw error;
1033 }
1034 
1036 DEFINE_TESTCASE(errorcopyctor, !backend) {
1037  Xapian::RangeError e("test");
1038  try {
1040  } catch (Xapian::Error&) {
1041  return;
1042  }
1043  FAIL_TEST("Expected exception to be thrown");
1044 }
1045 
1046 // Test ESetIterator iterator_traits.
1047 DEFINE_TESTCASE(stlesetiterator, !backend) {
1048  Xapian::ESet eset;
1049  vector<string> v;
1050  // This gave a compile error with stdc++ and -DGLIBCXX_DEBUG in 1.4.30:
1051  v.insert(v.begin(), eset.begin(), eset.end());
1052 }
1053 
1054 // Test MSetIterator iterator_traits.
1055 DEFINE_TESTCASE(stlmsetiterator, !backend) {
1056  Xapian::MSet mset;
1057  vector<Xapian::docid> v;
1058  // In Xapian <= 1.4.30 this gave a compile error with libc++, or
1059  // with stdc++ and -DGLIBCXX_DEBUG:
1060  v.insert(v.begin(), mset.begin(), mset.end());
1061 }
1062 
1063 // Test PositionIterator iterator_traits.
1064 DEFINE_TESTCASE(stlpositioniterator, !backend) {
1065  Xapian::Database db;
1066  vector<Xapian::termpos> v;
1067  if (db.get_doccount() > 0) {
1068  // In Xapian <= 1.4.30 this gave a compile error with stdc++ and
1069  // -DGLIBCXX_DEBUG:
1070  v.insert(v.begin(),
1071  db.positionlist_begin(1, ""),
1072  db.positionlist_end(1, ""));
1073  }
1074 }
1075 
1076 // Test PostingIterator iterator_traits.
1077 DEFINE_TESTCASE(stlpostingiterator, !backend) {
1078  Xapian::Database db;
1079  vector<Xapian::docid> v;
1080  // In Xapian <= 1.4.30 this gave a compile error with stdc++ and
1081  // -DGLIBCXX_DEBUG:
1082  v.insert(v.begin(), db.postlist_begin(""), db.postlist_end(""));
1083 }
1084 
1085 // Test TermIterator iterator_traits.
1086 DEFINE_TESTCASE(stltermiterator, !backend) {
1087  Xapian::Document doc;
1088  vector<string> v;
1089  // In Xapian <= 1.4.30 this gave a compile error with stdc++ and
1090  // -DGLIBCXX_DEBUG:
1091  v.insert(v.begin(), doc.termlist_begin(), doc.termlist_end());
1092 }
1093 
1094 // Test Utf8Iterator iterator_traits.
1095 DEFINE_TESTCASE(stlutf8iterator, !backend) {
1096  vector<unsigned> v;
1097  // In Xapian <= 1.4.30 this gave a compile error with stdc++ and
1098  // -DGLIBCXX_DEBUG:
1099  v.insert(v.begin(), Xapian::Utf8Iterator(""), Xapian::Utf8Iterator());
1100 }
1101 
1102 // Test ValueIterator iterator_traits.
1103 DEFINE_TESTCASE(stlvalueiterator, !backend) {
1104  Xapian::Document doc;
1105  vector<string> v;
1106  // In Xapian <= 1.4.30 this gave a compile error with stdc++ and
1107  // -DGLIBCXX_DEBUG:
1108  v.insert(v.begin(), doc.values_begin(), doc.values_end());
1109 }
DEFINE_TESTCASE(version1, !backend)
Definition: api_none.cc:40
#define singlesubquery1_(OP)
#define singlesubquery3_(OP)
#define singlesubquery2_(OP)
#define lit_a
static void errorcopyctor_helper(Xapian::Error &error)
Definition: api_none.cc:1028
#define pairwisequery1_(OP)
#define lit_b
Xapian::Database get_database(const string &dbname)
Definition: apitest.cc:48
test functionality of the Xapian API
DestroyedFlag(bool &destroyed_)
Definition: api_none.cc:297
bool & destroyed
Definition: api_none.cc:294
TestExpandDecider(bool &destroyed_)
Definition: api_none.cc:752
DestroyedFlag destroyed
Definition: api_none.cc:749
bool operator()(const string &) const override
Do we want this term in the ESet?
Definition: api_none.cc:754
TestFieldProcessor(bool &destroyed_)
Definition: api_none.cc:392
DestroyedFlag destroyed
Definition: api_none.cc:389
Xapian::Query operator()(const string &str) override
Convert a field-prefixed string to a Query object.
Definition: api_none.cc:394
string operator()(const Xapian::Document &) const override
Build a key string for a Document.
Definition: api_none.cc:671
TestKeyMaker(bool &destroyed_)
Definition: api_none.cc:669
DestroyedFlag destroyed
Definition: api_none.cc:666
DestroyedFlag destroyed
Definition: api_none.cc:453
void operator()(const Xapian::Document &, double) override
Register a document with the match spy.
Definition: api_none.cc:458
TestMatchSpy(bool &destroyed_)
Definition: api_none.cc:456
Xapian::Query operator()(const std::string &, const std::string &) override
Check for a valid range of this type.
Definition: api_none.cc:313
DestroyedFlag destroyed
Definition: api_none.cc:307
TestRangeProcessor(bool &destroyed_)
Definition: api_none.cc:310
DestroyedFlag destroyed
Definition: api_none.cc:517
bool operator()(const std::string &) const override
Is term a stop-word?
Definition: api_none.cc:522
TestStopper(bool &destroyed_)
Definition: api_none.cc:520
Xapian::valueno operator()(std::string &, std::string &)
Check for a valid range of this type.
Definition: api_none.cc:842
DestroyedFlag destroyed
Definition: api_none.cc:837
TestValueRangeProcessor(bool &destroyed_)
Definition: api_none.cc:840
This class is used to access a database, or a group of databases.
Definition: database.h:68
PostingIterator postlist_begin(const std::string &tname) const
An iterator pointing to the start of the postlist for a given term.
Definition: omdatabase.cc:162
std::string get_metadata(const std::string &key) const
Get the user-specified metadata associated with a given key.
Definition: omdatabase.cc:749
ValueIterator valuestream_begin(Xapian::valueno slot) const
Return an iterator over the value in slot slot for each document.
Definition: omdatabase.cc:450
ValueIterator valuestream_end(Xapian::valueno) const
Return end iterator corresponding to valuestream_begin().
Definition: database.h:368
PostingIterator postlist_end(const std::string &) const
Corresponding end iterator to postlist_begin().
Definition: database.h:230
Xapian::TermIterator metadata_keys_end(const std::string &=std::string()) const
Corresponding end iterator to metadata_keys_begin().
Definition: database.h:515
TermIterator termlist_begin(Xapian::docid did) const
An iterator pointing to the start of the termlist for a given document.
Definition: omdatabase.cc:198
Xapian::TermIterator metadata_keys_begin(const std::string &prefix=std::string()) const
An iterator which returns all user-specified metadata keys.
Definition: omdatabase.cc:759
Xapian::termcount get_doclength(Xapian::docid did) const
Get the length of a document.
Definition: omdatabase.cc:461
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
TermIterator allterms_end(const std::string &=std::string()) const
Corresponding end iterator to allterms_begin(prefix).
Definition: database.h:274
Xapian::doccount get_doccount() const
Get the number of documents in the database.
Definition: omdatabase.cc:267
Xapian::Document get_document(Xapian::docid did) const
Get a document from the database, given its document id.
Definition: omdatabase.cc:490
Xapian::docid get_lastdocid() const
Get the highest document id which has been used in the database.
Definition: omdatabase.cc:279
PositionIterator positionlist_end(Xapian::docid, const std::string &) const
Corresponding end iterator to positionlist_begin().
Definition: database.h:259
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
Xapian::termcount get_unique_terms(Xapian::docid did) const
Get the number of unique terms in document.
Definition: omdatabase.cc:476
A handle representing a document in a Xapian database.
Definition: document.h:61
void remove_term(const std::string &tname)
Remove a term and all postings associated with it.
Definition: omdocument.cc:177
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
void add_value(Xapian::valueno slot, const std::string &value)
Add a new value.
Definition: omdocument.cc:107
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
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
ValueIterator values_begin() const
Iterator for the values in this document.
Definition: omdocument.cc:210
docid get_docid() const
Get the document id which is associated with this document (if any).
Definition: omdocument.cc:220
void add_boolean_term(const std::string &term)
Add a boolean filter term to the document.
Definition: document.h:192
TermIterator termlist_end() const
Equivalent end iterator for termlist_begin().
Definition: document.h:270
ValueIterator values_end() const
Equivalent end iterator for values_begin().
Definition: document.h:281
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::termcount termlist_count() const
The length of the termlist - i.e.
Definition: omdocument.cc:191
TermIterator termlist_begin() const
Start iterating the terms in this document.
Definition: omdocument.cc:197
void clear_values()
Remove all values associated with the document.
Definition: omdocument.cc:121
std::string get_description() const
Return a string describing this object.
Definition: omdocument.cc:101
void clear_terms()
Remove all terms (and postings) from the document.
Definition: omdocument.cc:184
void set_data(const std::string &data)
Set data stored in the document.
Definition: omdocument.cc:78
Xapian::termcount values_count() const
Count the values in this document.
Definition: omdocument.cc:204
Class representing a list of search results.
Definition: eset.h:43
ESetIterator end() const
Return iterator pointing to just after the last item in this ESet.
Definition: eset.h:350
ESetIterator begin() const
Return iterator pointing to the first item in this ESet.
Definition: eset.h:345
This class provides an interface to the information retrieval system for the purpose of searching.
Definition: enquire.h:152
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
void add_matchspy(MatchSpy *spy)
Add a matchspy.
Definition: omenquire.cc:807
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
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 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
static const int INCLUDE_QUERY_TERMS
Terms in the query may be returned by get_eset().
Definition: enquire.h:595
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:43
ExpandDecider subclass which rejects terms using two ExpandDeciders.
Definition: expanddecider.h:88
Virtual base class for expand decider functor.
Definition: expanddecider.h:38
ExpandDecider * release()
Start reference counting this object.
Definition: expanddecider.h:65
Base class for field processors.
Definition: queryparser.h:749
FieldProcessor * release()
Start reference counting this object.
Definition: queryparser.h:778
InvalidArgumentError indicates an invalid parameter value was passed to the API.
Definition: error.h:241
InvalidOperationError indicates the API was used in an invalid way.
Definition: error.h:283
Virtual base class for key making functors.
Definition: keymaker.h:42
KeyMaker * release()
Start reference counting this object.
Definition: keymaker.h:71
Class representing a list of search results.
Definition: mset.h:44
MSetIterator begin() const
Return iterator pointing to the first item in this MSet.
Definition: mset.h:624
MSetIterator end() const
Return iterator pointing to just after the last item in this MSet.
Definition: mset.h:629
Abstract base class for match spies.
Definition: matchspy.h:50
MatchSpy * release()
Start reference counting this object.
Definition: matchspy.h:184
Build a Xapian::Query object from a user query string.
Definition: queryparser.h:797
void add_rangeprocessor(Xapian::RangeProcessor *range_proc, const std::string *grouping=NULL)
Register a RangeProcessor.
Definition: queryparser.cc:253
void add_valuerangeprocessor(Xapian::ValueRangeProcessor *vrproc)
Register a ValueRangeProcessor.
Definition: queryparser.h:1319
void set_stopper(const Stopper *stop=NULL)
Set the stopper.
Definition: queryparser.cc:97
void add_prefix(const std::string &field, const std::string &prefix)
Add a free-text field term prefix.
Definition: queryparser.cc:184
Class representing a query.
Definition: query.h:56
bool empty() const
Check if this query is Xapian::Query::MatchNothing.
Definition: query.h:537
std::string get_description() const
Return a string describing this object.
Definition: query.cc:232
@ OP_MAX
Pick the maximum weight of any subquery.
Definition: query.h:259
@ OP_XOR
Match documents which an odd number of subqueries match.
Definition: query.h:117
@ OP_AND_MAYBE
Match the first subquery taking extra weight from other subqueries.
Definition: query.h:128
@ OP_NEAR
Match only documents where all subqueries match near each other.
Definition: query.h:150
@ OP_ELITE_SET
Pick the best N subqueries and combine with OP_OR.
Definition: query.h:225
@ OP_AND
Match only documents which all subqueries match.
Definition: query.h:94
@ OP_OR
Match documents which at least one subquery matches.
Definition: query.h:102
@ OP_FILTER
Match like OP_AND but only taking weight from the first subquery.
Definition: query.h:138
@ OP_PHRASE
Match only documents where all subqueries match near and in order.
Definition: query.h:162
@ OP_SYNONYM
Match like OP_OR but weighting as if a single term.
Definition: query.h:249
@ OP_AND_NOT
Match documents which the first subquery matches but no others do.
Definition: query.h:109
static const Xapian::Query MatchNothing
A query matching no documents.
Definition: query.h:75
static const Xapian::Query MatchAll
A query matching all documents.
Definition: query.h:85
A relevance set (R-Set).
Definition: enquire.h:60
void add_document(Xapian::docid did)
Add a document to the relevance set.
Definition: omenquire.cc:104
RangeError indicates an attempt to access outside the bounds of a container.
Definition: error.h:971
Base class for range processors.
Definition: queryparser.h:141
RangeProcessor * release()
Start reference counting this object.
Definition: queryparser.h:233
Abstract base class for stop-word decision functor.
Definition: queryparser.h:51
Stopper * release()
Start reference counting this object.
Definition: queryparser.h:81
Parses a piece of text and generate terms.
Definition: termgenerator.h:48
void index_text(const Xapian::Utf8Iterator &itor, Xapian::termcount wdf_inc=1, const std::string &prefix=std::string())
Index some text.
void set_document(const Xapian::Document &doc)
Set the current document.
void set_stopper(const Xapian::Stopper *stop=NULL)
Set the Xapian::Stopper object to be used for identifying stopwords.
Class for iterating over a list of terms.
Definition: termiterator.h:41
Xapian::termcount positionlist_count() const
Return the length of the position list for the current position.
void skip_to(const std::string &term)
Advance the iterator to term term.
PositionIterator positionlist_end() const
Return an end PositionIterator for the current term.
Definition: termiterator.h:110
Xapian::termcount get_wdf() const
Return the wdf for the term at the current position.
PositionIterator positionlist_begin() const
Return a PositionIterator for the current term.
An iterator which returns Unicode character values from a UTF-8 encoded string.
Definition: unicode.h:38
Base class for value range processors.
Definition: queryparser.h:424
ValueRangeProcessor * release()
Start reference counting this object.
Definition: queryparser.h:461
This class provides read/write access to a database.
Definition: database.h:795
void begin_transaction(bool flushed=true)
Begin a transaction.
Definition: omdatabase.cc:859
void commit_transaction()
Complete the transaction currently in progress.
Definition: omdatabase.cc:870
void cancel_transaction()
Abort the transaction currently in progress, discarding the pending modifications made to the databas...
Definition: omdatabase.cc:881
string str(int value)
Convert int to std::string.
Definition: str.cc:90
The Xapian namespace contains public interfaces for the Xapian library.
Definition: compactor.cc:80
int major_version()
Report the major version of the library which the program is linked with.
Definition: xapian.h:124
int revision()
Report the revision of the library which the program is linked with.
Definition: xapian.h:142
unsigned valueno
The number for a value slot in a document.
Definition: types.h:108
const char * version_string()
Report the version string of the library which the program is linked with.
Definition: xapian.h:115
int minor_version()
Report the minor version of the library which the program is linked with.
Definition: xapian.h:133
unsigned XAPIAN_TERMPOS_BASE_TYPE termpos
A term position within a document or query.
Definition: types.h:83
Convert types to std::string.
bool startswith(const std::string &s, char pfx)
Definition: stringutils.h:51
a generic test suite engine
#define FAIL_TEST(MSG)
Fail the current testcase with message MSG.
Definition: testsuite.h:68
#define TEST_EQUAL(a, b)
Test for equality of two things.
Definition: testsuite.h:278
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:275
Xapian-specific test helper functions and macros.
#define TEST_EXCEPTION(TYPE, CODE)
Check that CODE throws exactly Xapian exception TYPE.
Definition: testutils.h:109
Public interfaces for the Xapian library.