unitest: Add testcase uuid1 to test UUID functions
[xapian.git] / xapian-core / tests / unittest.cc
blob6e890762a685247ddd9458d87b83e5f465a493e8
1 /** @file unittest.cc
2 * @brief Unit tests of non-Xapian-specific internal code.
3 */
4 /* Copyright (C) 2006,2007,2009,2010,2012,2015,2016,2017 Olly Betts
5 * Copyright (C) 2007 Richard Boulton
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.
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.
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
23 #include <config.h>
25 #include <cctype>
26 #include <cfloat>
27 #include <climits>
28 #include <cmath>
29 #include <cstring>
30 #include <iostream>
32 #include "safeunistd.h"
34 #define XAPIAN_UNITTEST
35 static const char * unittest_assertion_failed = NULL;
36 #define UNITTEST_CHECK_EXCEPTION \
37 if (unittest_assertion_failed) { \
38 const char * unittest_assertion_failed_ = unittest_assertion_failed;\
39 unittest_assertion_failed = NULL;\
40 throw unittest_assertion_failed_;\
43 #include "testsuite.h"
45 using namespace std;
47 #define UNITTEST_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG
48 #define UNITTEST_ASSERT_LOCATION_(LINE,MSG) UNITTEST_ASSERT_LOCATION__(LINE,MSG)
49 #define UNITTEST_ASSERT_LOCATION(MSG) UNITTEST_ASSERT_LOCATION_(__LINE__,MSG)
50 #define UNITTEST_ASSERT_NOTHROW(COND, RET) \
51 do {\
52 if (rare(!(COND))) {\
53 unittest_assertion_failed = UNITTEST_ASSERT_LOCATION(COND);\
54 return RET;\
56 } while (false)
58 // Utility code we use:
59 #include "../backends/multi.h"
60 #include "../common/stringutils.h"
61 #include "../common/log2.h"
63 // Simpler version of TEST_EXCEPTION macro.
64 #define TEST_EXCEPTION(TYPE, CODE) \
65 do { \
66 try { \
67 CODE; \
68 UNITTEST_CHECK_EXCEPTION \
69 FAIL_TEST("Expected exception "#TYPE" not thrown"); \
70 } catch (const TYPE &) { \
71 } \
72 } while (0)
74 // Code we're unit testing:
75 #include "../common/closefrom.cc"
76 #include "../common/errno_to_string.cc"
77 #include "../common/fileutils.cc"
78 #include "../common/serialise-double.cc"
79 #include "../common/str.cc"
80 #include "../common/safeuuid.h"
81 #ifdef USE_WIN32_UUID_API
82 # include "../common/win32_uuid.cc"
83 #elif defined HAVE_UUID_UUID_H
84 // Implementation in library.
85 #elif defined HAVE_UUID_H
86 // Implementation in library.
87 #elif defined USE_PROC_FOR_UUID
88 # include "../common/proc_uuid.cc"
89 #endif
90 #include "../net/length.cc"
91 #include "../net/serialise-error.cc"
92 #include "../api/error.cc"
93 #include "../api/sortable-serialise.cc"
95 // fileutils.cc uses opendir(), etc though not in a function we currently test.
96 #include "../common/msvc_dirent.cc"
98 // Stub replacement, which doesn't deal with escaping or producing valid UTF-8.
99 // The full implementation needs Xapian::Utf8Iterator and
100 // Xapian::Unicode::append_utf8().
101 void
102 description_append(std::string & desc, const std::string &s)
104 desc += s;
107 DEFINE_TESTCASE_(simple_exceptions_work1) {
108 try {
109 throw 42;
110 } catch (int val) {
111 TEST_EQUAL(val, 42);
112 return true;
114 return false;
117 class TestException { };
119 DEFINE_TESTCASE_(class_exceptions_work1) {
120 try {
121 throw TestException();
122 } catch (const TestException &) {
123 return true;
125 return false;
128 inline string
129 r_r_p(string a, const string & b)
131 resolve_relative_path(a, b);
132 return a;
135 DEFINE_TESTCASE_(resolverelativepath1) {
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", "//"), "/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/"), "/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("/abs/o/lute", "/foo/bar/"), "/abs/o/lute");
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", "//"), "//rel/a/tive");
150 TEST_EQUAL(r_r_p("rel/a/tive", "foo"), "rel/a/tive");
151 TEST_EQUAL(r_r_p("rel/a/tive", "foo/"), "foo/rel/a/tive");
152 TEST_EQUAL(r_r_p("rel/a/tive", "/foo"), "/rel/a/tive");
153 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/"), "/foo/rel/a/tive");
154 TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar"), "foo/rel/a/tive");
155 TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar/"), "foo/bar/rel/a/tive");
156 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar"), "/foo/rel/a/tive");
157 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar/"), "/foo/bar/rel/a/tive");
158 #ifndef __WIN32__
159 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo\\bar"), "/abs/o/lute");
160 TEST_EQUAL(r_r_p("rel/a/tive", "/foo\\bar"), "/rel/a/tive");
161 #else
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", "\\"), "\\dos\\path");
165 TEST_EQUAL(r_r_p("\\dos\\path", "c:"), "c:\\dos\\path");
166 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\"), "c:\\dos\\path");
167 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp"), "c:\\dos\\path");
168 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp\\"), "c:\\dos\\path");
169 TEST_EQUAL(r_r_p("rel/a/tive", "\\"), "\\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", "/foo/"), "/foo/rel\\a\\tive");
172 TEST_EQUAL(r_r_p("rel/a/tive", "c:/foo/bar"), "c:/foo/rel/a/tive");
173 TEST_EQUAL(r_r_p("rel/a/tive", "c:foo/bar/"), "c:foo/bar/rel/a/tive");
174 TEST_EQUAL(r_r_p("rel/a/tive", "c:"), "c:rel/a/tive");
175 TEST_EQUAL(r_r_p("rel/a/tive", "c:\\"), "c:\\rel/a/tive");
176 TEST_EQUAL(r_r_p("C:rel/a/tive", "c:\\foo\\bar"), "C:\\foo\\rel/a/tive");
177 TEST_EQUAL(r_r_p("C:rel/a/tive", "c:"), "C:rel/a/tive");
178 // This one is impossible to reliably resolve without knowing the current
179 // drive - if it is C:, then the answer is: "C:/abs/o/rel/a/tive"
180 TEST_EQUAL(r_r_p("C:rel/a/tive", "/abs/o/lute"), "C:rel/a/tive");
181 // UNC paths tests:
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("//SRV/VOL/FILE", "/a/b"), "//SRV/VOL/FILE");
189 TEST_EQUAL(r_r_p("rel/a/tive", "//SRV/VOL/DIR/FILE"), "//SRV/VOL/DIR/rel/a/tive");
190 TEST_EQUAL(r_r_p("/abs/o/lute", "//SRV/VOL/FILE"), "//SRV/VOL/abs/o/lute");
191 TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/FILE"), "//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", "//S/V"), "//S/V/abs/o/lute");
194 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\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\\"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
197 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
198 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\r\\elativ\\e");
199 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble\\wobble"), "\\\\?\\C:\\wibble\\r\\elativ\\e");
200 #if 0 // Is this a valid testcase? It fails, but isn't relevant to Xapian.
201 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
202 #endif
203 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
204 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\TMP\\r\\elativ\\e");
205 #endif
206 return true;
209 static void
210 check_double_serialisation(double u)
212 // Commonly C++ string implementations keep the string nul-terminated, and
213 // encoded.data() returns a pointer to a buffer including the nul (the same
214 // as encoded.c_str()). This means that valgrind won't catch a read one
215 // past the end of the serialised value, so we copy just the serialised
216 // value into a temporary buffer.
217 char buf[16];
218 string encoded = serialise_double(u);
219 TEST(encoded.size() < sizeof(buf));
220 memcpy(buf, encoded.data(), encoded.size());
221 // Put a NULL pointer either side, to catch incrementing/decrementing at
222 // the wrong level of indirection (regression test for a bug in an
223 // unreleased version).
224 const char * ptr[3] = { NULL, buf, NULL };
225 const char * end = ptr[1] + encoded.size();
226 double v = unserialise_double(&(ptr[1]), end);
227 if (ptr[1] != end || u != v) {
228 cout << u << " -> " << v << ", difference = " << v - u << endl;
229 cout << "FLT_RADIX = " << FLT_RADIX << endl;
230 cout << "DBL_MAX_EXP = " << DBL_MAX_EXP << endl;
232 TEST_EQUAL(static_cast<const void*>(ptr[1]), static_cast<const void*>(end));
235 // Check serialisation of doubles.
236 DEFINE_TESTCASE_(serialisedouble1) {
237 static const double test_values[] = {
238 3.14159265,
239 1e57,
240 123.1,
241 257.12,
242 1234.567e123,
243 255.5,
244 256.125,
245 257.03125,
248 check_double_serialisation(0.0);
249 check_double_serialisation(1.0);
250 check_double_serialisation(-1.0);
251 check_double_serialisation(DBL_MAX);
252 check_double_serialisation(-DBL_MAX);
253 check_double_serialisation(DBL_MIN);
254 check_double_serialisation(-DBL_MIN);
256 const double *p;
257 for (p = test_values; p < test_values + sizeof(test_values) / sizeof(double); ++p) {
258 double val = *p;
259 check_double_serialisation(val);
260 check_double_serialisation(-val);
261 check_double_serialisation(1.0 / val);
262 check_double_serialisation(-1.0 / val);
265 return true;
268 #ifdef XAPIAN_HAS_REMOTE_BACKEND
269 // Check serialisation of lengths.
270 static bool test_serialiselength1()
272 size_t n = 0;
273 while (n < 0xff000000) {
274 string s = encode_length(n);
275 const char *p = s.data();
276 const char *p_end = p + s.size();
277 size_t decoded_n;
278 decode_length(&p, p_end, decoded_n);
279 if (n != decoded_n || p != p_end) tout << "[" << s << "]" << endl;
280 TEST_EQUAL(n, decoded_n);
281 TEST_EQUAL(p_end - p, 0);
282 if (n < 5000) {
283 ++n;
284 } else {
285 n += 53643;
289 return true;
292 // Regression test: vetting the remaining buffer length
293 static bool test_serialiselength2()
295 // Special case tests for 0
297 string s = encode_length(0);
299 const char *p = s.data();
300 const char *p_end = p + s.size();
301 size_t r;
302 decode_length_and_check(&p, p_end, r);
303 TEST(r == 0);
304 TEST(p == p_end);
306 s += 'x';
308 const char *p = s.data();
309 const char *p_end = p + s.size();
310 size_t r;
311 decode_length_and_check(&p, p_end, r);
312 TEST(r == 0);
313 TEST_EQUAL(p_end - p, 1);
316 // Special case tests for 1
318 string s = encode_length(1);
319 TEST_EXCEPTION(Xapian_NetworkError,
320 const char *p = s.data();
321 const char *p_end = p + s.size();
322 size_t r;
323 decode_length_and_check(&p, p_end, r);
324 (void)r;
326 s += 'x';
328 const char *p = s.data();
329 const char *p_end = p + s.size();
330 size_t r;
331 decode_length_and_check(&p, p_end, r);
332 TEST(r == 1);
333 TEST_EQUAL(p_end - p, 1);
335 s += 'x';
337 const char *p = s.data();
338 const char *p_end = p + s.size();
339 size_t r;
340 decode_length_and_check(&p, p_end, r);
341 TEST(r == 1);
342 TEST_EQUAL(p_end - p, 2);
345 // Nothing magic here, just test a range of odd and even values.
346 for (size_t n = 2; n < 1000; n = (n + 1) * 2 + (n >> 1)) {
347 string s = encode_length(n);
348 TEST_EXCEPTION(Xapian_NetworkError,
349 const char *p = s.data();
350 const char *p_end = p + s.size();
351 size_t r;
352 decode_length_and_check(&p, p_end, r);
353 (void)r;
355 s.append(n - 1, 'x');
356 TEST_EXCEPTION(Xapian_NetworkError,
357 const char *p = s.data();
358 const char *p_end = p + s.size();
359 size_t r;
360 decode_length_and_check(&p, p_end, r);
361 (void)r;
363 s += 'x';
365 const char *p = s.data();
366 const char *p_end = p + s.size();
367 size_t r;
368 decode_length_and_check(&p, p_end, r);
369 TEST(r == n);
370 TEST_EQUAL(size_t(p_end - p), n);
372 s += 'x';
374 const char *p = s.data();
375 const char *p_end = p + s.size();
376 size_t r;
377 decode_length_and_check(&p, p_end, r);
378 TEST(r == n);
379 TEST_EQUAL(size_t(p_end - p), n + 1);
383 return true;
386 // Check serialisation of Xapian::Error.
387 static bool test_serialiseerror1()
389 string enoent_msg(strerror(ENOENT));
390 Xapian::DatabaseOpeningError e("Failed to open database", ENOENT);
391 // Regression test for bug in 1.0.0 - it didn't convert errno values for
392 // get_description() if they hadn't already been converted.
393 TEST_STRINGS_EQUAL(e.get_description(), "DatabaseOpeningError: Failed to open database (" + enoent_msg + ")");
395 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
397 string serialisation = serialise_error(e);
399 // Test if unserialise_error() throws with a flag to avoid the possibility
400 // of an "unreachable code" warning when we get around to marking
401 // unserialise_error() as "noreturn".
402 bool threw = false;
403 try {
404 // unserialise_error throws an exception.
405 unserialise_error(serialisation, "", "");
406 } catch (const Xapian::Error & ecaught) {
407 TEST_STRINGS_EQUAL(ecaught.get_error_string(), enoent_msg);
408 threw = true;
410 TEST(threw);
412 // Check that the original is still OK.
413 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
415 // Regression test - in 1.0.0, copying used to duplicate the error_string
416 // pointer, resulting in double calls to free().
417 Xapian::DatabaseOpeningError ecopy(e);
418 TEST_STRINGS_EQUAL(ecopy.get_error_string(), enoent_msg);
420 return true;
422 #endif
424 // Test log2() (which might be our replacement version).
425 static bool test_log2()
427 TEST_EQUAL(log2(1.0), 0.0);
428 TEST_EQUAL(log2(2.0), 1.0);
429 TEST_EQUAL(log2(1024.0), 10.0);
430 TEST_EQUAL(log2(0.5), -1.0);
431 return true;
434 static const double test_sortableserialise_numbers[] = {
435 #ifdef INFINITY
436 -INFINITY,
437 #endif
438 -HUGE_VAL,
439 -DBL_MAX,
440 -exp2(1022),
441 -1024.5,
442 -3.14159265358979323846,
445 -1.8,
446 -1.1,
448 -0.5,
449 -0.2,
450 -0.1,
451 -0.000005,
452 -0.000002,
453 -0.000001,
454 -exp2(-1023),
455 -exp2(-1024),
456 -exp2(-1074),
457 -DBL_MIN,
459 DBL_MIN,
460 exp2(-1074),
461 exp2(-1024),
462 exp2(-1023),
463 0.000001,
464 0.000002,
465 0.000005,
466 0.1,
467 0.2,
468 0.5,
470 1.1,
471 1.8,
474 3.14159265358979323846,
475 1024.5,
476 exp2(1022),
477 DBL_MAX,
478 HUGE_VAL,
479 #ifdef INFINITY
480 INFINITY,
481 #endif
483 64 // Magic number which we stop at.
486 // Test serialisation and unserialisation of various numbers.
487 // This is actually a public API, but we want extra assertions in the code
488 // while we test it.
489 static bool test_sortableserialise1()
491 double prevnum = 0;
492 string prevstr;
493 bool started = false;
494 for (const double *p = test_sortableserialise_numbers; *p != 64; ++p) {
495 double num = *p;
496 tout << "Number: " << num << '\n';
497 string str = Xapian::sortable_serialise(num);
498 tout << "String: " << str << '\n';
499 TEST_EQUAL(Xapian::sortable_unserialise(str), num);
501 if (started) {
502 int num_cmp = 0;
503 if (prevnum < num) {
504 num_cmp = -1;
505 } else if (prevnum > num) {
506 num_cmp = 1;
508 int str_cmp = 0;
509 if (prevstr < str) {
510 str_cmp = -1;
511 } else if (prevstr > str) {
512 str_cmp = 1;
515 TEST_AND_EXPLAIN(num_cmp == str_cmp,
516 "Numbers " << prevnum << " and " << num <<
517 " don't sort the same way as their string "
518 "counterparts");
521 prevnum = num;
522 prevstr = str;
523 started = true;
525 return true;
528 static bool test_tostring1()
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(0xffffffff), "4294967295");
542 TEST_EQUAL(str(0x7fffffff), "2147483647");
543 TEST_EQUAL(str(0x7fffffffu), "2147483647");
544 TEST_EQUAL(str(-0x7fffffff), "-2147483647");
546 #ifdef __WIN32__
547 /* Test the 64 bit integer conversion to string.
548 * (Currently only exists for windows.)
550 TEST_EQUAL(str(10ll), "10");
551 TEST_EQUAL(str(-10ll), "-10");
552 TEST_EQUAL(str(0x200000000ll), "8589934592");
553 // We don't currently have an "unsigned long long" version since it's not required
554 // anywhere in the library.
555 // TEST_EQUAL(str(0x200000000ull), "8589934592");
556 #endif
558 return true;
561 /// Regression test for bug fixed in 1.1.1.
562 static bool test_strbool1()
564 TEST_EQUAL(str(true), "1");
565 TEST_EQUAL(str(false), "0");
566 return true;
569 static bool test_closefrom1()
571 #ifndef __WIN32__
572 // Simple test.
573 closefrom(8);
575 // Simple test when there are definitely no fds to close.
576 closefrom(42);
578 // Test passing a really high threshold.
579 closefrom(INT_MAX);
581 // Open some fds and check the expected ones are closed.
582 TEST_EQUAL(dup2(1, 14), 14);
583 TEST_EQUAL(dup2(1, 15), 15);
584 TEST_EQUAL(dup2(1, 18), 18);
585 closefrom(15);
586 TEST_EQUAL(close(14), 0);
587 TEST(close(15) == -1 && errno == EBADF);
588 TEST(close(18) == -1 && errno == EBADF);
589 #endif
590 return true;
593 static bool test_shard1()
595 for (Xapian::docid did = 1; did != 10; ++did) {
596 for (size_t n = 1; n != 10; ++n) {
597 Xapian::docid s_did = shard_docid(did, n);
598 size_t shard = shard_number(did, n);
599 TEST_EQUAL(s_did, (did - 1) / n + 1);
600 TEST_EQUAL(shard, (did - 1) % n);
601 if (n == 1)
602 TEST_EQUAL(did, s_did);
603 if (did == 1)
604 TEST_EQUAL(s_did, 1);
605 if (s_did == 1)
606 TEST(did <= n);
607 TEST(s_did != 0);
608 TEST(s_did <= did);
609 TEST(shard < n);
610 TEST_EQUAL(did, unshard(s_did, shard, n));
613 return true;
616 static bool test_uuid1()
618 char buf[37];
619 uuid_t uuid, uuid2;
621 // Test null uuid.
622 uuid_clear(uuid);
623 TEST(uuid_is_null(uuid));
624 uuid_unparse_lower(uuid, buf);
625 TEST_EQUAL(buf[36], '\0');
626 TEST_EQUAL(strlen(buf), 36);
627 TEST_EQUAL(string(buf, 36), "00000000-0000-0000-0000-000000000000");
628 memset(uuid2, 0xff, sizeof(uuid));
629 uuid_parse(buf, uuid2);
630 TEST(memcmp(uuid, uuid2, sizeof(uuid)) == 0);
632 // Test a generated uuid.
633 uuid_generate(uuid);
634 TEST(!uuid_is_null(uuid));
635 uuid_unparse_lower(uuid, buf);
636 TEST_EQUAL(buf[36], '\0');
637 TEST_EQUAL(strlen(buf), 36);
638 TEST_NOT_EQUAL(string(buf, 36), "00000000-0000-0000-0000-000000000000");
639 // Check UUID pattern is correct and that upper case is not used.
640 for (int i = 0; i != 8; ++i) {
641 unsigned char ch = buf[i];
642 TEST(isxdigit(ch));
643 TEST(!isupper(ch));
645 TEST_EQUAL(buf[8], '-');
646 for (int i = 9; i != 13; ++i) {
647 unsigned char ch = buf[i];
648 TEST(isxdigit(ch));
649 TEST(!isupper(ch));
651 TEST_EQUAL(buf[13], '-');
652 for (int i = 14; i != 18; ++i) {
653 unsigned char ch = buf[i];
654 TEST(isxdigit(ch));
655 TEST(!isupper(ch));
657 TEST_EQUAL(buf[18], '-');
658 for (int i = 19; i != 23; ++i) {
659 unsigned char ch = buf[i];
660 TEST(isxdigit(ch));
661 TEST(!isupper(ch));
663 TEST_EQUAL(buf[23], '-');
664 for (int i = 24; i != 36; ++i) {
665 unsigned char ch = buf[i];
666 TEST(isxdigit(ch));
667 TEST(!isupper(ch));
669 uuid_parse(buf, uuid2);
670 TEST(memcmp(uuid, uuid2, sizeof(uuid)) == 0);
672 // Test generating another uuid gives us a different non-null uuid.
673 uuid_generate(uuid2);
674 TEST(!uuid_is_null(uuid2));
675 TEST(memcmp(uuid, uuid2, sizeof(uuid)) != 0);
677 return true;
680 static const test_desc tests[] = {
681 TESTCASE(simple_exceptions_work1),
682 TESTCASE(class_exceptions_work1),
683 TESTCASE(resolverelativepath1),
684 TESTCASE(serialisedouble1),
685 #ifdef XAPIAN_HAS_REMOTE_BACKEND
686 TESTCASE(serialiselength1),
687 TESTCASE(serialiselength2),
688 TESTCASE(serialiseerror1),
689 #endif
690 TESTCASE(log2),
691 TESTCASE(sortableserialise1),
692 TESTCASE(tostring1),
693 TESTCASE(strbool1),
694 TESTCASE(closefrom1),
695 TESTCASE(shard1),
696 TESTCASE(uuid1),
697 END_OF_TESTCASES
700 int main(int argc, char **argv)
701 try {
702 test_driver::parse_command_line(argc, argv);
703 return test_driver::run(tests);
704 } catch (const char * e) {
705 cout << e << endl;
706 return 1;