xapian-core  2.0.0
unittest.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006-2025 Olly Betts
5  * Copyright (C) 2007 Richard Boulton
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, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include <cctype>
25 #include <cerrno>
26 #include <cfloat>
27 #include <climits>
28 #include <cmath>
29 #include <cstring>
30 #include <iostream>
31 #include <limits>
32 #include <memory>
33 #include <string_view>
34 #include <utility>
35 
36 #include "safeunistd.h"
37 
38 #define XAPIAN_UNITTEST
39 static const char * unittest_assertion_failed = NULL;
40 #define UNITTEST_CHECK_EXCEPTION \
41  if (unittest_assertion_failed) { \
42  const char * unittest_assertion_failed_ = unittest_assertion_failed;\
43  unittest_assertion_failed = NULL;\
44  throw unittest_assertion_failed_;\
45  }
46 
47 #include "testsuite.h"
48 
49 #define UNITTEST_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG
50 #define UNITTEST_ASSERT_LOCATION_(LINE,MSG) UNITTEST_ASSERT_LOCATION__(LINE,MSG)
51 #define UNITTEST_ASSERT_LOCATION(MSG) UNITTEST_ASSERT_LOCATION_(__LINE__,MSG)
52 #define UNITTEST_ASSERT_NOTHROW(COND, RET) \
53  do {\
54  if (rare(!(COND))) {\
55  unittest_assertion_failed = UNITTEST_ASSERT_LOCATION(COND);\
56  return RET;\
57  }\
58  } while (false)
59 
60 // Utility code we use:
61 #include "../backends/multi.h"
62 #include "../common/stringutils.h"
63 
64 // Simpler version of TEST_EXCEPTION macro.
65 #define TEST_EXCEPTION(TYPE, CODE) \
66  do { \
67  try { \
68  CODE; \
69  UNITTEST_CHECK_EXCEPTION \
70  FAIL_TEST("Expected exception "#TYPE" not thrown"); \
71  } catch (const TYPE &) { \
72  } \
73  } while (0)
74 
75 // Code we're unit testing:
76 #include "../backends/uuids.cc"
77 #include "../common/closefrom.cc"
78 #include "../common/errno_to_string.cc"
79 #include "../common/io_utils.cc"
80 #include "../common/fileutils.cc"
81 #include "../common/overflow.h"
82 #include "../common/pack.cc"
83 #include "../common/parseint.h"
84 #include "../common/posixy_wrapper.cc"
85 #include "../common/serialise-double.cc"
86 #include "../common/str.cc"
87 #include "../net/serialise-error.cc"
88 #include "../api/error.cc"
89 #include "../api/smallvector.cc"
90 #include "../api/sortable-serialise.cc"
91 #include "../include/xapian/intrusive_ptr.h"
92 
93 // fileutils.cc uses opendir(), etc though not in a function we currently test.
94 #include "../common/msvc_dirent.cc"
95 
96 // The UUID code uses hex_decode().
97 #include "../api/constinfo.cc"
98 
99 using namespace std;
100 
101 // Stub replacement, which doesn't deal with escaping or producing valid UTF-8.
102 // The full implementation needs Xapian::Utf8Iterator and
103 // Xapian::Unicode::append_utf8().
104 void
105 description_append(std::string& desc, std::string_view s)
106 {
107  desc += s;
108 }
109 
110 DEFINE_TESTCASE(simple_exceptions_work1) {
111  try {
112  throw 42;
113  } catch (int val) {
114  TEST_EQUAL(val, 42);
115  }
116 }
117 
118 class TestException { };
119 
120 DEFINE_TESTCASE(class_exceptions_work1) {
121  try {
122  throw TestException();
123  } catch (const TestException &) {
124  }
125 }
126 
127 static inline string
128 r_r_p(string a, const string & b)
129 {
130  resolve_relative_path(a, b);
131  return a;
132 }
133 
134 DEFINE_TESTCASE(resolverelativepath1) {
135  TEST_EQUAL(r_r_p("/abs/o/lute", ""), "/abs/o/lute");
136  TEST_EQUAL(r_r_p("/abs/o/lute", "/"), "/abs/o/lute");
137  TEST_EQUAL(r_r_p("/abs/o/lute", "//"), "/abs/o/lute");
138  TEST_EQUAL(r_r_p("/abs/o/lute", "foo"), "/abs/o/lute");
139  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/"), "/abs/o/lute");
140  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo"), "/abs/o/lute");
141  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/"), "/abs/o/lute");
142  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar"), "/abs/o/lute");
143  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar/"), "/abs/o/lute");
144  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar"), "/abs/o/lute");
145  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar/"), "/abs/o/lute");
146  TEST_EQUAL(r_r_p("rel/a/tive", ""), "rel/a/tive");
147  TEST_EQUAL(r_r_p("rel/a/tive", "/"), "/rel/a/tive");
148  TEST_EQUAL(r_r_p("rel/a/tive", "//"), "//rel/a/tive");
149  TEST_EQUAL(r_r_p("rel/a/tive", "foo"), "rel/a/tive");
150  TEST_EQUAL(r_r_p("rel/a/tive", "foo/"), "foo/rel/a/tive");
151  TEST_EQUAL(r_r_p("rel/a/tive", "/foo"), "/rel/a/tive");
152  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/"), "/foo/rel/a/tive");
153  TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar"), "foo/rel/a/tive");
154  TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar/"), "foo/bar/rel/a/tive");
155  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar"), "/foo/rel/a/tive");
156  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar/"), "/foo/bar/rel/a/tive");
157 #ifndef __WIN32__
158  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo\\bar"), "/abs/o/lute");
159  TEST_EQUAL(r_r_p("rel/a/tive", "/foo\\bar"), "/rel/a/tive");
160 #else
161  TEST_EQUAL(r_r_p("\\dos\\path", ""), "\\dos\\path");
162  TEST_EQUAL(r_r_p("\\dos\\path", "/"), "\\dos\\path");
163  TEST_EQUAL(r_r_p("\\dos\\path", "\\"), "\\dos\\path");
164  TEST_EQUAL(r_r_p("\\dos\\path", "c:"), "c:\\dos\\path");
165  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\"), "c:\\dos\\path");
166  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp"), "c:\\dos\\path");
167  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp\\"), "c:\\dos\\path");
168  TEST_EQUAL(r_r_p("rel/a/tive", "\\"), "\\rel/a/tive");
169  TEST_EQUAL(r_r_p("rel/a/tive", "foo\\"), "foo\\rel/a/tive");
170  TEST_EQUAL(r_r_p("rel\\a\\tive", "/foo/"), "/foo/rel\\a\\tive");
171  TEST_EQUAL(r_r_p("rel/a/tive", "c:/foo/bar"), "c:/foo/rel/a/tive");
172  TEST_EQUAL(r_r_p("rel/a/tive", "c:foo/bar/"), "c:foo/bar/rel/a/tive");
173  TEST_EQUAL(r_r_p("rel/a/tive", "c:"), "c:rel/a/tive");
174  TEST_EQUAL(r_r_p("rel/a/tive", "c:\\"), "c:\\rel/a/tive");
175  TEST_EQUAL(r_r_p("C:rel/a/tive", "c:\\foo\\bar"), "C:\\foo\\rel/a/tive");
176  TEST_EQUAL(r_r_p("C:rel/a/tive", "c:"), "C:rel/a/tive");
177  // This one is impossible to reliably resolve without knowing the current
178  // drive - if it is C:, then the answer is: "C:/abs/o/rel/a/tive"
179  TEST_EQUAL(r_r_p("C:rel/a/tive", "/abs/o/lute"), "C:rel/a/tive");
180  // UNC paths tests:
181  TEST_EQUAL(r_r_p("\\\\SRV\\VOL\\FILE", "/a/b"), "\\\\SRV\\VOL\\FILE");
182  TEST_EQUAL(r_r_p("rel/a/tive", "\\\\SRV\\VOL\\DIR\\FILE"), "\\\\SRV\\VOL\\DIR\\rel/a/tive");
183  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\SRV\\VOL\\FILE"), "\\\\SRV\\VOL/abs/o/lute");
184  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\FILE"), "\\\\S\\V/abs/o/lute");
185  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\"), "\\\\S\\V/abs/o/lute");
186  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V"), "\\\\S\\V/abs/o/lute");
187  TEST_EQUAL(r_r_p("//SRV/VOL/FILE", "/a/b"), "//SRV/VOL/FILE");
188  TEST_EQUAL(r_r_p("rel/a/tive", "//SRV/VOL/DIR/FILE"), "//SRV/VOL/DIR/rel/a/tive");
189  TEST_EQUAL(r_r_p("/abs/o/lute", "//SRV/VOL/FILE"), "//SRV/VOL/abs/o/lute");
190  TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/FILE"), "//S/V/abs/o/lute");
191  TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/"), "//S/V/abs/o/lute");
192  TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V"), "//S/V/abs/o/lute");
193  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\abs\\o\\lute");
194  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
195  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
196  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
197  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\r\\elativ\\e");
198  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble\\wobble"), "\\\\?\\C:\\wibble\\r\\elativ\\e");
199 #if 0 // Is this a valid testcase? It fails, but isn't relevant to Xapian.
200  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
201 #endif
202  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
203  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\TMP\\r\\elativ\\e");
204 #endif
205 }
206 
207 static void
209 {
210  // Commonly C++ string implementations keep the string nul-terminated, and
211  // encoded.data() returns a pointer to a buffer including the nul (the same
212  // as encoded.c_str()). This means that valgrind won't catch a read one
213  // past the end of the serialised value, so we copy just the serialised
214  // value into a temporary buffer.
215  char buf[16];
216  string encoded = serialise_double(u);
217  TEST(encoded.size() < sizeof(buf));
218  memcpy(buf, encoded.data(), encoded.size());
219  // Put a NULL pointer either side, to catch incrementing/decrementing at
220  // the wrong level of indirection (regression test for a bug in an
221  // unreleased version).
222  const char * ptr[3] = { NULL, buf, NULL };
223  const char * end = ptr[1] + encoded.size();
224  double v = unserialise_double(&(ptr[1]), end);
225  if (ptr[1] != end || u != v) {
226  cout << u << " -> " << v << ", difference = " << v - u << '\n';
227  cout << "FLT_RADIX = " << FLT_RADIX << '\n';
228  cout << "DBL_MAX_EXP = " << DBL_MAX_EXP << '\n';
229  }
230  TEST_EQUAL(static_cast<const void*>(ptr[1]), static_cast<const void*>(end));
231 }
232 
233 // Check serialisation of doubles.
234 DEFINE_TESTCASE(serialisedouble1) {
235  static const double test_values[] = {
236  3.14159265,
237  1e57,
238  123.1,
239  257.12,
240  1234.567e123,
241  255.5,
242  256.125,
243  257.03125,
244  };
245 
250  check_double_serialisation(-DBL_MAX);
252  check_double_serialisation(-DBL_MIN);
253 
254  for (double val : test_values) {
257  check_double_serialisation(1.0 / val);
258  check_double_serialisation(-1.0 / val);
259  }
260 }
261 
262 // Test pack_uint() and unpack_uint().
263 static void test_packuint1()
264 {
265  size_t n = 0;
266  while (n < 0xff000000) {
267  string s;
268  pack_uint(s, n);
269  const char* p = s.data();
270  const char* p_end = p + s.size();
271  size_t decoded_n;
272  TEST(unpack_uint(&p, p_end, &decoded_n));
273  if (n != decoded_n || p != p_end) tout << "[" << s << "]\n";
274  TEST_EQUAL(n, decoded_n);
275  TEST_EQUAL(p_end - p, 0);
276  if (n < 5000) {
277  ++n;
278  } else {
279  n += 53643;
280  }
281  }
282 }
283 
284 static void
286 {
287  string s;
288  pack_string(s, string(len, 'x'));
289  {
290  const char* p = s.data();
291  const char* p_end = p + s.size();
292  // unpack_string() should overwrite any existing value.
293  string r = "dummy";
294  TEST(unpack_string(&p, p_end, r));
295  TEST_EQUAL(r.size(), len);
296  TEST_EQUAL(r.find_first_not_of('x'), r.npos);
297  TEST(p == p_end);
298  }
299  s += 'x';
300  {
301  const char* p = s.data();
302  const char* p_end = p + s.size();
303  // unpack_string() should overwrite any existing value.
304  string r = "dummy";
305  TEST(unpack_string(&p, p_end, r));
306  TEST_EQUAL(r.size(), len);
307  TEST_EQUAL(r.find_first_not_of('x'), r.npos);
308  TEST_EQUAL(p_end - p, 1);
309  }
310  // Test truncated encodings fail to unpack.
311  size_t trunc_len = s.size() - 2;
312  do {
313  const char* p = s.data();
314  const char* p_end = p + trunc_len;
315  string r;
316  TEST(!unpack_string(&p, p_end, r));
317  TEST(!p);
318  trunc_len >>= 1;
319  } while (trunc_len);
320 }
321 
322 // Test pack_string() and unpack_string().
323 static void test_packstring1()
324 {
327  // Nothing magic here, just test a range of odd and even values.
328  for (size_t n = 2; n < 1000; n = (n + 1) * 2 + (n >> 1)) {
330  }
331 }
332 
333 // Test pack_string_empty()
334 static void test_packstring2()
335 {
336  string s;
337  pack_string(s, {});
338  string s_empty;
339  pack_string_empty(s_empty);
340  TEST_EQUAL(s, s_empty);
341 }
342 
343 #ifdef XAPIAN_HAS_REMOTE_BACKEND
344 // Check serialisation of Xapian::Error.
345 static void test_serialiseerror1()
346 {
347  string enoent_msg = errno_to_string(ENOENT);
348  Xapian::DatabaseOpeningError e("Failed to open database", ENOENT);
349  // Regression test for bug in 1.0.0 - it didn't convert errno values for
350  // get_description() if they hadn't already been converted.
351  TEST_STRINGS_EQUAL(e.get_description(), "DatabaseOpeningError: Failed to open database (" + enoent_msg + ")");
352 
353  TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
354 
355  string serialisation = serialise_error(e);
356 
357  // Test if unserialise_error() throws with a flag to avoid the possibility
358  // of an "unreachable code" warning when we get around to marking
359  // unserialise_error() as "noreturn".
360  bool threw = false;
361  try {
362  // unserialise_error throws an exception.
363  unserialise_error(serialisation, "", "");
364  } catch (const Xapian::Error & ecaught) {
365  TEST_STRINGS_EQUAL(ecaught.get_error_string(), enoent_msg);
366  threw = true;
367  }
368  TEST(threw);
369 
370  // Check that the original is still OK.
371  TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
372 
373  // Regression test - in 1.0.0, copying used to duplicate the error_string
374  // pointer, resulting in double calls to free().
376  TEST_STRINGS_EQUAL(ecopy.get_error_string(), enoent_msg);
377 }
378 #endif
379 
380 static const double test_sortableserialise_numbers[] = {
381  -HUGE_VAL,
382  -DBL_MAX,
383  -exp2(1022),
384  -1024.5,
385  -3.14159265358979323846,
386  -3,
387  -2,
388  -1.8,
389  -1.1,
390  -1,
391  -0.5,
392  -0.2,
393  -0.1,
394  -0.000005,
395  -0.000002,
396  -0.000001,
397  -exp2(-1023),
398  -exp2(-1024),
399  -exp2(-1074),
400  -DBL_MIN,
401  0,
402  DBL_MIN,
403  exp2(-1074),
404  exp2(-1024),
405  exp2(-1023),
406  0.000001,
407  0.000002,
408  0.000005,
409  0.1,
410  0.2,
411  0.5,
412  1,
413  1.1,
414  1.8,
415  2,
416  3,
417  3.14159265358979323846,
418  1024.5,
419  exp2(1022),
420  DBL_MAX,
421  HUGE_VAL,
422 
423  64 // Magic number which we stop at.
424 };
425 
426 // Test serialisation and unserialisation of various numbers.
427 // This is actually a public API, but we want extra assertions in the code
428 // while we test it.
430 {
431  double prevnum = 0;
432  string prevstr;
433  bool started = false;
434  for (const double *p = test_sortableserialise_numbers; *p != 64; ++p) {
435  double num = *p;
436  tout << "Number: " << num << '\n';
437  string str = Xapian::sortable_serialise(num);
438  tout << "String: " << str << '\n';
440 
441  if (started) {
442  int num_cmp = 0;
443  if (prevnum < num) {
444  num_cmp = -1;
445  } else if (prevnum > num) {
446  num_cmp = 1;
447  }
448  int str_cmp = 0;
449  if (prevstr < str) {
450  str_cmp = -1;
451  } else if (prevstr > str) {
452  str_cmp = 1;
453  }
454 
455  TEST_AND_EXPLAIN(num_cmp == str_cmp,
456  "Numbers " << prevnum << " and " << num <<
457  " don't sort the same way as their string "
458  "counterparts");
459  }
460 
461  prevnum = num;
462  prevstr = str;
463  started = true;
464  }
465 }
466 
467 template<typename S>
468 inline static void tostring_helper() {
469  const S max_val = numeric_limits<S>::max();
470  const S min_val = numeric_limits<S>::min();
471  tout << "Testing with tostring_helper\n";
472  std::ostringstream oss;
473  oss << (long long)max_val;
474  TEST_EQUAL(str(max_val), oss.str());
475  oss.str("");
476  oss.clear();
477 
478  oss << (long long)min_val;
479  TEST_EQUAL(str(min_val), oss.str());
480  oss.str("");
481  oss.clear();
482 }
483 
484 static void test_tostring1()
485 {
486  TEST_EQUAL(str(0), "0");
487  TEST_EQUAL(str(0u), "0");
488  TEST_EQUAL(str(1), "1");
489  TEST_EQUAL(str(1u), "1");
490  TEST_EQUAL(str(9), "9");
491  TEST_EQUAL(str(9u), "9");
492  TEST_EQUAL(str(10), "10");
493  TEST_EQUAL(str(10u), "10");
494  TEST_EQUAL(str(-1), "-1");
495  TEST_EQUAL(str(-9), "-9");
496  TEST_EQUAL(str(-10), "-10");
497  TEST_EQUAL(str(0x7f), "127");
498  TEST_EQUAL(str(-0x80), "-128");
499  TEST_EQUAL(str(0x7fff), "32767");
500  TEST_EQUAL(str(0xffffffff), "4294967295");
501  TEST_EQUAL(str(0x7fffffff), "2147483647");
502  TEST_EQUAL(str(0x7fffffffu), "2147483647");
503  TEST_EQUAL(str(-0x7fffffff), "-2147483647");
504 
505  tostring_helper<char>();
506  tostring_helper<short>();
507  tostring_helper<int>();
508  tostring_helper<long>();
509  tostring_helper<long long>();
510 
511 #ifdef __WIN32__
512  /* Test the 64 bit integer conversion to string.
513  * (Currently only exists for windows.)
514  */
515  TEST_EQUAL(str(10ll), "10");
516  TEST_EQUAL(str(-10ll), "-10");
517  TEST_EQUAL(str(0x200000000ll), "8589934592");
518 // We don't currently have an "unsigned long long" version since it's not required
519 // anywhere in the library.
520 // TEST_EQUAL(str(0x200000000ull), "8589934592");
521 #endif
522 }
523 
525 static void test_strbool1()
526 {
527  TEST_EQUAL(str(true), "1");
528  TEST_EQUAL(str(false), "0");
529 }
530 
531 static void test_closefrom1()
532 {
533 #ifndef __WIN32__
534  // Simple test. Start from 13 as on macOS the FDTracker seems to get fd
535  // 10 and we don't want to collide with that.
536  closefrom(13);
537 
538  // Simple test when there are definitely no fds to close.
539  closefrom(42);
540 
541  // Test passing a really high threshold.
542  closefrom(INT_MAX);
543 
544  // Open some fds and check the expected ones are closed.
545  TEST_EQUAL(dup2(1, 14), 14);
546  TEST_EQUAL(dup2(1, 15), 15);
547  TEST_EQUAL(dup2(1, 18), 18);
548  closefrom(15);
549  TEST_EQUAL(close(14), 0);
550  TEST(close(15) == -1 && errno == EBADF);
551  TEST(close(18) == -1 && errno == EBADF);
552 #endif
553 }
554 
555 static void test_shard1()
556 {
557  for (Xapian::docid did = 1; did != 10; ++did) {
558  for (Xapian::doccount n = 1; n != 10; ++n) {
559  Xapian::docid s_did = shard_docid(did, n);
560  Xapian::doccount shard = shard_number(did, n);
561  TEST_EQUAL(s_did, (did - 1) / n + 1);
562  TEST_EQUAL(shard, (did - 1) % n);
563  if (n == 1)
564  TEST_EQUAL(did, s_did);
565  if (did == 1)
566  TEST_EQUAL(s_did, 1);
567  if (s_did == 1)
568  TEST(did <= n);
569  TEST(s_did != 0);
570  TEST(s_did <= did);
571  TEST(shard < n);
572  TEST_EQUAL(did, unshard(s_did, shard, n));
573  }
574  }
575 }
576 
577 static void test_uuid1()
578 {
579  Uuid uuid, uuid2;
580 
581  // Test a generated uuid.
582  uuid.generate();
583  TEST(!uuid.is_null());
584  string str = uuid.to_string();
585  TEST_EQUAL(str.size(), 36);
586  TEST_NOT_EQUAL(str, "00000000-0000-0000-0000-000000000000");
587  // Check UUID pattern is correct and that upper case is not used.
588  for (int i = 0; i != 8; ++i) {
589  unsigned char ch = str[i];
590  TEST(isxdigit(ch));
591  TEST(!isupper(ch));
592  }
593  TEST_EQUAL(str[8], '-');
594  for (int i = 9; i != 13; ++i) {
595  unsigned char ch = str[i];
596  TEST(isxdigit(ch));
597  TEST(!isupper(ch));
598  }
599  TEST_EQUAL(str[13], '-');
600  for (int i = 14; i != 18; ++i) {
601  unsigned char ch = str[i];
602  TEST(isxdigit(ch));
603  TEST(!isupper(ch));
604  }
605  TEST_EQUAL(str[18], '-');
606  for (int i = 19; i != 23; ++i) {
607  unsigned char ch = str[i];
608  TEST(isxdigit(ch));
609  TEST(!isupper(ch));
610  }
611  TEST_EQUAL(str[23], '-');
612  for (int i = 24; i != 36; ++i) {
613  unsigned char ch = str[i];
614  TEST(isxdigit(ch));
615  TEST(!isupper(ch));
616  }
617 
618  uuid2.parse(str);
619  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) == 0);
620 
621  // Check the variant is "10x" and the version between 1 and 5. Mostly this
622  // is to catch bugs where the platform's API for generating UUIDs uses a
623  // different endianness for fields (which we've run into under both WIN32
624  // and FreeBSD).
625  TEST_EQUAL(uuid.data()[8] & 0xc0, 0x80);
626  TEST_REL(str[19], >=, '8');
627  TEST_REL(str[19], <=, 'b');
628  TEST_REL(int(uuid.data()[6]), >=, 0x10);
629  TEST_REL(int(uuid.data()[6]), <=, 0x5f);
630  TEST_REL(str[14], >=, '1');
631  TEST_REL(str[14], <=, '5');
632 
633  // Test generating another uuid gives us a different non-null uuid.
634  uuid2.generate();
635  TEST(!uuid2.is_null());
636  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) != 0);
637 
638  // Test null uuid.
639  uuid.clear();
640  TEST(uuid.is_null());
641  str = uuid.to_string();
642  TEST_EQUAL(str, "00000000-0000-0000-0000-000000000000");
643  uuid2.generate();
644  TEST(!uuid2.is_null());
645  uuid2.parse(str);
646  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) == 0);
647 }
648 
649 // Classes used by movesupport1 test
651  int x = 0;
652  public:
653  explicit A(int x_) : x(x_) {}
654 
655  int get_x() const {
656  return x;
657  }
658 };
659 
661  int x = 0;
662  bool & alive;
663  public:
664  B(int x_, bool & alive_) : x(x_), alive(alive_) {
665  alive = true;
666  }
667 
668  ~B() {
669  alive = false;
670  }
671 
672  int get_x() const {
673  return x;
674  }
675 
676  B * release() {
677  opt_intrusive_base::release();
678  return this;
679  }
680 };
681 
682 static void test_movesupport1()
683 {
684  {
685  // Test move semantics support for intrusive_ptr class
688 
689  // Test move constructor
690  Xapian::Internal::intrusive_ptr<A> p2(std::move(p1));
691  TEST(p2);
692  TEST_EQUAL(p2->get_x(), 5);
693  TEST_EQUAL(p1.get(), 0);
694  TEST(!p1);
695 
696  // Test move assignment
697  p3 = std::move(p2);
698  TEST(p3);
699  TEST_EQUAL(p3->get_x(), 5);
700  TEST_EQUAL(p2.get(), 0);
701  TEST(!p2);
702  }
703 
704  {
705  // Same test for intrusive_ptr_nonnull class
708 
709  // Test move constructor
711  TEST(p2.get());
712  TEST_EQUAL(p2->get_x(), 5);
713 
714  // Test move assignment
715  p3 = std::move(p2);
716  TEST(p3.get());
717  TEST_EQUAL(p3->get_x(), 5);
718  }
719 
720  bool alive = false;
721  {
722  // Same test for opt_intrusive_ptr class
723  B * b1 = new B{5, alive};
724  b1->release();
727 
728  // Test move constructor
729  Xapian::Internal::opt_intrusive_ptr<B> p2(std::move(p1));
730  TEST(p2);
731  TEST_EQUAL(p2->get_x(), 5);
732  TEST_EQUAL(p1.get(), 0);
733  TEST(!p1);
734  TEST_EQUAL(alive, true);
735 
736  // Test move assignment
737  p3 = std::move(p2);
738  TEST(p3);
739  TEST_EQUAL(p3->get_x(), 5);
740  TEST_EQUAL(p2.get(), 0);
741  TEST(!p2);
742  TEST_EQUAL(alive, true);
743  }
744  // Test that object b1 has been deleted.
745  TEST_EQUAL(alive, false);
746 }
747 
748 static void test_addoverflows1()
749 {
750  const auto ulong_max = numeric_limits<unsigned long>::max();
751  const auto uint_max = numeric_limits<unsigned int>::max();
752  const auto ushort_max = numeric_limits<unsigned short>::max();
753  const auto uchar_max = numeric_limits<unsigned char>::max();
754 
755  unsigned long res_ulong;
756  unsigned res_uint;
757  unsigned short res_ushort;
758  unsigned char res_uchar;
759 
760  TEST(!add_overflows(0UL, 0UL, res_ulong));
761  TEST_EQUAL(res_ulong, 0);
762  TEST(!add_overflows(0UL, 0UL, res_uint));
763  TEST_EQUAL(res_uint, 0);
764  TEST(!add_overflows(0UL, 0UL, res_ushort));
765  TEST_EQUAL(res_ushort, 0);
766  TEST(!add_overflows(0UL, 0UL, res_uchar));
767  TEST_EQUAL(res_uchar, 0);
768 
769  TEST(add_overflows(ulong_max, 1UL, res_ulong));
770  TEST_EQUAL(res_ulong, 0);
771  TEST(add_overflows(uint_max, 1UL, res_uint));
772  TEST_EQUAL(res_uint, 0);
773  TEST(add_overflows(ushort_max, 1UL, res_ushort));
774  TEST_EQUAL(res_ushort, 0);
775  TEST(add_overflows(uchar_max, 1UL, res_uchar));
776  TEST_EQUAL(res_uchar, 0);
777 
778  TEST(add_overflows(1UL, ulong_max, res_ulong));
779  TEST_EQUAL(res_ulong, 0);
780  TEST(add_overflows(1UL, uint_max, res_uint));
781  TEST_EQUAL(res_uint, 0);
782  TEST(add_overflows(1UL, ushort_max, res_ushort));
783  TEST_EQUAL(res_ushort, 0);
784  TEST(add_overflows(1UL, uchar_max, res_uchar));
785  TEST_EQUAL(res_uchar, 0);
786 
787  TEST(add_overflows(ulong_max, ulong_max, res_ulong));
788  TEST_EQUAL(res_ulong, ulong_max - 1UL);
789  TEST(add_overflows(uint_max, uint_max, res_uint));
790  TEST_EQUAL(res_uint, uint_max - 1UL);
791  TEST(add_overflows(ushort_max, ushort_max, res_ushort));
792  TEST_EQUAL(res_ushort, ushort_max - 1UL);
793  TEST(add_overflows(uchar_max, uchar_max, res_uchar));
794  TEST_EQUAL(res_uchar, uchar_max - 1UL);
795 
796  res_uchar = 1;
797  TEST(add_overflows(res_uchar, unsigned(uchar_max) + 1U, res_uchar));
798  TEST_EQUAL(res_uchar, 1);
799 }
800 
801 static void test_suboverflows1()
802 {
803  unsigned long res;
804  TEST(!sub_overflows(0UL, 0UL, res));
805  TEST_EQUAL(res, 0);
806 
807  TEST(sub_overflows(0UL, 1UL, res));
808  TEST_EQUAL(res, ULONG_MAX);
809 
810  TEST(sub_overflows(ULONG_MAX - 1UL, ULONG_MAX, res));
811  TEST_EQUAL(res, ULONG_MAX);
812 
813  TEST(sub_overflows(0UL, ULONG_MAX, res));
814  TEST_EQUAL(res, 1);
815 }
816 
817 static void test_muloverflows1()
818 {
819  unsigned long res;
820  TEST(!mul_overflows(0UL, 0UL, res));
821  TEST_EQUAL(res, 0);
822 
823  TEST(!mul_overflows(ULONG_MAX, 0UL, res));
824  TEST_EQUAL(res, 0);
825 
826  TEST(!mul_overflows(0UL, ULONG_MAX, res));
827  TEST_EQUAL(res, 0);
828 
829  TEST(!mul_overflows(ULONG_MAX, 1UL, res));
830  TEST_EQUAL(res, ULONG_MAX);
831 
832  TEST(!mul_overflows(1UL, ULONG_MAX, res));
833  TEST_EQUAL(res, ULONG_MAX);
834 
835  TEST(mul_overflows((ULONG_MAX >> 1UL) + 1UL, 2UL, res));
836  TEST_EQUAL(res, 0);
837 
838  TEST(mul_overflows(2UL, (ULONG_MAX >> 1UL) + 1UL, res));
839  TEST_EQUAL(res, 0);
840 
841  TEST(mul_overflows(ULONG_MAX, ULONG_MAX, res));
842 }
843 
844 template<typename U>
845 inline static void parseunsigned_helper() {
846  U val;
847  constexpr U max_val = numeric_limits<U>::max();
848  tout << "Testing with parseunsigned_helper\n";
849  TEST(parse_unsigned("0", val));
850  TEST_EQUAL(val, 0);
851  TEST(parse_unsigned("99", val));
852  TEST_EQUAL(val, 99);
853  TEST(parse_unsigned(str(max_val).c_str(), val));
854  TEST_EQUAL(val, max_val);
855  TEST(!parse_unsigned("", val));
856  TEST(!parse_unsigned("-1", val));
857  TEST(!parse_unsigned("abc", val));
858  TEST(!parse_unsigned("0a", val));
859  // Only test if we can construct a value one larger easily.
860  if constexpr(max_val + 1ull != 0)
861  TEST(!parse_unsigned(str(max_val + 1ull).c_str(), val));
862 }
863 
864 static void test_parseunsigned1()
865 {
866  parseunsigned_helper<unsigned char>();
867  parseunsigned_helper<unsigned short>();
868  parseunsigned_helper<unsigned>();
869  parseunsigned_helper<unsigned long>();
870  parseunsigned_helper<unsigned long long>();
871 }
872 
873 template<typename S>
874 inline static void parsesigned_helper() {
875  S val;
876  const S max_val = numeric_limits<S>::max();
877  const S min_val = numeric_limits<S>::min();
878  tout << "Testing with parsesigned_helper\n";
879  TEST(parse_signed("0", val));
880  TEST_EQUAL(val, 0);
881  TEST(parse_signed("99", val));
882  TEST_EQUAL(val, 99);
883  TEST(parse_signed("-99", val));
884  TEST_EQUAL(val, -99);
885  TEST(parse_signed(str(max_val).c_str(), val));
886  TEST_EQUAL(val, max_val);
887  TEST(parse_signed(str(min_val).c_str(), val));
888  TEST_EQUAL(val, min_val);
889  TEST(!parse_signed("", val));
890  TEST(!parse_signed("abc", val));
891  TEST(!parse_signed("0a", val));
892  TEST(!parse_signed("-99a", val));
893  TEST(!parse_signed("-a99", val));
894  TEST(!parse_signed("--99", val));
895 
896  unsigned long long one_too_large = max_val + 1ull;
897  TEST(!parse_signed(str(one_too_large).c_str(), val));
898 
899  // We need to use an unsigned long long here so this works when S is
900  // long long. The somewhat contorted way we calculate this is to
901  // avoid unsigned overflow and value-changing implicit conversions.
902  // These aren't undefined behaviour, but we want to limit where they
903  // happen in the library to a few low-level places and ubsan's extra
904  // checks provide a way to check that, so keeping the testsuite clean
905  // of such warnings is useful.
906  unsigned long long one_too_small_negated =
907  static_cast<unsigned long long>(-(min_val + 1)) + 2ull;
908  TEST(!parse_signed(("-" + str(one_too_small_negated)).c_str(), val));
909 }
910 
911 static void test_parsesigned1()
912 {
913  parsesigned_helper<signed char>();
914  parsesigned_helper<short>();
915  parsesigned_helper<int>();
916  parsesigned_helper<long>();
917  parsesigned_helper<long long>();
918 }
919 
921 static void test_ioblock1()
922 try {
923  const char* tmp_file = ".unittest_ioutils1";
924  int fd = -1;
925  try {
926  constexpr int BLOCK_SIZE = 1024;
927 
928  fd = io_open_block_wr(tmp_file, true);
929  TEST_REL(fd, >=, 0);
930 
931  string buf(BLOCK_SIZE, 'x');
932  string out;
933 
934  // ZFS default blocksize is 128K so we need to write at least that far
935  // into the file to be able to successfully detect support for sparse
936  // files below. We won't detect sparse file support if the blocksize
937  // is larger, but that's not a problem.
938  io_write_block(fd, buf.data(), BLOCK_SIZE, 128);
939  out.resize(BLOCK_SIZE);
940  io_read_block(fd, &out[0], BLOCK_SIZE, 128);
941  TEST(buf == out);
942 
943  // Call io_sync() and check it claims to work. Checking it actually has
944  // any effect is much harder to do.
945  TEST(io_sync(fd));
946 
947  io_write_block(fd, buf.data(), BLOCK_SIZE, 129);
948  out.resize(BLOCK_SIZE);
949  io_read_block(fd, &out[0], BLOCK_SIZE, 129);
950  TEST(buf == out);
951 
952  // Call io_full_sync() and check it claims to work. Checking it actually
953  // has any effect is much harder to do.
954  TEST(io_full_sync(fd));
955 
956  if constexpr(sizeof(off_t) <= 4) {
957  SKIP_TEST("Skipping rest of testcase - no Large File Support");
958  }
959 
960 #ifdef SEEK_HOLE
961  struct stat statbuf;
962  TEST(fstat(fd, &statbuf) == 0);
963 
964  off_t hole = lseek(fd, 0, SEEK_HOLE);
965  if (hole < 0) {
966  SKIP_TEST("Skipping rest of testcase - SEEK_HOLE failed");
967  }
968  if (hole >= statbuf.st_size) {
969  SKIP_TEST("Skipping rest of testcase - sparse file support not "
970  "detected");
971  }
972 
973  // Write a block at an offset a little above 4GB and check that we wrote
974  // the specified block by checking the filesize. This should catch bugs
975  // which truncate the offset used.
976  constexpr off_t high_offset = off_t(0x100000000 + BLOCK_SIZE);
977  constexpr off_t high_block = high_offset / BLOCK_SIZE;
978  try {
979  io_write_block(fd, buf.data(), BLOCK_SIZE, high_block);
980  } catch (const Xapian::DatabaseError& e) {
981  if (e.get_error_string() == errno_to_string(EFBIG))
982  SKIP_TEST("Skipping rest of testcase - FS doesn't allow a > 4GB "
983  "file");
984  throw;
985  }
986  TEST(fstat(fd, &statbuf) == 0);
987  TEST_EQUAL(statbuf.st_size, high_offset + BLOCK_SIZE);
988 
989  close(fd);
990 
991  fd = io_open_block_rd(tmp_file);
992 
993  // We can't easily test that io_readahead_block() actually does anything if
994  // it returns true, but we can at least call it to check it doesn't crash.
995  (void)io_readahead_block(fd, BLOCK_SIZE, high_block);
996 
997  // Check we can read back the same data we wrote.
998  io_read_block(fd, &out[0], BLOCK_SIZE, high_block);
999  TEST(buf == out);
1000 
1001  close(fd);
1002  fd = -1;
1003  io_unlink(tmp_file);
1004 #else
1005  SKIP_TEST("Skipping rest of testcase - SEEK_HOLE not supported");
1006 #endif
1007  } catch (...) {
1008  close(fd);
1009  io_unlink(tmp_file);
1010  throw;
1011  }
1012 } catch (const Xapian::Error& e) {
1013  // Translate Xapian::Error exceptions to std::string exceptions which
1014  // utestsuite can catch.
1015  throw e.get_description();
1016 }
1017 
1019  Xapian::Vec<int> v_int;
1020  Xapian::Vec<double> v_double;
1021  Xapian::Vec<char> v_char;
1022  Xapian::Vec<const char*> v_cstring;
1023  for (int i = 0; i < 100; ++i) {
1024  v_int.push_back(i);
1025  v_double.push_back(double(i));
1026  v_char.push_back(char(i & 0xff));
1027  v_cstring.push_back("string");
1028  }
1029 }
1030 
1031 DEFINE_TESTCASE(vecdeleter1) {
1032  Xapian::VecUniquePtr<int> v_unique_int;
1033  struct U { int x; };
1034  Xapian::VecUniquePtr<U> v_unique_u;
1035  for (int i = 0; i < 100; ++i) {
1036  v_unique_int.push_back(new int(42));
1037  v_unique_u.push_back(new U());
1038  }
1039 }
1040 
1041 static const test_desc tests[] = {
1042  TESTCASE(simple_exceptions_work1),
1043  TESTCASE(class_exceptions_work1),
1044  TESTCASE(resolverelativepath1),
1045  TESTCASE(serialisedouble1),
1046  TESTCASE(packuint1),
1047  TESTCASE(packstring1),
1048  TESTCASE(packstring2),
1049 #ifdef XAPIAN_HAS_REMOTE_BACKEND
1050  TESTCASE(serialiseerror1),
1051 #endif
1052  TESTCASE(sortableserialise1),
1053  TESTCASE(tostring1),
1054  TESTCASE(strbool1),
1055  TESTCASE(closefrom1),
1056  TESTCASE(shard1),
1057  TESTCASE(uuid1),
1058  TESTCASE(movesupport1),
1059  TESTCASE(addoverflows1),
1060  TESTCASE(suboverflows1),
1061  TESTCASE(muloverflows1),
1062  TESTCASE(parseunsigned1),
1063  TESTCASE(parsesigned1),
1064  TESTCASE(ioblock1),
1065  TESTCASE(vec1),
1066  TESTCASE(vecdeleter1),
1068 };
1069 
1070 int main(int argc, char **argv)
1071 try {
1072  test_driver::parse_command_line(argc, argv);
1073  return test_driver::run(tests);
1074 } catch (const char * e) {
1075  cout << e << '\n';
1076  return 1;
1077 }
#define BLOCK_SIZE
Definition: unittest.cc:650
int get_x() const
Definition: unittest.cc:655
A(int x_)
Definition: unittest.cc:653
Definition: unittest.cc:660
B(int x_, bool &alive_)
Definition: unittest.cc:664
B * release()
Definition: unittest.cc:676
int get_x() const
Definition: unittest.cc:672
~B()
Definition: unittest.cc:668
bool & alive
Definition: unittest.cc:662
Definition: uuids.h:28
void generate()
Definition: uuids.cc:63
bool is_null() const
Definition: uuids.h:50
static constexpr unsigned BINARY_SIZE
The size of a UUID in bytes.
Definition: uuids.h:31
std::string to_string() const
Definition: uuids.cc:120
void clear()
Definition: uuids.h:45
void parse(const char *in)
Definition: uuids.cc:111
const char * data() const
Definition: uuids.h:60
DatabaseError indicates some sort of database related error.
Definition: error.h:355
DatabaseOpeningError indicates failure to open a database.
Definition: error.h:569
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:41
const char * get_error_string() const
Returns any system error string associated with this exception.
Definition: error.cc:50
std::string get_description() const
Return a string describing this object.
Definition: error.cc:93
Base class for objects managed by intrusive_ptr.
Definition: intrusive_ptr.h:50
A normally non-NULL smart pointer using intrusive reference counting.
A smart pointer that uses intrusive reference counting.
Definition: intrusive_ptr.h:83
Base class for objects managed by opt_intrusive_ptr.
A smart pointer that optionally uses intrusive reference counting.
Suitable for "simple" type T.
Definition: smallvector.h:62
void push_back(T elt)
Definition: smallvector.h:190
static void parse_command_line(int argc, char **argv)
Parse the command line arguments.
Definition: testsuite.cc:866
static int run(const test_desc *tests)
Definition: testsuite.cc:955
PositionList * p
void errno_to_string(int e, string &s)
int close(FD &fd)
Definition: fd.h:63
void resolve_relative_path(string &path, string_view base)
Resolve path relative to base.
Definition: fileutils.cc:105
void io_read_block(int fd, char *p, size_t n, off_t b, off_t o)
Read block b size n bytes into buffer p from file descriptor fd, offset o.
Definition: io_utils.cc:432
int io_open_block_wr(const char *filename, bool anew)
Open a block-based file for writing.
Definition: io_utils.cc:192
bool io_unlink(const std::string &filename)
Delete a file.
Definition: io_utils.cc:56
void io_write_block(int fd, const char *p, size_t n, off_t b, off_t o)
Write block b size n bytes from buffer p to file descriptor fd, offset o.
Definition: io_utils.cc:507
bool io_sync(int fd)
Ensure all data previously written to file descriptor fd has been written to disk.
Definition: io_utils.h:107
bool io_full_sync(int fd)
Definition: io_utils.h:122
bool io_readahead_block(int, size_t, off_t, off_t=0)
Readahead block b size n bytes from file descriptor fd.
Definition: io_utils.h:190
int io_open_block_rd(const char *filename)
Open a block-based file for reading.
Definition: io_utils.h:38
Xapian::doccount shard_number(Xapian::docid did, Xapian::doccount n_shards)
Convert docid in the multi-db to shard number.
Definition: multi.h:49
Xapian::docid shard_docid(Xapian::docid did, Xapian::doccount n_shards)
Convert docid in the multi-db to the docid in the shard.
Definition: multi.h:35
Xapian::docid unshard(Xapian::docid shard_did, Xapian::doccount shard, Xapian::doccount n_shards)
Convert shard number and shard docid to docid in multi-db.
Definition: multi.h:64
string str(int value)
Convert int to std::string.
Definition: str.cc:91
void closefrom(int fd)
Definition: closefrom.cc:91
std::string sortable_serialise(double value)
Convert a floating point number to a string, preserving sort order.
Definition: queryparser.h:1229
double sortable_unserialise(std::string_view serialised) noexcept
Convert a string encoded using sortable_serialise back to a floating point number.
unsigned XAPIAN_DOCID_BASE_TYPE doccount
A count of documents.
Definition: types.h:37
unsigned XAPIAN_DOCID_BASE_TYPE docid
A unique identifier for a document.
Definition: types.h:51
std::enable_if_t< std::is_unsigned_v< T1 > &&std::is_unsigned_v< T2 > &&std::is_unsigned_v< R >, bool > sub_overflows(T1 a, T2 b, R &res)
Subtraction with overflow checking.
Definition: overflow.h:125
std::enable_if_t< std::is_unsigned_v< T1 > &&std::is_unsigned_v< T2 > &&std::is_unsigned_v< R >, bool > add_overflows(T1 a, T2 b, R &res)
Addition with overflow checking.
Definition: overflow.h:58
std::enable_if_t< std::is_unsigned_v< T1 > &&std::is_unsigned_v< T2 > &&std::is_unsigned_v< R >, bool > mul_overflows(T1 a, T2 b, R &res)
Multiplication with overflow checking.
Definition: overflow.h:188
bool unpack_string(const char **p, const char *end, std::string &result)
Decode a std::string from a string.
Definition: pack.h:468
bool unpack_uint(const char **p, const char *end, U *result)
Decode an unsigned integer from a string.
Definition: pack.h:346
void pack_uint(std::string &s, U value)
Append an encoded unsigned integer to a string.
Definition: pack.h:315
void pack_string(std::string &s, std::string_view value)
Append an encoded std::string to a string.
Definition: pack.h:442
void pack_string_empty(std::string &s)
Append an empty encoded std::string to a string.
Definition: pack.h:456
bool parse_signed(const char *p, T &res)
Definition: parseint.h:44
bool parse_unsigned(const char *p, T &res)
Definition: parseint.h:29
<unistd.h>, but with compat.
string serialise_double(double v)
Serialise a double to a string.
double unserialise_double(const char **p, const char *end)
Unserialise a double serialised by serialise_double.
void unserialise_error(const string &serialised_error, const string &prefix, const string &new_context)
Unserialise a Xapian::Error object and throw it.
string serialise_error(const Xapian::Error &e)
Serialise a Xapian::Error object to a string.
Structure holding a description of a test.
Definition: testsuite.h:74
#define END_OF_TESTCASES
Definition: testmacros.h:32
#define TESTCASE(T)
Definition: testmacros.h:31
#define TEST_REL(A, REL, B)
Test a relation holds,e.g. TEST_REL(a,>,b);.
Definition: testmacros.h:35
std::ostringstream tout
The debug printing stream.
Definition: testsuite.cc:104
a generic test suite engine
#define SKIP_TEST(MSG)
Skip the current testcase with message MSG.
Definition: testsuite.h:71
#define TEST_EQUAL(a, b)
Test for equality of two things.
Definition: testsuite.h:276
#define TEST_STRINGS_EQUAL(a, b)
Test for equality of two strings.
Definition: testsuite.h:285
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:273
#define TEST_NOT_EQUAL(a, b)
Test for non-equality of two things.
Definition: testsuite.h:303
#define TEST_AND_EXPLAIN(a, b)
Test a condition, and display the test with an extra explanation if the condition fails.
Definition: testsuite.h:265
static void test_movesupport1()
Definition: unittest.cc:682
static void test_suboverflows1()
Definition: unittest.cc:801
static void test_packstring2()
Definition: unittest.cc:334
void description_append(std::string &desc, std::string_view s)
Definition: unittest.cc:105
static void tostring_helper()
Definition: unittest.cc:468
DEFINE_TESTCASE(simple_exceptions_work1)
Definition: unittest.cc:110
static void test_addoverflows1()
Definition: unittest.cc:748
static void parsesigned_helper()
Definition: unittest.cc:874
int main(int argc, char **argv)
Definition: unittest.cc:1070
static void test_muloverflows1()
Definition: unittest.cc:817
static void test_tostring1()
Definition: unittest.cc:484
static void test_parsesigned1()
Definition: unittest.cc:911
static string r_r_p(string a, const string &b)
Definition: unittest.cc:128
static void check_double_serialisation(double u)
Definition: unittest.cc:208
static const test_desc tests[]
Definition: unittest.cc:1041
static void test_sortableserialise1()
Definition: unittest.cc:429
static void test_shard1()
Definition: unittest.cc:555
static void test_packuint1()
Definition: unittest.cc:263
static const double test_sortableserialise_numbers[]
Definition: unittest.cc:380
static void packstring1_helper(size_t len)
Definition: unittest.cc:285
static const char * unittest_assertion_failed
Definition: unittest.cc:39
static void test_closefrom1()
Definition: unittest.cc:531
static void test_uuid1()
Definition: unittest.cc:577
static void test_parseunsigned1()
Definition: unittest.cc:864
static void test_packstring1()
Definition: unittest.cc:323
static void test_strbool1()
Regression test for bug fixed in 1.1.1.
Definition: unittest.cc:525
static void test_ioblock1()
Test working with a block-based file using functions from io_utils.h.
Definition: unittest.cc:921
static void parseunsigned_helper()
Definition: unittest.cc:845