xapian-core  1.4.22
unittest.cc
Go to the documentation of this file.
1 
4 /* Copyright (C) 2006-2022 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, 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 <cctype>
26 #include <cerrno>
27 #include <cfloat>
28 #include <climits>
29 #include <cmath>
30 #include <cstring>
31 #include <iostream>
32 #include <limits>
33 #include <utility>
34 
35 #include "safeunistd.h"
36 
37 #define XAPIAN_UNITTEST
38 static const char * unittest_assertion_failed = NULL;
39 #define UNITTEST_CHECK_EXCEPTION \
40  if (unittest_assertion_failed) { \
41  const char * unittest_assertion_failed_ = unittest_assertion_failed;\
42  unittest_assertion_failed = NULL;\
43  throw unittest_assertion_failed_;\
44  }
45 
46 #include "testsuite.h"
47 
48 using namespace std;
49 
50 #define UNITTEST_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG
51 #define UNITTEST_ASSERT_LOCATION_(LINE,MSG) UNITTEST_ASSERT_LOCATION__(LINE,MSG)
52 #define UNITTEST_ASSERT_LOCATION(MSG) UNITTEST_ASSERT_LOCATION_(__LINE__,MSG)
53 #define UNITTEST_ASSERT_NOTHROW(COND, RET) \
54  do {\
55  if (rare(!(COND))) {\
56  unittest_assertion_failed = UNITTEST_ASSERT_LOCATION(COND);\
57  return RET;\
58  }\
59  } while (false)
60 
61 // Utility code we use:
62 #include "../common/stringutils.h"
63 #include "../common/log2.h"
64 
65 // Simpler version of TEST_EXCEPTION macro.
66 #define TEST_EXCEPTION(TYPE, CODE) \
67  do { \
68  try { \
69  CODE; \
70  UNITTEST_CHECK_EXCEPTION \
71  FAIL_TEST("Expected exception "#TYPE" not thrown"); \
72  } catch (const TYPE &) { \
73  } \
74  } while (0)
75 
76 // Code we're unit testing:
77 #include "../common/closefrom.cc"
78 #include "../common/errno_to_string.cc"
79 #include "../common/fileutils.cc"
80 #include "../common/overflow.h"
81 #include "../common/parseint.h"
82 #include "../common/serialise-double.cc"
83 #include "../common/str.cc"
84 #include "../backends/uuids.cc"
85 #include "../net/length.cc"
86 #include "../net/serialise-error.cc"
87 #include "../api/error.cc"
88 #include "../api/sortable-serialise.cc"
89 
90 // fileutils.cc uses opendir(), etc though not in a function we currently test.
91 #include "../common/msvc_dirent.cc"
92 
93 // The UUID code uses hex_decode().
94 #include "../api/constinfo.cc"
95 
96 // Stub replacement, which doesn't deal with escaping or producing valid UTF-8.
97 // The full implementation needs Xapian::Utf8Iterator and
98 // Xapian::Unicode::append_utf8().
99 void
100 description_append(std::string & desc, const std::string &s)
101 {
102  desc += s;
103 }
104 
105 DEFINE_TESTCASE_(simple_exceptions_work1) {
106  try {
107  throw 42;
108  } catch (int val) {
109  TEST_EQUAL(val, 42);
110  }
111 }
112 
113 class TestException { };
114 
115 DEFINE_TESTCASE_(class_exceptions_work1) {
116  try {
117  throw TestException();
118  } catch (const TestException &) {
119  }
120 }
121 
122 static inline string
123 r_r_p(string a, const string & b)
124 {
125  resolve_relative_path(a, b);
126  return a;
127 }
128 
129 DEFINE_TESTCASE_(resolverelativepath1) {
130  TEST_EQUAL(r_r_p("/abs/o/lute", ""), "/abs/o/lute");
131  TEST_EQUAL(r_r_p("/abs/o/lute", "/"), "/abs/o/lute");
132  TEST_EQUAL(r_r_p("/abs/o/lute", "//"), "/abs/o/lute");
133  TEST_EQUAL(r_r_p("/abs/o/lute", "foo"), "/abs/o/lute");
134  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/"), "/abs/o/lute");
135  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo"), "/abs/o/lute");
136  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/"), "/abs/o/lute");
137  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar"), "/abs/o/lute");
138  TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar/"), "/abs/o/lute");
139  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar"), "/abs/o/lute");
140  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar/"), "/abs/o/lute");
141  TEST_EQUAL(r_r_p("rel/a/tive", ""), "rel/a/tive");
142  TEST_EQUAL(r_r_p("rel/a/tive", "/"), "/rel/a/tive");
143  TEST_EQUAL(r_r_p("rel/a/tive", "//"), "//rel/a/tive");
144  TEST_EQUAL(r_r_p("rel/a/tive", "foo"), "rel/a/tive");
145  TEST_EQUAL(r_r_p("rel/a/tive", "foo/"), "foo/rel/a/tive");
146  TEST_EQUAL(r_r_p("rel/a/tive", "/foo"), "/rel/a/tive");
147  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/"), "/foo/rel/a/tive");
148  TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar"), "foo/rel/a/tive");
149  TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar/"), "foo/bar/rel/a/tive");
150  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar"), "/foo/rel/a/tive");
151  TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar/"), "/foo/bar/rel/a/tive");
152 #ifndef __WIN32__
153  TEST_EQUAL(r_r_p("/abs/o/lute", "/foo\\bar"), "/abs/o/lute");
154  TEST_EQUAL(r_r_p("rel/a/tive", "/foo\\bar"), "/rel/a/tive");
155 #else
156  TEST_EQUAL(r_r_p("\\dos\\path", ""), "\\dos\\path");
157  TEST_EQUAL(r_r_p("\\dos\\path", "/"), "\\dos\\path");
158  TEST_EQUAL(r_r_p("\\dos\\path", "\\"), "\\dos\\path");
159  TEST_EQUAL(r_r_p("\\dos\\path", "c:"), "c:\\dos\\path");
160  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\"), "c:\\dos\\path");
161  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp"), "c:\\dos\\path");
162  TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp\\"), "c:\\dos\\path");
163  TEST_EQUAL(r_r_p("rel/a/tive", "\\"), "\\rel/a/tive");
164  TEST_EQUAL(r_r_p("rel/a/tive", "foo\\"), "foo\\rel/a/tive");
165  TEST_EQUAL(r_r_p("rel\\a\\tive", "/foo/"), "/foo/rel\\a\\tive");
166  TEST_EQUAL(r_r_p("rel/a/tive", "c:/foo/bar"), "c:/foo/rel/a/tive");
167  TEST_EQUAL(r_r_p("rel/a/tive", "c:foo/bar/"), "c:foo/bar/rel/a/tive");
168  TEST_EQUAL(r_r_p("rel/a/tive", "c:"), "c:rel/a/tive");
169  TEST_EQUAL(r_r_p("rel/a/tive", "c:\\"), "c:\\rel/a/tive");
170  TEST_EQUAL(r_r_p("C:rel/a/tive", "c:\\foo\\bar"), "C:\\foo\\rel/a/tive");
171  TEST_EQUAL(r_r_p("C:rel/a/tive", "c:"), "C:rel/a/tive");
172  // This one is impossible to reliably resolve without knowing the current
173  // drive - if it is C:, then the answer is: "C:/abs/o/rel/a/tive"
174  TEST_EQUAL(r_r_p("C:rel/a/tive", "/abs/o/lute"), "C:rel/a/tive");
175  // UNC paths tests:
176  TEST_EQUAL(r_r_p("\\\\SRV\\VOL\\FILE", "/a/b"), "\\\\SRV\\VOL\\FILE");
177  TEST_EQUAL(r_r_p("rel/a/tive", "\\\\SRV\\VOL\\DIR\\FILE"), "\\\\SRV\\VOL\\DIR\\rel/a/tive");
178  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\SRV\\VOL\\FILE"), "\\\\SRV\\VOL/abs/o/lute");
179  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\FILE"), "\\\\S\\V/abs/o/lute");
180  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\"), "\\\\S\\V/abs/o/lute");
181  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V"), "\\\\S\\V/abs/o/lute");
182  TEST_EQUAL(r_r_p("//SRV/VOL/FILE", "/a/b"), "//SRV/VOL/FILE");
183  TEST_EQUAL(r_r_p("rel/a/tive", "//SRV/VOL/DIR/FILE"), "//SRV/VOL/DIR/rel/a/tive");
184  TEST_EQUAL(r_r_p("/abs/o/lute", "//SRV/VOL/FILE"), "//SRV/VOL/abs/o/lute");
185  TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/FILE"), "//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("/abs/o/lute", "//S/V"), "//S/V/abs/o/lute");
188  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\abs\\o\\lute");
189  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
190  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
191  TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
192  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\r\\elativ\\e");
193  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble\\wobble"), "\\\\?\\C:\\wibble\\r\\elativ\\e");
194 #if 0 // Is this a valid testcase? It fails, but isn't relevant to Xapian.
195  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
196 #endif
197  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
198  TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\TMP\\r\\elativ\\e");
199 #endif
200 }
201 
202 static void
204 {
205  // Commonly C++ string implementations keep the string nul-terminated, and
206  // encoded.data() returns a pointer to a buffer including the nul (the same
207  // as encoded.c_str()). This means that valgrind won't catch a read one
208  // past the end of the serialised value, so we copy just the serialised
209  // value into a temporary buffer.
210  char buf[16];
211  string encoded = serialise_double(u);
212  TEST(encoded.size() < sizeof(buf));
213  memcpy(buf, encoded.data(), encoded.size());
214  // Put a NULL pointer either side, to catch incrementing/decrementing at
215  // the wrong level of indirection (regression test for a bug in an
216  // unreleased version).
217  const char * ptr[3] = { NULL, buf, NULL };
218  const char * end = ptr[1] + encoded.size();
219  double v = unserialise_double(&(ptr[1]), end);
220  if (ptr[1] != end || u != v) {
221  cout << u << " -> " << v << ", difference = " << v - u << endl;
222  cout << "FLT_RADIX = " << FLT_RADIX << endl;
223  cout << "DBL_MAX_EXP = " << DBL_MAX_EXP << endl;
224  }
225  TEST_EQUAL(static_cast<const void*>(ptr[1]), static_cast<const void*>(end));
226 }
227 
228 // Check serialisation of doubles.
229 DEFINE_TESTCASE_(serialisedouble1) {
230  static const double test_values[] = {
231  3.14159265,
232  1e57,
233  123.1,
234  257.12,
235  1234.567e123,
236  255.5,
237  256.125,
238  257.03125,
239  };
240 
245  check_double_serialisation(-DBL_MAX);
247  check_double_serialisation(-DBL_MIN);
248 
249  const double *p;
250  for (p = test_values; p < test_values + sizeof(test_values) / sizeof(double); ++p) {
251  double val = *p;
254  check_double_serialisation(1.0 / val);
255  check_double_serialisation(-1.0 / val);
256  }
257 }
258 
259 #ifdef XAPIAN_HAS_REMOTE_BACKEND
260 // Check serialisation of lengths.
262 {
263  size_t n = 0;
264  while (n < 0xff000000) {
265  string s = encode_length(n);
266  const char *p = s.data();
267  const char *p_end = p + s.size();
268  size_t decoded_n;
269  decode_length(&p, p_end, decoded_n);
270  if (n != decoded_n || p != p_end) tout << "[" << s << "]" << endl;
271  TEST_EQUAL(n, decoded_n);
272  TEST_EQUAL(p_end - p, 0);
273  if (n < 5000) {
274  ++n;
275  } else {
276  n += 53643;
277  }
278  }
279 }
280 
281 // Regression test: vetting the remaining buffer length
283 {
284  // Special case tests for 0
285  {
286  string s = encode_length(0);
287  {
288  const char *p = s.data();
289  const char *p_end = p + s.size();
290  size_t r;
291  decode_length_and_check(&p, p_end, r);
292  TEST(r == 0);
293  TEST(p == p_end);
294  }
295  s += 'x';
296  {
297  const char *p = s.data();
298  const char *p_end = p + s.size();
299  size_t r;
300  decode_length_and_check(&p, p_end, r);
301  TEST(r == 0);
302  TEST_EQUAL(p_end - p, 1);
303  }
304  }
305  // Special case tests for 1
306  {
307  string s = encode_length(1);
308  TEST_EXCEPTION(Xapian_NetworkError,
309  const char *p = s.data();
310  const char *p_end = p + s.size();
311  size_t r;
312  decode_length_and_check(&p, p_end, r);
313  (void)r;
314  );
315  s += 'x';
316  {
317  const char *p = s.data();
318  const char *p_end = p + s.size();
319  size_t r;
320  decode_length_and_check(&p, p_end, r);
321  TEST(r == 1);
322  TEST_EQUAL(p_end - p, 1);
323  }
324  s += 'x';
325  {
326  const char *p = s.data();
327  const char *p_end = p + s.size();
328  size_t r;
329  decode_length_and_check(&p, p_end, r);
330  TEST(r == 1);
331  TEST_EQUAL(p_end - p, 2);
332  }
333  }
334  // Nothing magic here, just test a range of odd and even values.
335  for (size_t n = 2; n < 1000; n = (n + 1) * 2 + (n >> 1)) {
336  string s = encode_length(n);
337  TEST_EXCEPTION(Xapian_NetworkError,
338  const char *p = s.data();
339  const char *p_end = p + s.size();
340  size_t r;
341  decode_length_and_check(&p, p_end, r);
342  (void)r;
343  );
344  s.append(n - 1, 'x');
345  TEST_EXCEPTION(Xapian_NetworkError,
346  const char *p = s.data();
347  const char *p_end = p + s.size();
348  size_t r;
349  decode_length_and_check(&p, p_end, r);
350  (void)r;
351  );
352  s += 'x';
353  {
354  const char *p = s.data();
355  const char *p_end = p + s.size();
356  size_t r;
357  decode_length_and_check(&p, p_end, r);
358  TEST(r == n);
359  TEST_EQUAL(size_t(p_end - p), n);
360  }
361  s += 'x';
362  {
363  const char *p = s.data();
364  const char *p_end = p + s.size();
365  size_t r;
366  decode_length_and_check(&p, p_end, r);
367  TEST(r == n);
368  TEST_EQUAL(size_t(p_end - p), n + 1);
369  }
370  }
371 }
372 
373 // Check serialisation of Xapian::Error.
374 static void test_serialiseerror1()
375 {
376  string enoent_msg = errno_to_string(ENOENT);
377  Xapian::DatabaseOpeningError e("Failed to open database", ENOENT);
378  // Regression test for bug in 1.0.0 - it didn't convert errno values for
379  // get_description() if they hadn't already been converted.
380  TEST_STRINGS_EQUAL(e.get_description(), "DatabaseOpeningError: Failed to open database (" + enoent_msg + ")");
381 
382  TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
383 
384  string serialisation = serialise_error(e);
385 
386  // Test if unserialise_error() throws with a flag to avoid the possibility
387  // of an "unreachable code" warning when we get around to marking
388  // unserialise_error() as "noreturn".
389  bool threw = false;
390  try {
391  // unserialise_error throws an exception.
392  unserialise_error(serialisation, "", "");
393  } catch (const Xapian::Error & ecaught) {
394  TEST_STRINGS_EQUAL(ecaught.get_error_string(), enoent_msg);
395  threw = true;
396  }
397  TEST(threw);
398 
399  // Check that the original is still OK.
400  TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
401 
402  // Regression test - in 1.0.0, copying used to duplicate the error_string
403  // pointer, resulting in double calls to free().
405  TEST_STRINGS_EQUAL(ecopy.get_error_string(), enoent_msg);
406 }
407 #endif
408 
409 // Test log2() (which might be our replacement version).
410 static void test_log2()
411 {
412  TEST_EQUAL(log2(1.0), 0.0);
413  TEST_EQUAL(log2(2.0), 1.0);
414  TEST_EQUAL(log2(1024.0), 10.0);
415  TEST_EQUAL(log2(0.5), -1.0);
416 }
417 
418 static const double test_sortableserialise_numbers[] = {
419 #ifdef INFINITY
420  -INFINITY,
421 #endif
422  -HUGE_VAL,
423  -DBL_MAX,
424  -exp2(1022),
425  -1024.5,
426  -3.14159265358979323846,
427  -3,
428  -2,
429  -1.8,
430  -1.1,
431  -1,
432  -0.5,
433  -0.2,
434  -0.1,
435  -0.000005,
436  -0.000002,
437  -0.000001,
438  -exp2(-1023),
439  -exp2(-1024),
440  -exp2(-1074),
441  -DBL_MIN,
442  0,
443  DBL_MIN,
444  exp2(-1074),
445  exp2(-1024),
446  exp2(-1023),
447  0.000001,
448  0.000002,
449  0.000005,
450  0.1,
451  0.2,
452  0.5,
453  1,
454  1.1,
455  1.8,
456  2,
457  3,
458  3.14159265358979323846,
459  1024.5,
460  exp2(1022),
461  DBL_MAX,
462  HUGE_VAL,
463 #ifdef INFINITY
464  INFINITY,
465 #endif
466 
467  64 // Magic number which we stop at.
468 };
469 
470 // Test serialisation and unserialisation of various numbers.
471 // This is actually a public API, but we want extra assertions in the code
472 // while we test it.
474 {
475  double prevnum = 0;
476  string prevstr;
477  bool started = false;
478  for (const double *p = test_sortableserialise_numbers; *p != 64; ++p) {
479  double num = *p;
480  tout << "Number: " << num << '\n';
481  string str = Xapian::sortable_serialise(num);
482  tout << "String: " << str << '\n';
484 
485  if (started) {
486  int num_cmp = 0;
487  if (prevnum < num) {
488  num_cmp = -1;
489  } else if (prevnum > num) {
490  num_cmp = 1;
491  }
492  int str_cmp = 0;
493  if (prevstr < str) {
494  str_cmp = -1;
495  } else if (prevstr > str) {
496  str_cmp = 1;
497  }
498 
499  TEST_AND_EXPLAIN(num_cmp == str_cmp,
500  "Numbers " << prevnum << " and " << num <<
501  " don't sort the same way as their string "
502  "counterparts");
503  }
504 
505  prevnum = num;
506  prevstr = str;
507  started = true;
508  }
509 }
510 
511 template<typename S>
512 inline static void tostring_helper() {
513  const S max_val = numeric_limits<S>::max();
514  const S min_val = numeric_limits<S>::min();
515  tout << "Testing with tostring_helper" << endl;
516  std::ostringstream oss;
517  oss << (long long)max_val;
518  TEST_EQUAL(str(max_val), oss.str());
519  oss.str("");
520  oss.clear();
521 
522  oss << (long long)min_val;
523  TEST_EQUAL(str(min_val), oss.str());
524  oss.str("");
525  oss.clear();
526 }
527 
528 static void test_tostring1()
529 {
530  TEST_EQUAL(str(0), "0");
531  TEST_EQUAL(str(0u), "0");
532  TEST_EQUAL(str(1), "1");
533  TEST_EQUAL(str(1u), "1");
534  TEST_EQUAL(str(9), "9");
535  TEST_EQUAL(str(9u), "9");
536  TEST_EQUAL(str(10), "10");
537  TEST_EQUAL(str(10u), "10");
538  TEST_EQUAL(str(-1), "-1");
539  TEST_EQUAL(str(-9), "-9");
540  TEST_EQUAL(str(-10), "-10");
541  TEST_EQUAL(str(0x7f), "127");
542  TEST_EQUAL(str(-0x80), "-128");
543  TEST_EQUAL(str(0x7fff), "32767");
544  TEST_EQUAL(str(0xffffffff), "4294967295");
545  TEST_EQUAL(str(0x7fffffff), "2147483647");
546  TEST_EQUAL(str(0x7fffffffu), "2147483647");
547  TEST_EQUAL(str(-0x7fffffff), "-2147483647");
548 
549  tostring_helper<char>();
550  tostring_helper<short>();
551  tostring_helper<int>();
552  tostring_helper<long>();
553  tostring_helper<long long>();
554 
555 #ifdef __WIN32__
556  /* Test the 64 bit integer conversion to string.
557  * (Currently only exists for windows.)
558  */
559  TEST_EQUAL(str(10ll), "10");
560  TEST_EQUAL(str(-10ll), "-10");
561  TEST_EQUAL(str(0x200000000ll), "8589934592");
562 // We don't currently have an "unsigned long long" version since it's not required
563 // anywhere in the library.
564 // TEST_EQUAL(str(0x200000000ull), "8589934592");
565 #endif
566 }
567 
569 static void test_strbool1()
570 {
571  TEST_EQUAL(str(true), "1");
572  TEST_EQUAL(str(false), "0");
573 }
574 
575 static void test_closefrom1()
576 {
577 #ifndef __WIN32__
578  // Simple test. Start from 13 as on macOS the FDTracker seems to get fd
579  // 10 and we don't want to collide with that.
580  closefrom(13);
581 
582  // Simple test when there are definitely no fds to close.
583  closefrom(42);
584 
585  // Test passing a really high threshold.
586  closefrom(INT_MAX);
587 
588  // Open some fds and check the expected ones are closed.
589  TEST_EQUAL(dup2(1, 14), 14);
590  TEST_EQUAL(dup2(1, 15), 15);
591  TEST_EQUAL(dup2(1, 18), 18);
592  closefrom(15);
593  TEST_EQUAL(close(14), 0);
594  TEST(close(15) == -1 && errno == EBADF);
595  TEST(close(18) == -1 && errno == EBADF);
596 #endif
597 }
598 
599 static void test_uuid1()
600 {
601  Uuid uuid, uuid2;
602 
603  // Test a generated uuid.
604  uuid.generate();
605  TEST(!uuid.is_null());
606  string str = uuid.to_string();
607  TEST_EQUAL(str.size(), 36);
608  TEST_NOT_EQUAL(str, "00000000-0000-0000-0000-000000000000");
609  // Check UUID pattern is correct and that upper case is not used.
610  for (int i = 0; i != 8; ++i) {
611  unsigned char ch = str[i];
612  TEST(isxdigit(ch));
613  TEST(!isupper(ch));
614  }
615  TEST_EQUAL(str[8], '-');
616  for (int i = 9; i != 13; ++i) {
617  unsigned char ch = str[i];
618  TEST(isxdigit(ch));
619  TEST(!isupper(ch));
620  }
621  TEST_EQUAL(str[13], '-');
622  for (int i = 14; i != 18; ++i) {
623  unsigned char ch = str[i];
624  TEST(isxdigit(ch));
625  TEST(!isupper(ch));
626  }
627  TEST_EQUAL(str[18], '-');
628  for (int i = 19; i != 23; ++i) {
629  unsigned char ch = str[i];
630  TEST(isxdigit(ch));
631  TEST(!isupper(ch));
632  }
633  TEST_EQUAL(str[23], '-');
634  for (int i = 24; i != 36; ++i) {
635  unsigned char ch = str[i];
636  TEST(isxdigit(ch));
637  TEST(!isupper(ch));
638  }
639 
640  uuid2.parse(str);
641  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) == 0);
642 
643  // Check the variant is "10x" and the version between 1 and 5. Mostly this
644  // is to catch bugs where the platform's API for generating UUIDs uses a
645  // different endianness for fields (which we've run into under both WIN32
646  // and FreeBSD).
647  TEST_EQUAL(uuid.data()[8] & 0xc0, 0x80);
648  TEST_REL(str[19], >=, '8');
649  TEST_REL(str[19], <=, 'b');
650  TEST_REL(int(uuid.data()[6]), >=, 0x10);
651  TEST_REL(int(uuid.data()[6]), <=, 0x5f);
652  TEST_REL(str[14], >=, '1');
653  TEST_REL(str[14], <=, '5');
654 
655  // Test generating another uuid gives us a different non-null uuid.
656  uuid2.generate();
657  TEST(!uuid2.is_null());
658  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) != 0);
659 
660  // Test null uuid.
661  uuid.clear();
662  TEST(uuid.is_null());
663  str = uuid.to_string();
664  TEST_EQUAL(str, "00000000-0000-0000-0000-000000000000");
665  uuid2.generate();
666  TEST(!uuid2.is_null());
667  uuid2.parse(str);
668  TEST(memcmp(uuid.data(), uuid2.data(), uuid.BINARY_SIZE) == 0);
669 }
670 
671 // Classes used by movesupport1 test
673  int x = 0;
674  public:
675  explicit A(int x_) : x(x_) {}
676 
677  int get_x() const {
678  return x;
679  }
680 };
681 
683  int x = 0;
684  bool & alive;
685  public:
686  B(int x_, bool & alive_) : x(x_), alive(alive_) {
687  alive = true;
688  }
689 
690  ~B() {
691  alive = false;
692  }
693 
694  int get_x() const {
695  return x;
696  }
697 
698  B * release() {
699  opt_intrusive_base::release();
700  return this;
701  }
702 };
703 
704 static void test_movesupport1()
705 {
706  {
707  // Test move semantics support for intrusive_ptr class
710 
711  // Test move constructor
712  Xapian::Internal::intrusive_ptr<A> p2(std::move(p1));
713  TEST_EQUAL(p2->get_x(), 5);
714  TEST_EQUAL(p1.get(), 0);
715 
716  // Test move assignment
717  p3 = std::move(p2);
718  TEST_EQUAL(p3->get_x(), 5);
719  TEST_EQUAL(p2.get(), 0);
720  }
721 
722  bool alive = false;
723  {
724  // Same test for opt_intrusive_ptr class
725  B * b1 = new B{5, alive};
726  b1->release();
729 
730  // Test move constructor
731  Xapian::Internal::opt_intrusive_ptr<B> p2(std::move(p1));
732  TEST_EQUAL(p2->get_x(), 5);
733  TEST_EQUAL(p1.get(), 0);
734  TEST_EQUAL(alive, true);
735 
736  // Test move assignment
737  p3 = std::move(p2);
738  TEST_EQUAL(p3->get_x(), 5);
739  TEST_EQUAL(p2.get(), 0);
740  TEST_EQUAL(alive, true);
741  }
742  // Test that object b1 has been deleted.
743  TEST_EQUAL(alive, false);
744 }
745 
746 static void test_addoverflows1()
747 {
748  const auto ulong_max = numeric_limits<unsigned long>::max();
749  const auto uint_max = numeric_limits<unsigned int>::max();
750  const auto ushort_max = numeric_limits<unsigned short>::max();
751  const auto uchar_max = numeric_limits<unsigned char>::max();
752 
753  unsigned long res_ulong;
754  unsigned res_uint;
755  unsigned short res_ushort;
756  unsigned char res_uchar;
757 
758  TEST(!add_overflows(0UL, 0UL, res_ulong));
759  TEST_EQUAL(res_ulong, 0);
760  TEST(!add_overflows(0UL, 0UL, res_uint));
761  TEST_EQUAL(res_uint, 0);
762  TEST(!add_overflows(0UL, 0UL, res_ushort));
763  TEST_EQUAL(res_ushort, 0);
764  TEST(!add_overflows(0UL, 0UL, res_uchar));
765  TEST_EQUAL(res_uchar, 0);
766 
767  TEST(add_overflows(ulong_max, 1UL, res_ulong));
768  TEST_EQUAL(res_ulong, 0);
769  TEST(add_overflows(uint_max, 1UL, res_uint));
770  TEST_EQUAL(res_uint, 0);
771  TEST(add_overflows(ushort_max, 1UL, res_ushort));
772  TEST_EQUAL(res_ushort, 0);
773  TEST(add_overflows(uchar_max, 1UL, res_uchar));
774  TEST_EQUAL(res_uchar, 0);
775 
776  TEST(add_overflows(1UL, ulong_max, res_ulong));
777  TEST_EQUAL(res_ulong, 0);
778  TEST(add_overflows(1UL, uint_max, res_uint));
779  TEST_EQUAL(res_uint, 0);
780  TEST(add_overflows(1UL, ushort_max, res_ushort));
781  TEST_EQUAL(res_ushort, 0);
782  TEST(add_overflows(1UL, uchar_max, res_uchar));
783  TEST_EQUAL(res_uchar, 0);
784 
785  TEST(add_overflows(ulong_max, ulong_max, res_ulong));
786  TEST_EQUAL(res_ulong, ulong_max - 1UL);
787  TEST(add_overflows(uint_max, uint_max, res_uint));
788  TEST_EQUAL(res_uint, uint_max - 1UL);
789  TEST(add_overflows(ushort_max, ushort_max, res_ushort));
790  TEST_EQUAL(res_ushort, ushort_max - 1UL);
791  TEST(add_overflows(uchar_max, uchar_max, res_uchar));
792  TEST_EQUAL(res_uchar, uchar_max - 1UL);
793 
794  res_uchar = 1;
795  TEST(add_overflows(res_uchar, unsigned(uchar_max) + 1U, res_uchar));
796  TEST_EQUAL(res_uchar, 1);
797 }
798 
799 static void test_suboverflows1()
800 {
801  unsigned long res;
802  TEST(!sub_overflows(0UL, 0UL, res));
803  TEST_EQUAL(res, 0);
804 
805  TEST(sub_overflows(0UL, 1UL, res));
806  TEST_EQUAL(res, ULONG_MAX);
807 
808  TEST(sub_overflows(ULONG_MAX - 1UL, ULONG_MAX, res));
809  TEST_EQUAL(res, ULONG_MAX);
810 
811  TEST(sub_overflows(0UL, ULONG_MAX, res));
812  TEST_EQUAL(res, 1);
813 }
814 
815 static void test_muloverflows1()
816 {
817  unsigned long res;
818  TEST(!mul_overflows(0UL, 0UL, res));
819  TEST_EQUAL(res, 0);
820 
821  TEST(!mul_overflows(ULONG_MAX, 0UL, res));
822  TEST_EQUAL(res, 0);
823 
824  TEST(!mul_overflows(0UL, ULONG_MAX, res));
825  TEST_EQUAL(res, 0);
826 
827  TEST(!mul_overflows(ULONG_MAX, 1UL, res));
828  TEST_EQUAL(res, ULONG_MAX);
829 
830  TEST(!mul_overflows(1UL, ULONG_MAX, res));
831  TEST_EQUAL(res, ULONG_MAX);
832 
833  TEST(mul_overflows((ULONG_MAX >> 1UL) + 1UL, 2UL, res));
834  TEST_EQUAL(res, 0);
835 
836  TEST(mul_overflows(2UL, (ULONG_MAX >> 1UL) + 1UL, res));
837  TEST_EQUAL(res, 0);
838 
839  TEST(mul_overflows(ULONG_MAX, ULONG_MAX, res));
840 }
841 
842 template<typename U>
843 inline static void parseunsigned_helper() {
844  U val;
845  const U max_val = numeric_limits<U>::max();
846  tout << "Testing with parseunsigned_helper" << endl;
847  TEST(parse_unsigned("0", val));
848  TEST_EQUAL(val, 0);
849  TEST(parse_unsigned("99", val));
850  TEST_EQUAL(val, 99);
851  TEST(parse_unsigned(str(max_val).c_str(), val));
852  TEST_EQUAL(val, max_val);
853  TEST(!parse_unsigned("", val));
854  TEST(!parse_unsigned("-1", val));
855  TEST(!parse_unsigned("abc", val));
856  TEST(!parse_unsigned("0a", val));
857  // Only test if we can construct a value one larger easily.
858  if (max_val + 1ull != 0)
859  TEST(!parse_unsigned(str(max_val + 1ull).c_str(), val));
860 }
861 
862 static void test_parseunsigned1()
863 {
864  parseunsigned_helper<unsigned char>();
865  parseunsigned_helper<unsigned short>();
866  parseunsigned_helper<unsigned>();
867  parseunsigned_helper<unsigned long>();
868  parseunsigned_helper<unsigned long long>();
869 }
870 
871 template<typename S>
872 inline static void parsesigned_helper() {
873  S val;
874  const S max_val = numeric_limits<S>::max();
875  const S min_val = numeric_limits<S>::min();
876  tout << "Testing with parsesigned_helper" << endl;
877  TEST(parse_signed("0", val));
878  TEST_EQUAL(val, 0);
879  TEST(parse_signed("99", val));
880  TEST_EQUAL(val, 99);
881  TEST(parse_signed("-99", val));
882  TEST_EQUAL(val, -99);
883  TEST(parse_signed(str(max_val).c_str(), val));
884  TEST_EQUAL(val, max_val);
885  TEST(parse_signed(str(min_val).c_str(), val));
886  TEST_EQUAL(val, min_val);
887  TEST(!parse_signed("", val));
888  TEST(!parse_signed("abc", val));
889  TEST(!parse_signed("0a", val));
890  TEST(!parse_signed("-99a", val));
891  TEST(!parse_signed("-a99", val));
892  TEST(!parse_signed("--99", val));
893 
894  unsigned long long one_too_large = max_val + 1ull;
895  TEST(!parse_signed(str(one_too_large).c_str(), val));
896 
897  unsigned long long one_too_small_negated = 1ull - min_val;
898  TEST(!parse_signed(("-" + str(one_too_small_negated)).c_str(), val));
899 }
900 
901 static void test_parsesigned1()
902 {
903  parsesigned_helper<signed char>();
904  parsesigned_helper<short>();
905  parsesigned_helper<int>();
906  parsesigned_helper<long>();
907  parsesigned_helper<long long>();
908 }
909 
910 static const test_desc tests[] = {
911  TESTCASE(simple_exceptions_work1),
912  TESTCASE(class_exceptions_work1),
913  TESTCASE(resolverelativepath1),
914  TESTCASE(serialisedouble1),
915 #ifdef XAPIAN_HAS_REMOTE_BACKEND
916  TESTCASE(serialiselength1),
917  TESTCASE(serialiselength2),
918  TESTCASE(serialiseerror1),
919 #endif
920  TESTCASE(log2),
921  TESTCASE(sortableserialise1),
922  TESTCASE(tostring1),
923  TESTCASE(strbool1),
924  TESTCASE(closefrom1),
925  TESTCASE(uuid1),
926  TESTCASE(movesupport1),
927  TESTCASE(addoverflows1),
928  TESTCASE(suboverflows1),
929  TESTCASE(muloverflows1),
930  TESTCASE(parseunsigned1),
931  TESTCASE(parsesigned1),
933 };
934 
935 int main(int argc, char **argv)
936 try {
938  return test_driver::run(tests);
939 } catch (const char * e) {
940  cout << e << endl;
941  return 1;
942 }
int close(FD &fd)
Definition: fd.h:63
~B()
Definition: unittest.cc:690
Definition: unittest.cc:682
static void test_serialiseerror1()
Definition: unittest.cc:374
static void test_serialiselength2()
Definition: unittest.cc:282
std::enable_if< std::is_unsigned< T1 >::value &&std::is_unsigned< T2 >::value &&std::is_unsigned< R >::value, bool >::type add_overflows(T1 a, T2 b, R &res)
Addition with overflow checking.
Definition: overflow.h:58
static void test_parsesigned1()
Definition: unittest.cc:901
static void check_double_serialisation(double u)
Definition: unittest.cc:203
#define TEST(a)
Test a condition, without an additional explanation for failure.
Definition: testsuite.h:275
static void parse_command_line(int argc, char **argv)
Parse the command line arguments.
Definition: testsuite.cc:799
void closefrom(int fd)
Definition: closefrom.cc:89
DatabaseOpeningError indicates failure to open a database.
Definition: error.h:581
static void parseunsigned_helper()
Definition: unittest.cc:843
#define TEST_AND_EXPLAIN(a, b)
Test a condition, and display the test with an extra explanation if the condition fails...
Definition: testsuite.h:267
static void test_suboverflows1()
Definition: unittest.cc:799
a generic test suite engine
static void test_uuid1()
Definition: unittest.cc:599
STL namespace.
string serialise_error(const Xapian::Error &e)
Serialise a Xapian::Error object to a string.
std::string sortable_serialise(double value)
Convert a floating point number to a string, preserving sort order.
Definition: queryparser.h:1347
Definition: unittest.cc:672
std::string encode_length(T len)
Encode a length as a variable-length string.
Definition: length.h:36
static string r_r_p(string a, const string &b)
Definition: unittest.cc:123
int get_x() const
Definition: unittest.cc:694
static void parsesigned_helper()
Definition: unittest.cc:872
static void test_serialiselength1()
Definition: unittest.cc:261
void unserialise_error(const string &serialised_error, const string &prefix, const string &new_context)
Unserialise a Xapian::Error object and throw it.
#define TEST_REL(A, REL, B)
Test a relation holds,e.g. TEST_REL(a,>,b);.
Definition: testmacros.h:32
static const char * unittest_assertion_failed
Definition: unittest.cc:38
#define TEST_NOT_EQUAL(a, b)
Test for non-equality of two things.
Definition: testsuite.h:305
double unserialise_double(const char **p, const char *end)
Unserialise a double serialised by serialise_double.
void description_append(std::string &desc, const std::string &s)
Definition: unittest.cc:100
std::ostringstream tout
The debug printing stream.
Definition: testsuite.cc:103
void errno_to_string(int e, string &s)
A(int x_)
Definition: unittest.cc:675
#define TEST_EXCEPTION(TYPE, CODE)
Definition: unittest.cc:66
B(int x_, bool &alive_)
Definition: unittest.cc:686
static void test_parseunsigned1()
Definition: unittest.cc:862
void clear()
Definition: uuids.h:45
static void test_tostring1()
Definition: unittest.cc:528
#define END_OF_TESTCASES
Definition: testmacros.h:29
string str(int value)
Convert int to std::string.
Definition: str.cc:90
std::string to_string() const
Definition: uuids.cc:120
static void test_sortableserialise1()
Definition: unittest.cc:473
B * release()
Definition: unittest.cc:698
void parse(const char *in)
Definition: uuids.cc:111
Base class for objects managed by intrusive_ptr.
Definition: intrusive_ptr.h:49
Base class for objects managed by opt_intrusive_ptr.
static void test_muloverflows1()
Definition: unittest.cc:815
double sortable_unserialise(const std::string &serialised)
Convert a string encoded using sortable_serialise back to a floating point number.
std::string get_description() const
Return a string describing this object.
Definition: error.cc:93
static void test_closefrom1()
Definition: unittest.cc:575
void resolve_relative_path(string &path, const string &base)
Resolve path relative to base.
Definition: fileutils.cc:105
double log2(double x)
Definition: log2.h:31
std::string serialise_double(double v)
Serialise a double to a string.
void decode_length_and_check(const char **p, const char *end, unsigned &out)
Decode a length encoded by encode_length.
Definition: length.cc:112
static void test_movesupport1()
Definition: unittest.cc:704
bool is_null() const
Definition: uuids.h:50
#define TESTCASE(T)
Definition: testmacros.h:28
int get_x() const
Definition: unittest.cc:677
static void tostring_helper()
Definition: unittest.cc:512
const char * get_error_string() const
Returns any system error string associated with this exception.
Definition: error.cc:50
static constexpr unsigned BINARY_SIZE
The size of a UUID in bytes.
Definition: uuids.h:31
bool parse_signed(const char *p, T &res)
Definition: parseint.h:43
All exceptions thrown by Xapian are subclasses of Xapian::Error.
Definition: error.h:43
static const double test_sortableserialise_numbers[]
Definition: unittest.cc:418
std::enable_if< std::is_unsigned< T1 >::value &&std::is_unsigned< T2 >::value &&std::is_unsigned< R >::value, bool >::type sub_overflows(T1 a, T2 b, R &res)
Subtraction with overflow checking.
Definition: overflow.h:125
#define TEST_STRINGS_EQUAL(a, b)
Test for equality of two strings.
Definition: testsuite.h:287
Definition: uuids.h:28
static void test_strbool1()
Regression test for bug fixed in 1.1.1.
Definition: unittest.cc:569
static int run(const test_desc *tests)
Definition: testsuite.cc:886
std::enable_if< std::is_unsigned< T1 >::value &&std::is_unsigned< T2 >::value &&std::is_unsigned< R >::value, bool >::type mul_overflows(T1 a, T2 b, R &res)
Multiplication with overflow checking.
Definition: overflow.h:188
<unistd.h>, but with compat.
static const test_desc tests[]
Definition: unittest.cc:910
int main(int argc, char **argv)
Definition: unittest.cc:935
static void test_log2()
Definition: unittest.cc:410
static void test_addoverflows1()
Definition: unittest.cc:746
const char * data() const
Definition: uuids.h:60
Structure holding a description of a test.
Definition: testsuite.h:77
bool parse_unsigned(const char *p, T &res)
Definition: parseint.h:28
#define TEST_EQUAL(a, b)
Test for equality of two things.
Definition: testsuite.h:278
A smart pointer that optionally uses intrusive reference counting.
A smart pointer that uses intrusive reference counting.
Definition: intrusive_ptr.h:81
void decode_length(const char **p, const char *end, unsigned &out)
Decode a length encoded by encode_length.
Definition: length.cc:94
bool & alive
Definition: unittest.cc:684
DEFINE_TESTCASE_(simple_exceptions_work1)
Definition: unittest.cc:105
void generate()
Definition: uuids.cc:63