1 /* -*- coding: utf-8 -*-
2  * ----------------------------------------------------------------------
3  * Copyright © 2011-2014, RedJack, LLC.
4  * All rights reserved.
5  *
6  * Please see the COPYING file in this distribution for license details.
7  * ----------------------------------------------------------------------
8  */
9 
10 #include <errno.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include <check.h>
17 
18 #include "libcork/config.h"
19 #include "libcork/core/byte-order.h"
20 #include "libcork/core/error.h"
21 #include "libcork/core/hash.h"
22 #include "libcork/core/id.h"
23 #include "libcork/core/net-addresses.h"
24 #include "libcork/core/timestamp.h"
25 #include "libcork/core/types.h"
26 #include "libcork/core/u128.h"
27 #include "libcork/os/subprocess.h"
28 
29 #include "helpers.h"
30 
31 
32 /*-----------------------------------------------------------------------
33  * Core types
34  */
35 
START_TEST(test_bool)36 START_TEST(test_bool)
37 {
38     bool  value;
39 
40     value = true;
41     fail_unless(value, "Unexpected true value");
42 
43     value = false;
44     fail_if(value, "Unexpected false value");
45 }
46 END_TEST
47 
START_TEST(test_int_types)48 START_TEST(test_int_types)
49 {
50     /*
51      * Make sure we have all of the C99 fixed-size integer types
52      * available.
53      */
54 
55 #define TEST_INT_TYPE(type) \
56     { \
57         type  i = 0; \
58         fail_unless(i == 0, "Unexpected value for " #type); \
59     }
60 
61     TEST_INT_TYPE(int8_t);
62     TEST_INT_TYPE(int16_t);
63     TEST_INT_TYPE(int32_t);
64     TEST_INT_TYPE(int64_t);
65     TEST_INT_TYPE(uint8_t);
66     TEST_INT_TYPE(uint16_t);
67     TEST_INT_TYPE(uint32_t);
68     TEST_INT_TYPE(uint64_t);
69     TEST_INT_TYPE(size_t);
70     TEST_INT_TYPE(ptrdiff_t);
71     TEST_INT_TYPE(intptr_t);
72     TEST_INT_TYPE(uintptr_t);
73 
74 #undef TEST_INT_TYPE
75 }
76 END_TEST
77 
78 
START_TEST(test_int_sizeof)79 START_TEST(test_int_sizeof)
80 {
81     /*
82      * Test that our CORK_SIZEOF_FOO preprocessor macros match the
83      * results of the builtin sizeof operator.
84      */
85 
86 #define TEST_SIZEOF(TYPE, type) \
87     { \
88         fail_unless(CORK_SIZEOF_##TYPE == sizeof(type), \
89                     "Incorrect size for " #type ": got %zu, expected %zu", \
90                     (size_t) CORK_SIZEOF_##TYPE, \
91                     (size_t) sizeof(type)); \
92     }
93 
94     TEST_SIZEOF(SHORT, short)
95     TEST_SIZEOF(SHORT, unsigned short)
96     TEST_SIZEOF(INT, int)
97     TEST_SIZEOF(INT, unsigned int)
98     TEST_SIZEOF(LONG, long)
99     TEST_SIZEOF(LONG, unsigned long)
100     TEST_SIZEOF(POINTER, void *)
101     TEST_SIZEOF(POINTER, int *)
102     TEST_SIZEOF(POINTER, void (*)(void))
103 
104 #undef TEST_SIZEOF
105 }
106 END_TEST
107 
108 
109 /*-----------------------------------------------------------------------
110  * Strings
111  */
112 
113 static void
test_strndup(const char * string,size_t size)114 test_strndup(const char *string, size_t size)
115 {
116     const char  *copy;
117 
118     copy = cork_strndup(string, size);
119     if (memcmp(string, copy, size) != 0) {
120         fail("cork_strndup failed");
121     }
122     cork_strfree(copy);
123 
124     copy = cork_xstrndup(string, size);
125     fail_if(copy == NULL, "cork_xstrndup couldn't allocate copy");
126     if (memcmp(string, copy, size) != 0) {
127         fail("cork_xstrndup failed");
128     }
129     cork_strfree(copy);
130 }
131 
START_TEST(test_string)132 START_TEST(test_string)
133 {
134     DESCRIBE_TEST;
135     test_strndup("", 0);
136     test_strndup("abc", 3);
137     test_strndup("abc\x00xyz", 7);
138 }
139 END_TEST
140 
141 
142 /*-----------------------------------------------------------------------
143  * Endianness
144  */
145 
START_TEST(test_endianness)146 START_TEST(test_endianness)
147 {
148 #define TEST_ENDIAN(TYPE, type, sz, expected, ...) \
149     { \
150         union { uint8_t octets[sz]; type val; }  u = \
151             { { __VA_ARGS__ } }; \
152         \
153         type  from_big = CORK_##TYPE##_BIG_TO_HOST(u.val); \
154         fail_unless(from_big == expected, \
155                     "Unexpected big-to-host " #type " value"); \
156         \
157         type  from_big_in_place = u.val; \
158         CORK_##TYPE##_BIG_TO_HOST_IN_PLACE(from_big_in_place); \
159         fail_unless(from_big_in_place == expected, \
160                     "Unexpected in-place big-to-host " #type " value"); \
161         \
162         type  to_big = CORK_##TYPE##_HOST_TO_BIG(expected); \
163         fail_unless(to_big == u.val, \
164                     "Unexpected host-to-big " #type " value"); \
165         \
166         type  to_big_in_place = expected; \
167         CORK_##TYPE##_HOST_TO_BIG_IN_PLACE(to_big_in_place); \
168         fail_unless(to_big_in_place == u.val, \
169                     "Unexpected in-place host-to-big " #type " value"); \
170         \
171         int  i; \
172         for (i = 0; i < sz/2; i++) { \
173             uint8_t  tmp = u.octets[i]; \
174             u.octets[i] = u.octets[sz-i-1]; \
175             u.octets[sz-i-1] = tmp; \
176         } \
177         \
178         type  from_little = CORK_##TYPE##_LITTLE_TO_HOST(u.val); \
179         fail_unless(from_little == expected, \
180                     "Unexpected little-to-host " #type " value"); \
181         \
182         type  from_little_in_place = u.val; \
183         CORK_##TYPE##_LITTLE_TO_HOST_IN_PLACE(from_little_in_place); \
184         fail_unless(from_little_in_place == expected, \
185                     "Unexpected in-place little-to-host " #type " value"); \
186         \
187         type  to_little = CORK_##TYPE##_HOST_TO_LITTLE(expected); \
188         fail_unless(to_little == u.val, \
189                     "Unexpected host-to-little " #type " value"); \
190         \
191         type  to_little_in_place = expected; \
192         CORK_##TYPE##_HOST_TO_LITTLE_IN_PLACE(to_little_in_place); \
193         fail_unless(to_little_in_place == u.val, \
194                     "Unexpected in-place host-to-little " #type " value"); \
195     }
196 
197     TEST_ENDIAN(UINT16, uint16_t, 2, 0x0102, 1, 2);
198     TEST_ENDIAN(UINT32, uint32_t, 4, 0x01020304, 1, 2, 3, 4);
199     TEST_ENDIAN(UINT64, uint64_t, 8, UINT64_C(0x0102030405060708),
200                 1, 2, 3, 4, 5, 6, 7, 8);
201 
202 #undef TEST_ENDIAN
203 }
204 END_TEST
205 
206 
207 /*-----------------------------------------------------------------------
208  * Built-in errors
209  */
210 
START_TEST(test_error_prefix)211 START_TEST(test_error_prefix)
212 {
213     DESCRIBE_TEST;
214     cork_error_clear();
215     cork_error_set_printf
216         (CORK_UNKNOWN_ERROR, "%u errors occurred", (unsigned int) 17);
217     fail_unless_streq("Error messages",
218                       "17 errors occurred",
219                       cork_error_message());
220     cork_error_prefix("The %s is aborting because ", "program");
221     fail_unless_streq("Error messages",
222                       "The program is aborting because 17 errors occurred",
223                       cork_error_message());
224     cork_error_clear();
225 }
226 END_TEST
227 
START_TEST(test_system_error)228 START_TEST(test_system_error)
229 {
230     DESCRIBE_TEST;
231     /* Artificially flag a system error and make sure we can detect it */
232     errno = ENOMEM;
233     cork_error_clear();
234     cork_system_error_set();
235     fail_unless(cork_error_code() == ENOMEM,
236                 "Expected a system error");
237     printf("Got error: %s\n", cork_error_message());
238     cork_error_clear();
239 }
240 END_TEST
241 
242 
243 /*-----------------------------------------------------------------------
244  * Hash values
245  */
246 
247 #define test_hash_func(func, expected, ...) \
248     fail_unless(func(0, __VA_ARGS__) == expected, \
249                 "Unexpected hash value 0x%08" PRIx32 \
250                 " (expected 0x%08" PRIx32 ")", \
251                 func(0, __VA_ARGS__), expected);
252 
253 #if CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN
254 #if CORK_SIZEOF_POINTER == 8
255 #define test_hash_buf(buf, len, little32, big32, little64, big64) \
256     test_hash_func(cork_hash_buffer, little64, buf, len)
257 #define test_hash_var(var, little32, big32, little64, big64) \
258     test_hash_func(cork_hash_variable, little64, var)
259 #else
260 #define test_hash_buf(buf, len, little32, big32, little64, big64) \
261     test_hash_func(cork_hash_buffer, little32, buf, len)
262 #define test_hash_var(var, little32, big32, little64, big64) \
263     test_hash_func(cork_hash_variable, little32, var)
264 #endif
265 #else
266 #if CORK_SIZEOF_POINTER == 8
267 #define test_hash_buf(buf, len, little32, big32, little64, big64) \
268     test_hash_func(cork_hash_buffer, big64, buf, len)
269 #define test_hash_var(var, little32, big32, little64, big64) \
270     test_hash_func(cork_hash_variable, big64, var)
271 #else
272 #define test_hash_buf(buf, len, little32, big32, little64, big64) \
273     test_hash_func(cork_hash_buffer, big32, buf, len)
274 #define test_hash_var(var, little32, big32, little64, big64) \
275     test_hash_func(cork_hash_variable, big32, var)
276 #endif
277 #endif
278 
279 
280 #define test_stable_hash_buf(buf, len, expected) \
281     test_hash_func(cork_stable_hash_buffer, expected, buf, len)
282 #define test_stable_hash_var(var, expected) \
283     test_hash_func(cork_stable_hash_variable, expected, var)
284 
285 
286 #define test_big_hash_func(buf, len, e1, e2) \
287     do { \
288         cork_big_hash  seed = CORK_BIG_HASH_INIT(); \
289         cork_big_hash  expected = {cork_u128_from_64(e1, e2)}; \
290         cork_big_hash  actual = cork_big_hash_buffer(seed, buf, len); \
291         fail_unless(cork_big_hash_equal(actual, expected), \
292                     "\nUnexpected hash value 0x%016" PRIx64 ".%016" PRIx64 \
293                     "\n            (expected 0x%016" PRIx64 ".%016" PRIx64 ")", \
294                     cork_u128_be64(actual.u128, 0), \
295                     cork_u128_be64(actual.u128, 1), \
296                     cork_u128_be64(expected.u128, 0), \
297                     cork_u128_be64(expected.u128, 1)); \
298     } while (0)
299 
300 #if CORK_HOST_ENDIANNESS == CORK_LITTLE_ENDIAN
301 #if CORK_SIZEOF_POINTER == 8
302 #define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \
303     test_big_hash_func(buf, len, l64a, l64b)
304 #else
305 #define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \
306     test_big_hash_func(buf, len, l32a, l32b)
307 #endif
308 #else
309 #if CORK_SIZEOF_POINTER == 8
310 #define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \
311     test_big_hash_func(buf, len, b64a, b64b)
312 #else
313 #define test_big_hash_buf(buf,len,l32a,l32b,b32a,b32b,l64a,l64b,b64a,b64b) \
314     test_big_hash_func(buf, len, b32a, b32b)
315 #endif
316 #endif
317 
318 
START_TEST(test_hash)319 START_TEST(test_hash)
320 {
321     DESCRIBE_TEST;
322 
323     static const char  BUF[] = "test";
324     static size_t  LEN = sizeof(BUF);
325     static const char  LONG_BUF[] =
326         "this is a much longer test string in the hopes that we have to "
327         "go through a few iterations of the hashing loop in order to "
328         "calculate the value of the hash which we are trying to compute.";
329     static size_t  LONG_LEN = sizeof(LONG_BUF);
330     uint32_t  val32 = 1234;
331     uint64_t  val64 = 1234;
332     uint32_t  stable_val32 = CORK_UINT32_HOST_TO_LITTLE(1234);
333     uint64_t  stable_val64 = CORK_UINT64_HOST_TO_LITTLE(1234);
334 
335     /* without the NUL terminator */
336     test_stable_hash_buf(BUF, LEN-1, 0xba6bd213);
337     test_hash_buf(BUF, LEN-1,
338       /* little 32 */ 0xba6bd213,
339       /*    big 32 */ 0x29d175e5,
340       /* little 64 */ 0xac7d28cc,
341       /*    big 64 */ 0x74bde19d);
342     test_big_hash_buf(BUF, LEN-1,
343       /* little 32 */ 0x6f02ef30550c7d68LL, 0x550c7d68550c7d68LL,
344       /*    big 32 */ 0x6f02ef30550c7d68LL, 0x550c7d68550c7d68LL,
345       /* little 64 */ 0xac7d28cc74bde19dLL, 0x9a128231f9bd4d82LL,
346       /*    big 64 */ 0xac7d28cc74bde19dLL, 0x9a128231f9bd4d82LL);
347 
348     /* with the NUL terminator */
349     test_stable_hash_buf(BUF, LEN, 0x586fce33);
350     test_hash_buf(BUF, LEN,
351       /* little 32 */ 0x586fce33,
352       /*    big 32 */ 0xe31d1ce0,
353       /* little 64 */ 0xc3812fdf,
354       /*    big 64 */ 0x4d18f852);
355     test_big_hash_buf(BUF, LEN,
356       /* little 32 */ 0x98c2b52b29ab177cLL, 0x29ab177c29ab177cLL,
357       /*    big 32 */ 0x98c2b52b29ab177cLL, 0x29ab177c29ab177cLL,
358       /* little 64 */ 0xc3812fdf4d18f852LL, 0xc81a9057aa737aecLL,
359       /*    big 64 */ 0xc3812fdf4d18f852LL, 0xc81a9057aa737aecLL);
360 
361     /* without the NUL terminator */
362     test_stable_hash_buf(LONG_BUF, LONG_LEN-1, 0x5caacc30);
363     test_hash_buf(LONG_BUF, LONG_LEN-1,
364       /* little 32 */ 0x5caacc30,
365       /*    big 32 */ 0x88f94165,
366       /* little 64 */ 0xcbdc2092,
367       /*    big 64 */ 0x03578c96);
368     test_big_hash_buf(LONG_BUF, LONG_LEN-1,
369       /* little 32 */ 0x4240d5134fb7793cLL, 0xee7e281c799f335aLL,
370       /*    big 32 */ 0xab564a5e029c92a4LL, 0x0bd80c741093400fLL,
371       /* little 64 */ 0xcbdc20928fa72e9cLL, 0x48de52d2c680420eLL,
372       /*    big 64 */ 0x5935f90a03578c96LL, 0x163e514fff9c30a8LL);
373 
374     /* with the NUL terminator */
375     test_stable_hash_buf(LONG_BUF, LONG_LEN, 0x5e37d33d);
376     test_hash_buf(LONG_BUF, LONG_LEN,
377       /* little 32 */ 0x5e37d33d,
378       /*    big 32 */ 0x4977421a,
379       /* little 64 */ 0xe89ec005,
380       /*    big 64 */ 0x8c919559);
381     test_big_hash_buf(LONG_BUF, LONG_LEN,
382       /* little 32 */ 0x63bcdcd0c2615146LL, 0x8e7fd7aaece3cab6LL,
383       /*    big 32 */ 0x250b47cda3fc07fdLL, 0x840c4bb606aafbd0LL,
384       /* little 64 */ 0xe89ec0054becb434LL, 0x826391b83f0b4d3eLL,
385       /*    big 64 */ 0xf00a12ab8c919559LL, 0x684ecf4973c66eacLL);
386 
387     test_stable_hash_var(stable_val32, 0x6bb65380);
388     test_hash_var(val32,
389       /* little 32 */ 0x6bb65380,
390       /*    big 32 */ 0x6bb65380,
391       /* little 64 */ 0x061fecc8,
392       /*    big 64 */ 0x7e1b3998);
393 
394     test_stable_hash_var(stable_val64, 0x4d5c4063);
395     test_hash_var(val64,
396       /* little 32 */ 0x4d5c4063,
397       /*    big 32 */ 0xbaeee6e9,
398       /* little 64 */ 0xb119ee69,
399       /*    big 64 */ 0x267305fb);
400 }
401 END_TEST
402 
403 
404 /*-----------------------------------------------------------------------
405  * IP addresses
406  */
407 
408 #define IPV4_TESTS(good, bad) \
409     good("192.168.1.100", "192.168.1.100"); \
410     good("01.002.0003.00000004", "1.2.3.4"); \
411     good("010.0020.00034.00000089", "10.20.34.89"); \
412     good("0100.000200.00.000", "100.200.0.0"); \
413     bad("", -1); \
414     bad(".", -1); \
415     bad("192.168.0.", -1); \
416     bad("192.168.0.1.", -1); \
417     bad("192..168.0.1", -1); \
418     bad("192.168.0.1.2", -1); \
419     bad(".168.0.1.2", -1); \
420     bad("256.0.0.0", -1); \
421     bad("00256.0.0.0", -1); \
422     bad("392.0.0.0", -1); \
423     bad("1920.0.0.0", -1); \
424     bad("stuv", -1); \
425 
426 #define IPV6_TESTS(good, bad) \
427     good("::", "::"); \
428     good("0:0:0:0:0:0:0:0", "::"); \
429     good("0000:0000:0000:0000:0000:0000:0000:0000", "::"); \
430     good("fe80::", "fe80::"); \
431     good("fe80:0:0:0:0:0:0:0", "fe80::"); \
432     good("fe80:0000:0000:0000:0000:0000:0000:0000", "fe80::"); \
433     good("::1", "::1"); \
434     good("0:0:0:0:0:0:0:1", "::1"); \
435     good("0000:0000:0000:0000:0000:0000:0000:0001", "::1"); \
436     good("fe80::1", "fe80::1"); \
437     good("fe80:0:0:0:0:0:0:1", "fe80::1"); \
438     good("fe80:0000:0000:0000:0000:0000:0000:0001", "fe80::1"); \
439     good("0:1:2:3:4:5:6:7", "0:1:2:3:4:5:6:7"); \
440     good("1230:4567:89ab:cdef:1230:4567:89ab:cdef", \
441          "1230:4567:89ab:cdef:1230:4567:89ab:cdef"); \
442     good("::ffff:192.168.1.100", "::ffff:192.168.1.100"); \
443     bad("", -1); \
444     bad(":", -1); \
445     bad("fe80:", -1); \
446     bad("fe80::1::2", -1); \
447     bad("1:2:3:4:5:6:7", -1); \
448     bad("1:2:3:4:5:6:7:8:9", -1); \
449     bad("::1:", -1); \
450     bad("fe800::", -1); \
451     bad("stuv", -1); \
452     /* RFC 5952 recommendations */ \
453     good("2001:0db8::0001", "2001:db8::1"); \
454     good("2001:db8:0:0:0:0:2:1", "2001:db8::2:1"); \
455     good("2001:db8:0:1:1:1:1:1", "2001:db8:0:1:1:1:1:1"); \
456     good("2001:0:0:1:0:0:0:1", "2001:0:0:1::1"); \
457     good("2001:db8:0:0:1:0:0:1", "2001:db8::1:0:0:1"); \
458     good("0:1:A:B:C:D:E:F", "0:1:a:b:c:d:e:f"); \
459 
START_TEST(test_ipv4_address)460 START_TEST(test_ipv4_address)
461 {
462     DESCRIBE_TEST;
463 
464 #define GOOD(str, normalized) \
465     { \
466         struct cork_ipv4  addr; \
467         fail_if_error(cork_ipv4_init(&addr, str)); \
468         char  actual[CORK_IPV4_STRING_LENGTH]; \
469         cork_ipv4_to_raw_string(&addr, actual); \
470         fail_unless(strcmp(actual, normalized) == 0, \
471                     "Unexpected string representation: " \
472                     "got \"%s\", expected \"%s\"", \
473                     actual, normalized); \
474         \
475         struct cork_ipv4  addr2; \
476         cork_ipv4_init(&addr2, normalized); \
477         fail_unless(cork_ipv4_equal(&addr, &addr2), \
478                     "IPv4 instances should be equal"); \
479     }
480 
481 #define BAD(str, unused) \
482     { \
483         struct cork_ipv4  addr; \
484         fail_unless_error \
485             (cork_ipv4_init(&addr, str), \
486              "Shouldn't be able to initialize IPv4 address from \"%s\"", \
487              str); \
488     }
489 
490     IPV4_TESTS(GOOD, BAD);
491     IPV6_TESTS(BAD, BAD);
492 
493 #undef GOOD
494 #undef BAD
495 
496     struct cork_ipv4  addr4;
497     unsigned int  ipv4_cidr_good = 30;
498     unsigned int  ipv4_cidr_bad_value = 24;
499     unsigned int  ipv4_cidr_bad_range = 33;
500 
501     fprintf(stderr, "Testing network prefixes\n");
502     cork_ipv4_init(&addr4, "1.2.3.4");
503     fail_unless(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_good),
504                 "Bad CIDR block for 1.2.3.4 and %u",
505                 ipv4_cidr_good);
506     fail_if(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_bad_value),
507             "IPv4 CIDR check should fail for %u",
508             ipv4_cidr_bad_value);
509     fail_if(cork_ipv4_is_valid_network(&addr4, ipv4_cidr_bad_range),
510             "IPv4 CIDR check should fail for %u",
511             ipv4_cidr_bad_range);
512 }
513 END_TEST
514 
515 
START_TEST(test_ipv6_address)516 START_TEST(test_ipv6_address)
517 {
518     DESCRIBE_TEST;
519 
520 #define GOOD(str, normalized) \
521     { \
522         struct cork_ipv6  addr; \
523         fail_if_error(cork_ipv6_init(&addr, str)); \
524         char  actual[CORK_IPV6_STRING_LENGTH]; \
525         cork_ipv6_to_raw_string(&addr, actual); \
526         fail_unless(strcmp(actual, normalized) == 0, \
527                     "Unexpected string representation: " \
528                     "got \"%s\", expected \"%s\"", \
529                     actual, normalized); \
530         \
531         struct cork_ipv6  addr2; \
532         cork_ipv6_init(&addr2, normalized); \
533         fail_unless(cork_ipv6_equal(&addr, &addr2), \
534                     "IPv6 instances should be equal"); \
535     }
536 
537 #define BAD(str, unused) \
538     { \
539         struct cork_ipv6  addr; \
540         fail_unless_error \
541             (cork_ipv6_init(&addr, str), \
542              "Shouldn't be able to initialize IPv6 address from \"%s\"", \
543              str); \
544     }
545 
546     IPV6_TESTS(GOOD, BAD);
547     IPV4_TESTS(BAD, BAD);
548 
549 #undef GOOD
550 #undef BAD
551 
552     struct cork_ipv6  addr6;
553     unsigned int  ipv6_cidr_good = 127;
554     unsigned int  ipv6_cidr_bad_value = 64;
555     unsigned int  ipv6_cidr_bad_range = 129;
556 
557     fprintf(stderr, "Testing network prefixes\n");
558     cork_ipv6_init(&addr6, "fe80::200:f8ff:fe21:6000");
559     fail_unless(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_good),
560                 "Bad CIDR block %u",
561                 ipv6_cidr_good);
562     fail_if(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_bad_value),
563             "IPv6 CIDR check should fail for %u",
564             ipv6_cidr_bad_value);
565     fail_if(cork_ipv6_is_valid_network(&addr6, ipv6_cidr_bad_range),
566             "IPv6 CIDR check should fail for %u",
567             ipv6_cidr_bad_range);
568 }
569 END_TEST
570 
571 
START_TEST(test_ip_address)572 START_TEST(test_ip_address)
573 {
574     DESCRIBE_TEST;
575     struct cork_ip  addr;
576 
577 #define GOOD(str, normalized) \
578     { \
579         struct cork_ip  addr; \
580         fail_if_error(cork_ip_init(&addr, str)); \
581         char  actual[CORK_IP_STRING_LENGTH]; \
582         cork_ip_to_raw_string(&addr, actual); \
583         fail_unless(strcmp(actual, normalized) == 0, \
584                     "Unexpected string representation: " \
585                     "got \"%s\", expected \"%s\"", \
586                     actual, normalized); \
587         \
588         struct cork_ip  addr2; \
589         cork_ip_init(&addr2, normalized); \
590         fail_unless(cork_ip_equal(&addr, &addr2), \
591                     "IP instances should be equal"); \
592     }
593 
594 #define BAD(str, unused) \
595     { \
596         struct cork_ip  addr; \
597         fail_unless_error \
598             (cork_ip_init(&addr, str), \
599              "Shouldn't be able to initialize IP address from \"%s\"", \
600              str); \
601     }
602 
603     IPV4_TESTS(GOOD, BAD);
604     IPV6_TESTS(GOOD, BAD);
605 
606 #undef GOOD
607 #undef BAD
608 
609     struct cork_ipv4  addr4;
610     struct cork_ipv6  addr6;
611 
612     fprintf(stderr, "Testing IP address versions\n");
613     cork_ip_init(&addr, "192.168.1.1");
614     cork_ipv4_init(&addr4, "192.168.1.1");
615     fail_unless(addr.version == 4,
616                 "Unexpected IP address version (expected 4, got %u)",
617                 addr.version);
618     fail_unless(cork_ipv4_equal(&addr.ip.v4, &addr4),
619                 "IP addresses should be equal");
620 
621     cork_ip_init(&addr, "fe80::1");
622     cork_ipv6_init(&addr6, "fe80::1");
623     fail_unless(addr.version == 6,
624                 "Unexpected IP address version (expected 6, got %u)",
625                 addr.version);
626     fail_unless(cork_ipv6_equal(&addr.ip.v6, &addr6),
627                 "IP addresses should be equal");
628 }
629 END_TEST
630 
631 
632 /*-----------------------------------------------------------------------
633  * Timestamps
634  */
635 
636 static void
test_timestamp_bad_format(cork_timestamp ts,const char * format)637 test_timestamp_bad_format(cork_timestamp ts, const char *format)
638 {
639     struct cork_buffer  buf = CORK_BUFFER_INIT();
640     fail_unless_error(cork_timestamp_format_utc(ts, format, &buf));
641     cork_buffer_done(&buf);
642 }
643 
644 static void
test_timestamp_utc_format(cork_timestamp ts,const char * format,const char * expected)645 test_timestamp_utc_format(cork_timestamp ts, const char *format,
646                           const char *expected)
647 {
648     struct cork_buffer  buf = CORK_BUFFER_INIT();
649     fail_if_error(cork_timestamp_format_utc(ts, format, &buf));
650     fail_unless(strcmp(buf.buf, expected) == 0,
651                 "Unexpected formatted UTC time "
652                 "(got \"%s\", expected \"%s\")",
653                 (char *) buf.buf, expected);
654     cork_buffer_done(&buf);
655 }
656 
657 static void
test_timestamp_local_format(cork_timestamp ts,const char * format,const char * expected)658 test_timestamp_local_format(cork_timestamp ts, const char *format,
659                             const char *expected)
660 {
661     struct cork_buffer  buf = CORK_BUFFER_INIT();
662     fail_if_error(cork_timestamp_format_local(ts, format, &buf));
663     fail_unless(strcmp(buf.buf, expected) == 0,
664                 "Unexpected formatted local time "
665                 "(got \"%s\", expected \"%s\")",
666                 (char *) buf.buf, expected);
667     cork_buffer_done(&buf);
668 }
669 
START_TEST(test_timestamp)670 START_TEST(test_timestamp)
671 {
672     /* All of the local times here are in America/Los_Angeles.  Down at the
673      * bottom of the file we override the TZ environment variable to ensure that
674      * we use a consistent local time zone in the test cases, regardless of the
675      * actual time zone of the current machine. */
676 
677     static const uint32_t  TEST_TIME_1 = 700000000;
678     static const char  *FORMATTED_UTC_TIME_1   = " 1992-03-07 20:26:40 ";
679     static const char  *FORMATTED_LOCAL_TIME_1 = " 1992-03-07 12:26:40 ";
680 
681     static const uint32_t  TEST_TIME_2 = 1200000000;
682     static const char  *FORMATTED_UTC_TIME_2   = " 2008-01-10 21:20:00 ";
683     static const char  *FORMATTED_LOCAL_TIME_2 = " 2008-01-10 13:20:00 ";
684 
685     static const uint32_t  TEST_TIME_3 = 1305180745;
686     static const char  *FORMATTED_UTC_TIME_3   = " 2011-05-12 06:12:25 ";
687     static const char  *FORMATTED_LOCAL_TIME_3 = " 2011-05-11 23:12:25 ";
688 
689     cork_timestamp  ts;
690 
691     DESCRIBE_TEST;
692 
693 #define test(unit, expected) \
694     fail_unless(cork_timestamp_##unit(ts) == expected, \
695                 "Unexpected " #unit " portion of timestamp " \
696                 "(got %lu, expected %lu)", \
697                 (unsigned long) cork_timestamp_##unit(ts), \
698                 (unsigned long) expected);
699 
700 #define test_format(utc, local) \
701     test_timestamp_utc_format(ts, " %Y-%m-%d %H:%M:%S ", utc); \
702     test_timestamp_local_format(ts, " %Y-%m-%d %H:%M:%S ", local);
703 
704     cork_timestamp_init_sec(&ts, TEST_TIME_1);
705     test(sec, TEST_TIME_1);
706     test(gsec, 0);
707     test(msec, 0);
708     test(usec, 0);
709     test(nsec, 0);
710     test_format(FORMATTED_UTC_TIME_1, FORMATTED_LOCAL_TIME_1);
711 
712     cork_timestamp_init_sec(&ts, TEST_TIME_2);
713     test(sec, TEST_TIME_2);
714     test(gsec, 0);
715     test(msec, 0);
716     test(usec, 0);
717     test(nsec, 0);
718     test_format(FORMATTED_UTC_TIME_2, FORMATTED_LOCAL_TIME_2);
719 
720     cork_timestamp_init_sec(&ts, TEST_TIME_3);
721     test(sec, TEST_TIME_3);
722     test(gsec, 0);
723     test(msec, 0);
724     test(usec, 0);
725     test(nsec, 0);
726     test_format(FORMATTED_UTC_TIME_3, FORMATTED_LOCAL_TIME_3);
727 
728     cork_timestamp_init_gsec(&ts, TEST_TIME_1, 1 << 30);
729     test(sec, TEST_TIME_1);
730     test(gsec, 1 << 30);
731     test(msec, 250);
732     test(usec, 250000);
733     test(nsec, 250000000);
734 
735     cork_timestamp_init_msec(&ts, TEST_TIME_1, 500);
736     test(sec, TEST_TIME_1);
737     test(gsec, 1 << 31);
738     test(msec, 500);
739     test(usec, 500000);
740     test(nsec, 500000000);
741 
742     cork_timestamp_init_usec(&ts, TEST_TIME_1, 500000);
743     test(sec, TEST_TIME_1);
744     test(gsec, 1 << 31);
745     test(msec, 500);
746     test(usec, 500000);
747     test(nsec, 500000000);
748 
749     cork_timestamp_init_nsec(&ts, TEST_TIME_1, 500000000);
750     test(sec, TEST_TIME_1);
751     test(gsec, 1 << 31);
752     test(msec, 500);
753     test(usec, 500000);
754     test(nsec, 500000000);
755 }
756 END_TEST
757 
START_TEST(test_timestamp_format)758 START_TEST(test_timestamp_format)
759 {
760     cork_timestamp  ts;
761     DESCRIBE_TEST;
762 
763     cork_timestamp_init_nsec(&ts, 0, 123456789);
764     test_timestamp_bad_format(ts, "%f");
765     test_timestamp_bad_format(ts, "%0f");
766     test_timestamp_bad_format(ts, "%10f");
767     test_timestamp_utc_format(ts, "%1f",   "1");
768     test_timestamp_utc_format(ts, "%2f",   "12");
769     test_timestamp_utc_format(ts, "%3f",   "123");
770     test_timestamp_utc_format(ts, "%4f",   "1235");
771     test_timestamp_utc_format(ts, "%5f",   "12346");
772     test_timestamp_utc_format(ts, "%6f",   "123457");
773     test_timestamp_utc_format(ts, "%7f",   "1234568");
774     test_timestamp_utc_format(ts, "%8f",   "12345679");
775     test_timestamp_utc_format(ts, "%9f",   "123456789");
776     test_timestamp_utc_format(ts, "%009f", "123456789");
777 
778     cork_timestamp_init_nsec(&ts, 1200000000, 123456789);
779 }
780 END_TEST
781 
782 
783 /*-----------------------------------------------------------------------
784  * 128-bit integers
785  */
786 
787 static void
test_one_u128_decimal(cork_u128 value,const char * expected)788 test_one_u128_decimal(cork_u128 value, const char *expected)
789 {
790     char  buf[CORK_U128_DECIMAL_LENGTH];
791     const char  *actual = cork_u128_to_decimal(buf, value);
792     fail_unless_streq("Integers", expected, actual);
793 }
794 
795 static void
test_one_u128_hex(cork_u128 value,const char * expected)796 test_one_u128_hex(cork_u128 value, const char *expected)
797 {
798     char  buf[CORK_U128_HEX_LENGTH];
799     const char  *actual = cork_u128_to_hex(buf, value);
800     fail_unless_streq("Integers", expected, actual);
801 }
802 
803 static void
test_one_u128_padded_hex(cork_u128 value,const char * expected)804 test_one_u128_padded_hex(cork_u128 value, const char *expected)
805 {
806     char  buf[CORK_U128_HEX_LENGTH];
807     const char  *actual = cork_u128_to_padded_hex(buf, value);
808     fail_unless_streq("Integers", expected, actual);
809 }
810 
811 static void
test_one_u128_print_from_32(uint32_t i0,uint32_t i1,uint32_t i2,uint32_t i3,const char * expected_decimal,const char * expected_hex,const char * expected_padded_hex)812 test_one_u128_print_from_32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3,
813                             const char *expected_decimal,
814                             const char *expected_hex,
815                             const char *expected_padded_hex)
816 {
817     cork_u128  value = cork_u128_from_32(i0, i1, i2, i3);
818     test_one_u128_decimal(value, expected_decimal);
819     test_one_u128_hex(value, expected_hex);
820     test_one_u128_padded_hex(value, expected_padded_hex);
821 }
822 
823 static void
test_one_u128_print_from_64(uint64_t i0,uint64_t i1,const char * expected_decimal,const char * expected_hex,const char * expected_padded_hex)824 test_one_u128_print_from_64(uint64_t i0, uint64_t i1,
825                             const char *expected_decimal,
826                             const char *expected_hex,
827                             const char *expected_padded_hex)
828 {
829     cork_u128  value = cork_u128_from_64(i0, i1);
830     test_one_u128_decimal(value, expected_decimal);
831     test_one_u128_hex(value, expected_hex);
832     test_one_u128_padded_hex(value, expected_padded_hex);
833 }
834 
START_TEST(test_u128_print)835 START_TEST(test_u128_print)
836 {
837     DESCRIBE_TEST;
838     test_one_u128_print_from_32(
839         0, 0, 0, 0,
840         "0",
841         "0",
842         "00000000000000000000000000000000"
843     );
844     test_one_u128_print_from_32(
845         0, 0, 0, 2,
846         "2",
847         "2",
848         "00000000000000000000000000000002"
849     );
850     test_one_u128_print_from_32(
851         0, 0, 0, 20,
852         "20",
853         "14",
854         "00000000000000000000000000000014"
855     );
856     test_one_u128_print_from_32(
857         0, 0, 0, 0xffffffff,
858         "4294967295",
859         "ffffffff",
860         "000000000000000000000000ffffffff"
861     );
862     test_one_u128_print_from_32(
863         0, 0, 1, 0,
864         "4294967296",
865         "100000000",
866         "00000000000000000000000100000000"
867     );
868     test_one_u128_print_from_32(
869         0, 0, 0xffffffff, 0xffffffff,
870         "18446744073709551615",
871         "ffffffffffffffff",
872         "0000000000000000ffffffffffffffff"
873     );
874     test_one_u128_print_from_32(
875         0, 1, 0, 0,
876         "18446744073709551616",
877         "10000000000000000",
878         "00000000000000010000000000000000"
879     );
880     test_one_u128_print_from_64(
881         0, 0,
882         "0",
883         "0",
884         "00000000000000000000000000000000"
885     );
886     test_one_u128_print_from_64(
887         0, 2,
888         "2",
889         "2",
890         "00000000000000000000000000000002"
891     );
892     test_one_u128_print_from_64(
893         0, 20,
894         "20",
895         "14",
896         "00000000000000000000000000000014"
897     );
898     test_one_u128_print_from_64(
899         0, UINT64_C(0xffffffffffffffff),
900         "18446744073709551615",
901         "ffffffffffffffff",
902         "0000000000000000ffffffffffffffff"
903     );
904     test_one_u128_print_from_64(
905         1, 0,
906         "18446744073709551616",
907         "10000000000000000",
908         "00000000000000010000000000000000"
909     );
910 }
911 END_TEST
912 
913 
914 static void
test_one_u128_add(uint64_t i0,uint64_t i1,uint64_t j0,uint64_t j1,const char * expected)915 test_one_u128_add(uint64_t i0, uint64_t i1, uint64_t j0, uint64_t j1,
916                   const char *expected)
917 {
918     cork_u128  value1 = cork_u128_from_64(i0, i1);
919     cork_u128  value2 = cork_u128_from_64(j0, j1);
920     cork_u128  sum = cork_u128_add(value1, value2);
921     test_one_u128_decimal(sum, expected);
922 }
923 
START_TEST(test_u128_add)924 START_TEST(test_u128_add)
925 {
926     DESCRIBE_TEST;
927     test_one_u128_add(0, 0, 0, 0, "0");
928     test_one_u128_add(0, 1, 0, 1, "2");
929     test_one_u128_add(0, 1, 0, 0xffffffff, "4294967296");
930     test_one_u128_add(0, 1, 0xffffffffffffffffLL, 0xffffffffffffffffLL, "0");
931 }
932 END_TEST
933 
934 
935 static void
test_one_u128_sub(uint64_t i0,uint64_t i1,uint64_t j0,uint64_t j1,const char * expected)936 test_one_u128_sub(uint64_t i0, uint64_t i1, uint64_t j0, uint64_t j1,
937                   const char *expected)
938 {
939     cork_u128  value1 = cork_u128_from_64(i0, i1);
940     cork_u128  value2 = cork_u128_from_64(j0, j1);
941     cork_u128  diff = cork_u128_sub(value1, value2);
942     test_one_u128_decimal(diff, expected);
943 }
944 
START_TEST(test_u128_sub)945 START_TEST(test_u128_sub)
946 {
947     DESCRIBE_TEST;
948     test_one_u128_sub(0, 0, 0, 0, "0");
949     test_one_u128_sub(0, 1, 0, 1, "0");
950     test_one_u128_sub(0, 2, 0, 1, "1");
951     test_one_u128_sub(0, UINT64_C(0x100000000), 0, 1, "4294967295");
952     test_one_u128_sub(1, 0, 0, 1, "18446744073709551615");
953     test_one_u128_sub(0, 1, 0, 2, "340282366920938463463374607431768211455");
954 }
955 END_TEST
956 
957 
958 #define test_u128_cmp(op, op_str, v1, v2, expected) \
959     do { \
960         bool  actual = cork_u128_##op((v1), (v2)); \
961         fail_unless(actual == (expected), \
962                     "%" PRIu64 ":%" PRIu64 \
963                     " should %sbe " op_str " " \
964                     "%" PRIu64 ":%" PRIu64, \
965                     cork_u128_be64((v1), 0), cork_u128_be64((v1), 1), \
966                     (expected)? "": "not ", \
967                     cork_u128_be64((v2), 0), cork_u128_be64((v2), 1)); \
968     } while (0)
969 
970 static void
test_one_u128_eq(uint64_t i0,uint64_t i1,uint64_t j0,uint64_t j1,bool expected)971 test_one_u128_eq(uint64_t i0, uint64_t i1, uint64_t j0, uint64_t j1,
972                  bool expected)
973 {
974     cork_u128  value1 = cork_u128_from_64(i0, i1);
975     cork_u128  value2 = cork_u128_from_64(j0, j1);
976     test_u128_cmp(eq, "==", value1, value2, expected);
977     test_u128_cmp(ne, "!=", value1, value2, !expected);
978 }
979 
START_TEST(test_u128_eq)980 START_TEST(test_u128_eq)
981 {
982     DESCRIBE_TEST;
983     test_one_u128_eq(0, 0, 0, 0, true);
984     test_one_u128_eq(0, 0, 0, 1, false);
985     test_one_u128_eq(0, 2, 0, 1, false);
986     test_one_u128_eq(0, 1, 0, UINT64_C(0x100000000), false);
987     test_one_u128_eq(0, UINT64_C(0x100000000), 0, UINT64_C(0x100000000), true);
988 }
989 END_TEST
990 
991 static void
test_one_u128_lt(uint64_t i0,uint64_t i1,uint64_t j0,uint64_t j1,bool expected)992 test_one_u128_lt(uint64_t i0, uint64_t i1, uint64_t j0, uint64_t j1,
993                  bool expected)
994 {
995     cork_u128  value1 = cork_u128_from_64(i0, i1);
996     cork_u128  value2 = cork_u128_from_64(j0, j1);
997     test_u128_cmp(lt, "<",  value1, value2, expected);
998     test_u128_cmp(ge, ">=", value1, value2, !expected);
999 }
1000 
START_TEST(test_u128_lt)1001 START_TEST(test_u128_lt)
1002 {
1003     DESCRIBE_TEST;
1004     test_one_u128_lt(0, 0, 0, 0, false);
1005     test_one_u128_lt(0, 0, 0, 1, true);
1006     test_one_u128_lt(0, 2, 0, 1, false);
1007     test_one_u128_lt(0, 1, 0, UINT64_C(0x100000000), true);
1008 }
1009 END_TEST
1010 
1011 static void
test_one_u128_gt(uint64_t i0,uint64_t i1,uint64_t j0,uint64_t j1,bool expected)1012 test_one_u128_gt(uint64_t i0, uint64_t i1, uint64_t j0, uint64_t j1,
1013                  bool expected)
1014 {
1015     cork_u128  value1 = cork_u128_from_64(i0, i1);
1016     cork_u128  value2 = cork_u128_from_64(j0, j1);
1017     test_u128_cmp(gt, ">",  value1, value2, expected);
1018     test_u128_cmp(le, "<=", value1, value2, !expected);
1019 }
1020 
START_TEST(test_u128_gt)1021 START_TEST(test_u128_gt)
1022 {
1023     DESCRIBE_TEST;
1024     test_one_u128_gt(0, 0, 0, 0, false);
1025     test_one_u128_gt(0, 1, 0, 0, true);
1026     test_one_u128_gt(0, 1, 0, 2, false);
1027     test_one_u128_gt(0, UINT64_C(0x100000000), 0, 1, true);
1028 }
1029 END_TEST
1030 
1031 
1032 /*-----------------------------------------------------------------------
1033  * Statement expressions
1034  */
1035 
START_TEST(test_statement_expr)1036 START_TEST(test_statement_expr)
1037 {
1038 #if CORK_CONFIG_HAVE_GCC_STATEMENT_EXPRS
1039     int  value = ({ int __x = 0; __x += 2; __x;});
1040     fail_unless_equal("Statement expression result", "%d", 2, value);
1041 #endif
1042 }
1043 END_TEST
1044 
1045 
1046 /*-----------------------------------------------------------------------
1047  * Unique identifiers
1048  */
1049 
START_TEST(test_uid)1050 START_TEST(test_uid)
1051 {
1052     DESCRIBE_TEST;
1053     cork_uid_define(test_id_01);
1054     cork_uid_define(test_id_02);
1055     cork_uid  id1;
1056     cork_uid  id2;
1057 
1058     fail_unless_streq("UID name", "test_id_01", cork_uid_name(test_id_01));
1059     fail_unless_streq("UID name", "test_id_02", cork_uid_name(test_id_02));
1060 
1061     id1 = test_id_01;
1062     id2 = test_id_02;
1063     fail_if(cork_uid_equal(id1, id2), "Unique IDs aren't unique");
1064 
1065     id1 = test_id_01;
1066     id2 = test_id_01;
1067     fail_unless(cork_uid_equal(id1, id2), "Unique ID isn't equal to itself");
1068 
1069     id1 = test_id_01;
1070     id2 = CORK_UID_NONE;
1071     fail_if(cork_uid_equal(id1, id2), "NULL unique ID isn't unique");
1072 }
1073 END_TEST
1074 
1075 
1076 /*-----------------------------------------------------------------------
1077  * Testing harness
1078  */
1079 
1080 Suite *
test_suite()1081 test_suite()
1082 {
1083     Suite  *s = suite_create("core");
1084 
1085     TCase  *tc_types = tcase_create("types");
1086     tcase_add_test(tc_types, test_bool);
1087     tcase_add_test(tc_types, test_int_types);
1088     tcase_add_test(tc_types, test_int_sizeof);
1089     suite_add_tcase(s, tc_types);
1090 
1091     TCase  *tc_string = tcase_create("string");
1092     tcase_add_test(tc_string, test_string);
1093     suite_add_tcase(s, tc_string);
1094 
1095     TCase  *tc_endianness = tcase_create("endianness");
1096     tcase_add_test(tc_endianness, test_endianness);
1097     suite_add_tcase(s, tc_endianness);
1098 
1099     TCase  *tc_errors = tcase_create("errors");
1100     tcase_add_test(tc_errors, test_error_prefix);
1101     tcase_add_test(tc_errors, test_system_error);
1102     suite_add_tcase(s, tc_errors);
1103 
1104     TCase  *tc_hash = tcase_create("hash");
1105     tcase_add_test(tc_hash, test_hash);
1106     suite_add_tcase(s, tc_hash);
1107 
1108     TCase  *tc_addresses = tcase_create("net-addresses");
1109     tcase_add_test(tc_addresses, test_ipv4_address);
1110     tcase_add_test(tc_addresses, test_ipv6_address);
1111     tcase_add_test(tc_addresses, test_ip_address);
1112     suite_add_tcase(s, tc_addresses);
1113 
1114     TCase  *tc_timestamp = tcase_create("timestamp");
1115     tcase_add_test(tc_timestamp, test_timestamp);
1116     tcase_add_test(tc_timestamp, test_timestamp_format);
1117     suite_add_tcase(s, tc_timestamp);
1118 
1119     TCase  *tc_u128 = tcase_create("u128");
1120     tcase_add_test(tc_u128, test_u128_print);
1121     tcase_add_test(tc_u128, test_u128_add);
1122     tcase_add_test(tc_u128, test_u128_sub);
1123     tcase_add_test(tc_u128, test_u128_eq);
1124     tcase_add_test(tc_u128, test_u128_lt);
1125     tcase_add_test(tc_u128, test_u128_gt);
1126     suite_add_tcase(s, tc_u128);
1127 
1128     TCase  *tc_statement_expr = tcase_create("statement_expr");
1129     tcase_add_test(tc_statement_expr, test_statement_expr);
1130     suite_add_tcase(s, tc_statement_expr);
1131 
1132     TCase  *tc_uid = tcase_create("uid");
1133     tcase_add_test(tc_uid, test_uid);
1134     suite_add_tcase(s, tc_uid);
1135 
1136     return s;
1137 }
1138 
1139 
1140 int
main(int argc,const char ** argv)1141 main(int argc, const char **argv)
1142 {
1143     int  number_failed;
1144     Suite  *suite = test_suite();
1145     SRunner  *runner = srunner_create(suite);
1146 
1147     setup_allocator();
1148 
1149     /* Before anything starts, override the TZ environment variable so that we
1150      * get consistent test results. */
1151     cork_env_add(NULL, "TZ", "America/Los_Angeles");
1152 
1153     srunner_run_all(runner, CK_NORMAL);
1154     number_failed = srunner_ntests_failed(runner);
1155     srunner_free(runner);
1156 
1157     return (number_failed == 0)? EXIT_SUCCESS: EXIT_FAILURE;
1158 }
1159