1 /*
2 * SysDB - t/unit/core/data_test.c
3 * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include "core/data.h"
29 #include "libsysdb_test.h"
31 #include <assert.h>
32 #include <check.h>
34 static regex_t empty_re;
36 START_TEST(test_data)
37 {
38 sdb_data_t d1, d2;
39 int check;
41 d2.type = SDB_TYPE_INTEGER;
42 d2.data.integer = 4711;
43 memset(&d1, 0, sizeof(d1));
44 check = sdb_data_copy(&d1, &d2);
45 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
46 fail_unless(d1.type == d2.type,
47 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
48 d1.type, d2.type);
49 fail_unless(d1.data.integer == d2.data.integer,
50 "sdb_data_copy() didn't copy integer data: got: %d; expected: %d",
51 d1.data.integer, d2.data.integer);
53 d2.type = SDB_TYPE_DECIMAL;
54 d2.data.decimal = 47.11;
55 check = sdb_data_copy(&d1, &d2);
56 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
57 fail_unless(d1.type == d2.type,
58 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
59 d1.type, d2.type);
60 fail_unless(d1.data.decimal == d2.data.decimal,
61 "sdb_data_copy() didn't copy decimal data: got: %f; expected: %f",
62 d1.data.decimal, d2.data.decimal);
64 d2.type = SDB_TYPE_STRING;
65 d2.data.string = "some string";
66 check = sdb_data_copy(&d1, &d2);
67 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
68 fail_unless(d1.type == d2.type,
69 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
70 d1.type, d2.type);
71 fail_unless(!strcmp(d1.data.string, d2.data.string),
72 "sdb_data_copy() didn't copy string data: got: %s; expected: %s",
73 d1.data.string, d2.data.string);
75 sdb_data_free_datum(&d1);
76 fail_unless(d1.data.string == NULL,
77 "sdb_data_free_datum() didn't free string data");
79 d1.type = 0;
80 d2.type = SDB_TYPE_STRING;
81 d2.data.string = NULL;
82 check = sdb_data_copy(&d1, &d2);
83 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
84 fail_unless(d1.type == d2.type,
85 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
86 d1.type, d2.type);
87 fail_unless(d1.data.string == d2.data.string,
88 "sdb_data_copy() didn't copy string data: got: %s; expected: %s",
89 d1.data.string, d2.data.string);
91 sdb_data_free_datum(&d1);
92 fail_unless(d1.data.string == NULL,
93 "sdb_data_free_datum() didn't free string data");
95 d2.type = SDB_TYPE_DATETIME;
96 d2.data.datetime = 4711;
97 check = sdb_data_copy(&d1, &d2);
98 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
99 fail_unless(d1.type == d2.type,
100 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
101 d1.type, d2.type);
102 fail_unless(d1.data.datetime == d2.data.datetime,
103 "sdb_data_copy() didn't copy datetime data: got: %d; expected: %d",
104 d1.data.datetime, d2.data.datetime);
106 d2.type = SDB_TYPE_BINARY;
107 d2.data.binary.datum = (unsigned char *)"some string";
108 d2.data.binary.length = strlen((const char *)d2.data.binary.datum);
109 check = sdb_data_copy(&d1, &d2);
110 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
111 fail_unless(d1.type == d2.type,
112 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
113 d1.type, d2.type);
114 fail_unless(d1.data.binary.length == d2.data.binary.length,
115 "sdb_data_copy() didn't copy length; got: %d; expected: 5d",
116 d1.data.binary.length, d2.data.binary.length);
117 fail_unless(!memcmp(d1.data.binary.datum, d2.data.binary.datum,
118 d2.data.binary.length),
119 "sdb_data_copy() didn't copy binary data: got: %s; expected: %s",
120 d1.data.binary.datum, d2.data.binary.datum);
122 sdb_data_free_datum(&d1);
123 fail_unless(d1.data.binary.length == 0,
124 "sdb_data_free_datum() didn't reset binary datum length");
125 fail_unless(d1.data.binary.datum == NULL,
126 "sdb_data_free_datum() didn't free binary datum");
128 d1.type = 0;
129 d2.type = SDB_TYPE_BINARY;
130 d2.data.binary.datum = NULL;
131 d2.data.binary.length = 0;
132 check = sdb_data_copy(&d1, &d2);
133 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
134 fail_unless(d1.type == d2.type,
135 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
136 d1.type, d2.type);
137 fail_unless(d1.data.binary.length == d2.data.binary.length,
138 "sdb_data_copy() didn't copy length; got: %d; expected: 5d",
139 d1.data.binary.length, d2.data.binary.length);
140 fail_unless(d1.data.binary.datum == d2.data.binary.datum,
141 "sdb_data_copy() didn't copy binary data: got: %s; expected: %s",
142 d1.data.binary.datum, d2.data.binary.datum);
144 sdb_data_free_datum(&d1);
145 fail_unless(d1.data.binary.length == 0,
146 "sdb_data_free_datum() didn't reset binary datum length");
147 fail_unless(d1.data.binary.datum == NULL,
148 "sdb_data_free_datum() didn't free binary datum");
150 check = sdb_data_parse(".", SDB_TYPE_REGEX, &d2);
151 fail_unless(check == 0,
152 "INTERNAL ERROR: Failed to parse regex '.'");
153 assert(d2.type == SDB_TYPE_REGEX);
154 check = sdb_data_copy(&d1, &d2);
155 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
156 fail_unless(d1.type == d2.type,
157 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
158 d1.type, d2.type);
159 fail_unless(d1.data.re.raw != d2.data.re.raw,
160 "sdb_data_copy() copy string pointer");
161 fail_unless(!strcmp(d1.data.re.raw, d2.data.re.raw),
162 "sdb_data_copy() didn't copy raw regex: got: %s; expected: %s",
163 d1.data.re.raw, d2.data.re.raw);
164 sdb_data_free_datum(&d2);
166 sdb_data_free_datum(&d1);
167 fail_unless(d1.data.re.raw == NULL,
168 "sdb_data_free_datum() didn't reset raw regex");
170 d2.type = SDB_TYPE_REGEX;
171 d2.data.re.raw = NULL;
172 check = sdb_data_copy(&d1, &d2);
173 fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
174 fail_unless(d1.type == d2.type,
175 "sdb_data_copy() didn't copy type; got: %i; expected: %i",
176 d1.type, d2.type);
177 fail_unless(d1.data.re.raw == d2.data.re.raw,
178 "sdb_data_copy() didn't copy raw regex: got: %s; expected: %s",
179 d1.data.re.raw, d2.data.re.raw);
181 sdb_data_free_datum(&d1);
182 fail_unless(d1.data.re.raw == NULL,
183 "sdb_data_free_datum() didn't reset raw regex");
184 }
185 END_TEST
187 START_TEST(test_cmp)
188 {
189 struct {
190 sdb_data_t d1;
191 sdb_data_t d2;
192 int expected;
193 } golden_data[] = {
194 {
195 { SDB_TYPE_INTEGER, { .integer = 47 } },
196 { SDB_TYPE_INTEGER, { .integer = 4711 } },
197 -1,
198 },
199 {
200 { SDB_TYPE_INTEGER, { .integer = 4711 } },
201 { SDB_TYPE_INTEGER, { .integer = 4711 } },
202 0,
203 },
204 {
205 { SDB_TYPE_INTEGER, { .integer = 4711 } },
206 { SDB_TYPE_INTEGER, { .integer = 47 } },
207 1,
208 },
209 {
210 { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } },
211 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
212 -1,
213 },
214 {
215 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
216 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
217 0,
218 },
219 {
220 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
221 { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } },
222 1,
223 },
224 {
225 { SDB_TYPE_STRING, { .string = NULL } },
226 { SDB_TYPE_STRING, { .string = "" } },
227 -1,
228 },
229 {
230 { SDB_TYPE_STRING, { .string = NULL } },
231 { SDB_TYPE_STRING, { .string = NULL } },
232 0,
233 },
234 {
235 { SDB_TYPE_STRING, { .string = "" } },
236 { SDB_TYPE_STRING, { .string = NULL } },
237 1,
238 },
239 {
240 { SDB_TYPE_STRING, { .string = "a" } },
241 { SDB_TYPE_STRING, { .string = "b" } },
242 -1,
243 },
244 {
245 { SDB_TYPE_STRING, { .string = "a" } },
246 { SDB_TYPE_STRING, { .string = "ab" } },
247 -1,
248 },
249 {
250 { SDB_TYPE_STRING, { .string = "a" } },
251 { SDB_TYPE_STRING, { .string = "a" } },
252 0,
253 },
254 {
255 { SDB_TYPE_STRING, { .string = "b" } },
256 { SDB_TYPE_STRING, { .string = "a" } },
257 1,
258 },
259 {
260 { SDB_TYPE_STRING, { .string = "ab" } },
261 { SDB_TYPE_STRING, { .string = "a" } },
262 1,
263 },
264 {
265 { SDB_TYPE_DATETIME, { .datetime = 471147114711471000 } },
266 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
267 -1,
268 },
269 {
270 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
271 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
272 0,
273 },
274 {
275 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
276 { SDB_TYPE_DATETIME, { .datetime = 471147114711471000 } },
277 1,
278 },
279 {
280 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
281 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
282 -1,
283 },
284 {
285 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
286 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
287 0,
288 },
289 {
290 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
291 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
292 1,
293 },
294 {
295 {
296 SDB_TYPE_BINARY,
297 { .binary = { 3, (unsigned char *)"a\0a" } },
298 },
299 {
300 SDB_TYPE_BINARY,
301 { .binary = { 3, (unsigned char *)"a\0b" } },
302 },
303 -1,
304 },
305 {
306 {
307 SDB_TYPE_BINARY,
308 { .binary = { 1, (unsigned char *)"a" } },
309 },
310 {
311 SDB_TYPE_BINARY,
312 { .binary = { 3, (unsigned char *)"a\0\0" } },
313 },
314 -1,
315 },
316 {
317 {
318 SDB_TYPE_BINARY,
319 { .binary = { 3, (unsigned char *)"a\0a" } },
320 },
321 {
322 SDB_TYPE_BINARY,
323 { .binary = { 3, (unsigned char *)"a\0a" } },
324 },
325 0,
326 },
327 {
328 {
329 SDB_TYPE_BINARY,
330 { .binary = { 3, (unsigned char *)"a\0b" } },
331 },
332 {
333 SDB_TYPE_BINARY,
334 { .binary = { 3, (unsigned char *)"a\0a" } },
335 },
336 1,
337 },
338 {
339 {
340 SDB_TYPE_BINARY,
341 { .binary = { 3, (unsigned char *)"a\0\0" } },
342 },
343 {
344 SDB_TYPE_BINARY,
345 { .binary = { 1, (unsigned char *)"a" } },
346 },
347 1,
348 },
349 {
350 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
351 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
352 0,
353 },
354 {
355 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
356 { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
357 -1,
358 },
359 {
360 { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
361 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
362 1,
363 },
364 };
366 size_t i;
368 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
369 int check = sdb_data_cmp(&golden_data[i].d1, &golden_data[i].d2);
370 check = check < 0 ? -1 : check > 0 ? 1 : 0;
371 if (check != golden_data[i].expected) {
372 char d1_str[64] = "", d2_str[64] = "";
373 sdb_data_format(&golden_data[i].d1, d1_str, sizeof(d1_str),
374 SDB_DOUBLE_QUOTED);
375 sdb_data_format(&golden_data[i].d2, d2_str, sizeof(d2_str),
376 SDB_DOUBLE_QUOTED);
377 fail("sdb_data_cmp(%s, %s) = %d; expected: %d",
378 d1_str, d2_str, check, golden_data[i].expected);
379 }
380 }
381 }
382 END_TEST
384 START_TEST(test_strcmp)
385 {
386 struct {
387 sdb_data_t d1;
388 sdb_data_t d2;
389 int expected;
390 } golden_data[] = {
391 /* same data as for the sdb_data_cmp test; in case the types match,
392 * both functions should behave the same (except for some loss in
393 * precision, e.g. when formatting datetime values) */
394 {
395 { SDB_TYPE_INTEGER, { .integer = 47 } },
396 { SDB_TYPE_INTEGER, { .integer = 4711 } },
397 -1,
398 },
399 {
400 { SDB_TYPE_INTEGER, { .integer = 4711 } },
401 { SDB_TYPE_INTEGER, { .integer = 4711 } },
402 0,
403 },
404 {
405 { SDB_TYPE_INTEGER, { .integer = 4711 } },
406 { SDB_TYPE_INTEGER, { .integer = 47 } },
407 1,
408 },
409 {
410 { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } },
411 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
412 -1,
413 },
414 {
415 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
416 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
417 0,
418 },
419 {
420 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
421 { SDB_TYPE_DECIMAL, { .decimal = 65535.9 } },
422 1,
423 },
424 {
425 { SDB_TYPE_STRING, { .string = NULL } },
426 { SDB_TYPE_STRING, { .string = "" } },
427 -1,
428 },
429 {
430 { SDB_TYPE_STRING, { .string = NULL } },
431 { SDB_TYPE_STRING, { .string = NULL } },
432 0,
433 },
434 {
435 { SDB_TYPE_STRING, { .string = "" } },
436 { SDB_TYPE_STRING, { .string = NULL } },
437 1,
438 },
439 {
440 { SDB_TYPE_STRING, { .string = "a" } },
441 { SDB_TYPE_STRING, { .string = "b" } },
442 -1,
443 },
444 {
445 { SDB_TYPE_STRING, { .string = "a" } },
446 { SDB_TYPE_STRING, { .string = "ab" } },
447 -1,
448 },
449 {
450 { SDB_TYPE_STRING, { .string = "a" } },
451 { SDB_TYPE_STRING, { .string = "a" } },
452 0,
453 },
454 {
455 { SDB_TYPE_STRING, { .string = "b" } },
456 { SDB_TYPE_STRING, { .string = "a" } },
457 1,
458 },
459 {
460 { SDB_TYPE_STRING, { .string = "ab" } },
461 { SDB_TYPE_STRING, { .string = "a" } },
462 1,
463 },
464 {
465 { SDB_TYPE_DATETIME, { .datetime = 471047114711471100 } },
466 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
467 -1,
468 },
469 {
470 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
471 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
472 0,
473 },
474 {
475 { SDB_TYPE_DATETIME, { .datetime = 471147114711471100 } },
476 { SDB_TYPE_DATETIME, { .datetime = 471047114711471100 } },
477 1,
478 },
479 {
480 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
481 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
482 -1,
483 },
484 {
485 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
486 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
487 0,
488 },
489 {
490 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
491 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
492 1,
493 },
494 {
495 {
496 SDB_TYPE_BINARY,
497 { .binary = { 3, (unsigned char *)"a\0a" } },
498 },
499 {
500 SDB_TYPE_BINARY,
501 { .binary = { 3, (unsigned char *)"a\0b" } },
502 },
503 -1,
504 },
505 {
506 {
507 SDB_TYPE_BINARY,
508 { .binary = { 1, (unsigned char *)"a" } },
509 },
510 {
511 SDB_TYPE_BINARY,
512 { .binary = { 3, (unsigned char *)"a\0\0" } },
513 },
514 -1,
515 },
516 {
517 {
518 SDB_TYPE_BINARY,
519 { .binary = { 3, (unsigned char *)"a\0a" } },
520 },
521 {
522 SDB_TYPE_BINARY,
523 { .binary = { 3, (unsigned char *)"a\0a" } },
524 },
525 0,
526 },
527 {
528 {
529 SDB_TYPE_BINARY,
530 { .binary = { 3, (unsigned char *)"a\0b" } },
531 },
532 {
533 SDB_TYPE_BINARY,
534 { .binary = { 3, (unsigned char *)"a\0a" } },
535 },
536 1,
537 },
538 {
539 {
540 SDB_TYPE_BINARY,
541 { .binary = { 3, (unsigned char *)"a\0\0" } },
542 },
543 {
544 SDB_TYPE_BINARY,
545 { .binary = { 1, (unsigned char *)"a" } },
546 },
547 1,
548 },
549 {
550 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
551 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
552 0,
553 },
554 {
555 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
556 { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
557 -1,
558 },
559 {
560 { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
561 { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
562 1,
563 },
564 /* type mismatches */
565 {
566 { SDB_TYPE_INTEGER, { .integer = 123 } },
567 { SDB_TYPE_STRING, { .string = "123" } },
568 0,
569 },
570 {
571 { SDB_TYPE_INTEGER, { .integer = 120 } },
572 { SDB_TYPE_STRING, { .string = "123" } },
573 -1,
574 },
575 {
576 { SDB_TYPE_STRING, { .string = "123" } },
577 { SDB_TYPE_INTEGER, { .integer = 120 } },
578 1,
579 },
580 {
581 { SDB_TYPE_STRING, { .string = "12.3" } },
582 { SDB_TYPE_DECIMAL, { .decimal = 12.3 } },
583 0,
584 },
585 {
586 { SDB_TYPE_STRING, { .string = "12.0" } },
587 { SDB_TYPE_DECIMAL, { .decimal = 12.3 } },
588 -1,
589 },
590 {
591 { SDB_TYPE_DECIMAL, { .decimal = 12.3 } },
592 { SDB_TYPE_STRING, { .string = "12.0" } },
593 1,
594 },
595 {
596 { SDB_TYPE_REGEX, { .re = { "regex", empty_re } } },
597 { SDB_TYPE_STRING, { .string = "/regex/" } },
598 0,
599 },
600 };
602 size_t i;
604 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
605 int check = sdb_data_strcmp(&golden_data[i].d1, &golden_data[i].d2);
606 check = check < 0 ? -1 : check > 0 ? 1 : 0;
607 if (check != golden_data[i].expected) {
608 char d1_str[64] = "", d2_str[64] = "";
609 sdb_data_format(&golden_data[i].d1, d1_str, sizeof(d1_str),
610 SDB_DOUBLE_QUOTED);
611 sdb_data_format(&golden_data[i].d2, d2_str, sizeof(d2_str),
612 SDB_DOUBLE_QUOTED);
613 fail("sdb_data_strcmp(%s, %s) = %d; expected: %d",
614 d1_str, d2_str, check, golden_data[i].expected);
615 }
616 }
617 }
618 END_TEST
620 START_TEST(test_expr_eval)
621 {
622 struct {
623 sdb_data_t d1;
624 sdb_data_t d2;
625 sdb_data_t expected_add;
626 sdb_data_t expected_sub;
627 sdb_data_t expected_mul;
628 sdb_data_t expected_div;
629 sdb_data_t expected_mod;
630 sdb_data_t expected_concat;
631 } golden_data[] = {
632 {
633 { SDB_TYPE_INTEGER, { .integer = 4711 } },
634 { SDB_TYPE_INTEGER, { .integer = 47 } },
635 { SDB_TYPE_INTEGER, { .integer = 4758 } },
636 { SDB_TYPE_INTEGER, { .integer = 4664 } },
637 { SDB_TYPE_INTEGER, { .integer = 221417 } },
638 { SDB_TYPE_INTEGER, { .integer = 100 } },
639 { SDB_TYPE_INTEGER, { .integer = 11 } },
640 SDB_DATA_INIT,
641 },
642 {
643 { SDB_TYPE_DECIMAL, { .decimal = 35.0 } },
644 { SDB_TYPE_DECIMAL, { .decimal = 17.5 } },
645 { SDB_TYPE_DECIMAL, { .decimal = 52.5 } },
646 { SDB_TYPE_DECIMAL, { .decimal = 17.5 } },
647 { SDB_TYPE_DECIMAL, { .decimal = 612.5 } },
648 { SDB_TYPE_DECIMAL, { .decimal = 2.0 } },
649 { SDB_TYPE_DECIMAL, { .decimal = 0.0 } },
650 SDB_DATA_INIT,
651 },
652 {
653 { SDB_TYPE_STRING, { .string = NULL } },
654 { SDB_TYPE_STRING, { .string = "" } },
655 SDB_DATA_INIT,
656 SDB_DATA_INIT,
657 SDB_DATA_INIT,
658 SDB_DATA_INIT,
659 SDB_DATA_INIT,
660 { SDB_TYPE_STRING, { .string = "" } },
661 },
662 {
663 { SDB_TYPE_STRING, { .string = NULL } },
664 { SDB_TYPE_STRING, { .string = NULL } },
665 SDB_DATA_INIT,
666 SDB_DATA_INIT,
667 SDB_DATA_INIT,
668 SDB_DATA_INIT,
669 SDB_DATA_INIT,
670 { SDB_TYPE_STRING, { .string = NULL } },
671 },
672 {
673 { SDB_TYPE_STRING, { .string = "" } },
674 { SDB_TYPE_STRING, { .string = NULL } },
675 SDB_DATA_INIT,
676 SDB_DATA_INIT,
677 SDB_DATA_INIT,
678 SDB_DATA_INIT,
679 SDB_DATA_INIT,
680 { SDB_TYPE_STRING, { .string = "" } },
681 },
682 {
683 { SDB_TYPE_STRING, { .string = "a" } },
684 { SDB_TYPE_STRING, { .string = "b" } },
685 SDB_DATA_INIT,
686 SDB_DATA_INIT,
687 SDB_DATA_INIT,
688 SDB_DATA_INIT,
689 SDB_DATA_INIT,
690 { SDB_TYPE_STRING, { .string = "ab" } },
691 },
692 {
693 { SDB_TYPE_DATETIME, { .datetime = 47114711 } },
694 { SDB_TYPE_DATETIME, { .datetime = 4711 } },
695 { SDB_TYPE_DATETIME, { .datetime = 47119422 } },
696 { SDB_TYPE_DATETIME, { .datetime = 47110000 } },
697 { SDB_TYPE_DATETIME, { .datetime = 221957403521 } },
698 { SDB_TYPE_DATETIME, { .datetime = 10001 } },
699 { SDB_TYPE_DATETIME, { .datetime = 0 } },
700 SDB_DATA_INIT,
701 },
702 {
703 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
704 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
705 SDB_DATA_INIT,
706 SDB_DATA_INIT,
707 SDB_DATA_INIT,
708 SDB_DATA_INIT,
709 SDB_DATA_INIT,
710 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
711 },
712 {
713 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
714 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
715 SDB_DATA_INIT,
716 SDB_DATA_INIT,
717 SDB_DATA_INIT,
718 SDB_DATA_INIT,
719 SDB_DATA_INIT,
720 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
721 },
722 {
723 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
724 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
725 SDB_DATA_INIT,
726 SDB_DATA_INIT,
727 SDB_DATA_INIT,
728 SDB_DATA_INIT,
729 SDB_DATA_INIT,
730 { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } },
731 },
732 {
733 {
734 SDB_TYPE_BINARY,
735 { .binary = { 3, (unsigned char *)"a\0a" } },
736 },
737 {
738 SDB_TYPE_BINARY,
739 { .binary = { 3, (unsigned char *)"b\0b" } },
740 },
741 SDB_DATA_INIT,
742 SDB_DATA_INIT,
743 SDB_DATA_INIT,
744 SDB_DATA_INIT,
745 SDB_DATA_INIT,
746 {
747 SDB_TYPE_BINARY,
748 { .binary = { 6, (unsigned char *)"a\0ab\0b" } },
749 },
750 },
751 {
752 { SDB_TYPE_REGEX, { .re = { ".", empty_re } } },
753 { SDB_TYPE_REGEX, { .re = { ".", empty_re } } },
754 SDB_DATA_INIT,
755 SDB_DATA_INIT,
756 SDB_DATA_INIT,
757 SDB_DATA_INIT,
758 SDB_DATA_INIT,
759 SDB_DATA_INIT,
760 },
761 /* supported type-mismatches */
762 {
763 /* int * datetime */
764 { SDB_TYPE_INTEGER, { .integer = 20 } },
765 { SDB_TYPE_DATETIME, { .datetime = 2 } },
766 SDB_DATA_INIT,
767 SDB_DATA_INIT,
768 { SDB_TYPE_DATETIME, { .datetime = 40 } },
769 SDB_DATA_INIT,
770 SDB_DATA_INIT,
771 SDB_DATA_INIT,
772 },
773 {
774 /* datetime * int, datetime / int, datetime % int */
775 { SDB_TYPE_DATETIME, { .datetime = 20 } },
776 { SDB_TYPE_INTEGER, { .integer = 2 } },
777 SDB_DATA_INIT,
778 SDB_DATA_INIT,
779 { SDB_TYPE_DATETIME, { .datetime = 40 } },
780 { SDB_TYPE_DATETIME, { .datetime = 10 } },
781 { SDB_TYPE_DATETIME, { .datetime = 0 } },
782 SDB_DATA_INIT,
783 },
784 {
785 /* float * datetime */
786 { SDB_TYPE_DECIMAL, { .decimal = 20.0 } },
787 { SDB_TYPE_DATETIME, { .datetime = 2 } },
788 SDB_DATA_INIT,
789 SDB_DATA_INIT,
790 { SDB_TYPE_DATETIME, { .datetime = 40 } },
791 SDB_DATA_INIT,
792 SDB_DATA_INIT,
793 SDB_DATA_INIT,
794 },
795 {
796 /* datetime * float, datetime / float, datetime % float */
797 { SDB_TYPE_DATETIME, { .datetime = 20 } },
798 { SDB_TYPE_DECIMAL, { .decimal = 2.0 } },
799 SDB_DATA_INIT,
800 SDB_DATA_INIT,
801 { SDB_TYPE_DATETIME, { .datetime = 40 } },
802 { SDB_TYPE_DATETIME, { .datetime = 10 } },
803 { SDB_TYPE_DATETIME, { .datetime = 0 } },
804 SDB_DATA_INIT,
805 },
806 };
808 size_t i;
810 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
811 struct {
812 int op;
813 sdb_data_t expected;
814 } tests[] = {
815 { SDB_DATA_ADD, golden_data[i].expected_add },
816 { SDB_DATA_SUB, golden_data[i].expected_sub },
817 { SDB_DATA_MUL, golden_data[i].expected_mul },
818 { SDB_DATA_DIV, golden_data[i].expected_div },
819 { SDB_DATA_MOD, golden_data[i].expected_mod },
820 { SDB_DATA_CONCAT, golden_data[i].expected_concat },
821 };
823 size_t j;
824 for (j = 0; j < SDB_STATIC_ARRAY_LEN(tests); ++j) {
825 sdb_data_t res;
826 int check;
828 char d1_str[64] = "", d2_str[64] = "";
829 sdb_data_format(&golden_data[i].d1, d1_str, sizeof(d1_str),
830 SDB_DOUBLE_QUOTED);
831 sdb_data_format(&golden_data[i].d2, d2_str, sizeof(d2_str),
832 SDB_DOUBLE_QUOTED);
834 check = sdb_data_expr_eval(tests[j].op,
835 &golden_data[i].d1, &golden_data[i].d2, &res);
836 fail_unless((check == 0) == (tests[j].expected.type != 0),
837 "sdb_data_expr_eval(%s, %s, %s) = %d; expected: %d",
838 SDB_DATA_OP_TO_STRING(tests[j].op), d1_str, d2_str, check,
839 tests[j].expected.type == 0 ? -1 : 0);
840 if (tests[j].expected.type == 0)
841 continue;
843 check = sdb_data_cmp(&res, &tests[j].expected);
844 if (check != 0) {
845 char res_str[64] = "", expected_str[64] = "";
846 sdb_data_format(&res, res_str, sizeof(res_str),
847 SDB_DOUBLE_QUOTED);
848 sdb_data_format(&tests[j].expected, expected_str,
849 sizeof(expected_str), SDB_DOUBLE_QUOTED);
850 fail("sdb_data_expr_eval(%s, %s, %s) evaluated to %s; "
851 "expected: %s", SDB_DATA_OP_TO_STRING(tests[j].op),
852 d1_str, d2_str, res_str, expected_str);
853 }
855 sdb_data_free_datum(&res);
856 }
857 }
858 }
859 END_TEST
861 START_TEST(test_format)
862 {
863 struct {
864 sdb_data_t datum;
865 const char *expected;
866 } golden_data[] = {
867 {
868 { SDB_TYPE_INTEGER, { .integer = 4711 } },
869 "4711",
870 },
871 {
872 { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } },
873 "65536",
874 },
875 {
876 { SDB_TYPE_DECIMAL, { .decimal = 12.3 } },
877 "12.3",
878 },
879 {
880 { SDB_TYPE_STRING, { .string = NULL } },
881 "\"<NULL>\"",
882 },
883 {
884 { SDB_TYPE_STRING, { .string = "this is a test" } },
885 "\"this is a test\"",
886 },
887 {
888 { SDB_TYPE_STRING, { .string = "special \\ \" characters" } },
889 "\"special \\\\ \\\" characters\"",
890 },
891 {
892 { SDB_TYPE_DATETIME, { .datetime= 471147114711471100 } },
893 "\"1984-12-06 02:11:54 +0000\"",
894 },
895 {
896 { SDB_TYPE_BINARY, { .binary = { 0, NULL } } },
897 "\"<NULL>\"",
898 },
899 {
900 {
901 SDB_TYPE_BINARY,
902 { .binary = { 12, (unsigned char *)"binary\0crap\x42" } },
903 },
904 "\"\\x62\\x69\\x6e\\x61\\x72\\x79\\x0\\x63\\x72\\x61\\x70\\x42\"",
905 },
906 {
907 { SDB_TYPE_REGEX, { .re = { "some regex", empty_re } } },
908 "\"/some regex/\"",
909 },
910 };
912 size_t i;
914 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
915 sdb_data_t *datum = &golden_data[i].datum;
916 char buf[sdb_data_strlen(datum) + 2];
917 int check;
919 memset(buf, (int)'A', sizeof(buf));
921 check = sdb_data_format(datum, buf, sizeof(buf) - 1,
922 SDB_DOUBLE_QUOTED);
923 fail_unless(check > 0,
924 "sdb_data_format(type=%s) = %d; expected: >0",
925 SDB_TYPE_TO_STRING(datum->type), check);
926 fail_unless(! strcmp(buf, golden_data[i].expected),
927 "sdb_data_format(type=%s) used wrong format: %s; expected: %s",
928 SDB_TYPE_TO_STRING(datum->type), buf, golden_data[i].expected);
930 fail_unless((size_t)check <= sizeof(buf) - 2,
931 "sdb_data_format(type=%s) wrote %d bytes; "
932 "expected <= %zu based on sdb_data_strlen()",
933 SDB_TYPE_TO_STRING(datum->type), check, sizeof(buf) - 2);
935 fail_unless(buf[sizeof(buf) - 2] == '\0',
936 "sdb_data_format(type=%s) did not nul-terminate the buffer",
937 SDB_TYPE_TO_STRING(datum->type));
938 fail_unless(buf[sizeof(buf) - 1] == 'A',
939 "sdb_data_format(type=%s) wrote past the end of the buffer",
940 SDB_TYPE_TO_STRING(datum->type));
941 }
942 }
943 END_TEST
945 START_TEST(test_parse)
946 {
947 struct {
948 char *input;
949 sdb_data_t result;
950 int expected;
951 } golden_data[] = {
952 { "4711", { SDB_TYPE_INTEGER, { .integer = 4711 } }, 0 },
953 { "0x10", { SDB_TYPE_INTEGER, { .integer = 16 } }, 0 },
954 { "010", { SDB_TYPE_INTEGER, { .integer = 8 } }, 0 },
955 { "abc", { SDB_TYPE_INTEGER, { .integer = 0 } }, -1 },
956 { "1.2", { SDB_TYPE_DECIMAL, { .decimal = 1.2 } }, 0 },
957 { "0x1p+16", { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, 0 },
958 { "abc", { SDB_TYPE_DECIMAL, { .decimal = 0.0 } }, -1 },
959 { "abc", { SDB_TYPE_STRING, { .string = "abc" } }, 0 },
960 { ".4", { SDB_TYPE_DATETIME, { .datetime = 400000000 } }, 0 },
961 { "abc", { SDB_TYPE_DATETIME, { .datetime = 0 } }, -1 },
962 { "abc", { SDB_TYPE_BINARY,
963 { .binary = { 3, (unsigned char *)"abc" } } }, 0 },
964 { "abc", { SDB_TYPE_REGEX, { .re = { "abc", empty_re } } }, 0 },
965 { "(|", { SDB_TYPE_REGEX, { .re = { "", empty_re } } }, -1 },
966 };
968 size_t i;
970 for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
971 sdb_data_t result;
972 int type, check;
974 memset(&result, 0, sizeof(result));
975 type = golden_data[i].result.type;
976 check = sdb_data_parse(golden_data[i].input, type, &result);
977 fail_unless(check == golden_data[i].expected,
978 "sdb_data_parse(%s, %d, <d>) = %d; expected: %d",
979 golden_data[i].input, type, check, golden_data[i].expected);
981 if (check)
982 continue;
984 fail_unless(sdb_data_cmp(&result, &golden_data[i].result) == 0,
985 "sdb_data_parse(%s, %d, <d>) did not create expected result",
986 golden_data[i].input, type);
988 if (type == SDB_TYPE_STRING)
989 fail_unless(golden_data[i].input == result.data.string,
990 "sdb_data_parse(%s, %d, <d>) modified input string",
991 golden_data[i].input, type);
992 if (type == SDB_TYPE_BINARY)
993 fail_unless(golden_data[i].input == (char *)result.data.binary.datum,
994 "sdb_data_parse(%s, %d, <d>) modified input string",
995 golden_data[i].input, type);
996 if (type == SDB_TYPE_REGEX) {
997 fail_unless(golden_data[i].input != result.data.re.raw,
998 "sdb_data_parse(%s, %d, <d>) copied input string",
999 golden_data[i].input, type);
1000 sdb_data_free_datum(&result);
1001 }
1002 }
1003 }
1004 END_TEST
1006 Suite *
1007 core_data_suite(void)
1008 {
1009 Suite *s = suite_create("core::data");
1010 TCase *tc;
1012 tc = tcase_create("core");
1013 tcase_add_test(tc, test_data);
1014 tcase_add_test(tc, test_cmp);
1015 tcase_add_test(tc, test_strcmp);
1016 tcase_add_test(tc, test_expr_eval);
1017 tcase_add_test(tc, test_format);
1018 tcase_add_test(tc, test_parse);
1019 suite_add_tcase(s, tc);
1021 return s;
1022 } /* core_data_suite */
1024 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */