1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to you under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 */
17
18 /* Test cases for the new avro_value_t interface */
19
20 #include <limits.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24
25 #include "avro.h"
26 #include "avro_private.h"
27
28 typedef int (*avro_test) (void);
29
30 #ifndef SHOW_ALLOCATIONS
31 #define SHOW_ALLOCATIONS 0
32 #endif
33
34 /*
35 * Use a custom allocator that verifies that the size that we use to
36 * free an object matches the size that we use to allocate it.
37 */
38
39 static void *
test_allocator(void * ud,void * ptr,size_t osize,size_t nsize)40 test_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
41 {
42 AVRO_UNUSED(ud);
43 AVRO_UNUSED(osize);
44
45 #if SHOW_ALLOCATIONS
46 fprintf(stderr, "alloc(%p, %" PRIsz ", %" PRIsz ") => ", ptr, osize, nsize);
47 #endif
48
49 if (nsize == 0) {
50 size_t *size = ((size_t *) ptr) - 1;
51 if (osize != *size) {
52 fprintf(stderr,
53 #if SHOW_ALLOCATIONS
54 "ERROR!\n"
55 #endif
56 "Error freeing %p:\n"
57 "Size passed to avro_free (%" PRIsz ") "
58 "doesn't match size passed to "
59 "avro_malloc (%" PRIsz ")\n",
60 ptr, osize, *size);
61 exit(EXIT_FAILURE);
62 }
63 free(size);
64 #if SHOW_ALLOCATIONS
65 fprintf(stderr, "NULL\n");
66 #endif
67 return NULL;
68 } else {
69 size_t real_size = nsize + sizeof(size_t);
70 size_t *old_size = ptr? ((size_t *) ptr)-1: NULL;
71 size_t *size = (size_t *) realloc(old_size, real_size);
72 *size = nsize;
73 #if SHOW_ALLOCATIONS
74 fprintf(stderr, "%p\n", (size+1));
75 #endif
76 return (size + 1);
77 }
78 }
79
80 void
init_rand(void)81 init_rand(void)
82 {
83 srand(time(NULL));
84 }
85
86 double
rand_number(double from,double to)87 rand_number(double from, double to)
88 {
89 double range = to - from;
90 return from + ((double)rand() / (RAND_MAX + 1.0)) * range;
91 }
92
93 int64_t
rand_int64(void)94 rand_int64(void)
95 {
96 return (int64_t) rand_number(LONG_MIN, LONG_MAX);
97 }
98
99 int32_t
rand_int32(void)100 rand_int32(void)
101 {
102 return (int32_t) rand_number(INT_MIN, INT_MAX);
103 }
104
105 size_t
rand_count(void)106 rand_count(void)
107 {
108 return (size_t) rand_number(0, 100);
109 }
110
111 #define check_(call) \
112 do { \
113 int _rval = call; \
114 if (_rval) { return _rval; } \
115 } while (0)
116
117 /*
118 * Verify that we can't call any of the getters and setters that don't
119 * apply to the given value.
120 */
121
122 static int
_check_invalid_methods(const char * name,avro_value_t * val)123 _check_invalid_methods(const char *name, avro_value_t *val)
124 {
125 avro_type_t type = avro_value_get_type(val);
126
127 /* For a description on GCC vs Visual Studio 2008 usage of variadic
128 * macros see:
129 * https://stackoverflow.com/questions/2575864/the-problem-about-different
130 * -treatment-to-va-args-when-using-vs-2008-and-gcc
131 */
132 #define expand_args(...) __VA_ARGS__
133 #define check_bad(method, ...) \
134 do { \
135 if (!expand_args(avro_value_##method(__VA_ARGS__))) { \
136 fprintf(stderr, \
137 "Shouldn't be able to " #method " a %s\n", \
138 name); \
139 return EXIT_FAILURE; \
140 } \
141 } while (0)
142
143 if (type != AVRO_BOOLEAN) {
144 int dummy = 0;
145 check_bad(get_boolean, val, &dummy);
146 check_bad(set_boolean, val, dummy);
147 }
148
149 if (type != AVRO_BYTES) {
150 const void *cbuf = NULL;
151 void *buf = NULL;
152 size_t size = 0;
153 check_bad(get_bytes, val, &cbuf, &size);
154 check_bad(set_bytes, val, buf, size);
155 }
156
157 if (type != AVRO_DOUBLE) {
158 double dummy = 0;
159 check_bad(get_double, val, &dummy);
160 check_bad(set_double, val, dummy);
161 }
162
163 if (type != AVRO_FLOAT) {
164 float dummy = 0;
165 check_bad(get_float, val, &dummy);
166 check_bad(set_float, val, dummy);
167 }
168
169 if (type != AVRO_INT32) {
170 int32_t dummy = 0;
171 check_bad(get_int, val, &dummy);
172 check_bad(set_int, val, dummy);
173 }
174
175 if (type != AVRO_INT64) {
176 int64_t dummy = 0;
177 check_bad(get_long, val, &dummy);
178 check_bad(set_long, val, dummy);
179 }
180
181 if (type != AVRO_NULL) {
182 check_bad(get_null, val);
183 check_bad(set_null, val);
184 }
185
186 if (type != AVRO_STRING) {
187 const char *cstr = NULL;
188 char *str = NULL;
189 size_t size = 0;
190 check_bad(get_string, val, &cstr, &size);
191 check_bad(set_string, val, str);
192 check_bad(set_string_len, val, str, size);
193 }
194
195 if (type != AVRO_ENUM) {
196 int dummy = 0;
197 check_bad(get_enum, val, &dummy);
198 check_bad(set_enum, val, dummy);
199 }
200
201 if (type != AVRO_FIXED) {
202 const void *cbuf = NULL;
203 void *buf = NULL;
204 size_t size = 0;
205 check_bad(get_fixed, val, &cbuf, &size);
206 check_bad(set_fixed, val, buf, size);
207 }
208
209 if (type != AVRO_ARRAY && type != AVRO_MAP && type != AVRO_RECORD) {
210 size_t size = 0;
211 check_bad(get_size, val, &size);
212
213 size_t index = 0;
214 avro_value_t child;
215 const char *key = NULL;
216 check_bad(get_by_index, val, index, &child, &key);
217 }
218
219 if (type != AVRO_MAP && type != AVRO_RECORD) {
220 const char *key = NULL;
221 avro_value_t child;
222 size_t index = 0;
223 check_bad(get_by_name, val, key, &child, &index);
224 }
225
226 if (type != AVRO_ARRAY) {
227 avro_value_t child;
228 size_t index;
229 check_bad(append, val, &child, &index);
230 }
231
232 if (type != AVRO_MAP) {
233 const char *key = NULL;
234 avro_value_t child;
235 size_t index = 0;
236 int is_new = 0;
237 check_bad(add, val, key, &child, &index, &is_new);
238 }
239
240 if (type != AVRO_UNION) {
241 int discriminant = 0;
242 avro_value_t branch;
243 check_bad(get_discriminant, val, &discriminant);
244 check_bad(get_current_branch, val, &branch);
245 check_bad(set_branch, val, discriminant, &branch);
246 }
247
248 #undef check_bad
249
250 return EXIT_SUCCESS;
251 }
252
253 #define check_invalid_methods(name, val) \
254 check_(_check_invalid_methods(name, val))
255
256 /*
257 * Verify that we get the expected type code and schema for a value.
258 */
259
260 static int
check_type_and_schema(const char * name,avro_value_t * val,avro_type_t expected_type,avro_schema_t expected_schema)261 check_type_and_schema(const char *name,
262 avro_value_t *val,
263 avro_type_t expected_type,
264 avro_schema_t expected_schema)
265 {
266 if (avro_value_get_type(val) != expected_type) {
267 avro_schema_decref(expected_schema);
268 fprintf(stderr, "Unexpected type for %s\n", name);
269 return EXIT_FAILURE;
270 }
271
272 if (!avro_schema_equal(avro_value_get_schema(val),
273 expected_schema)) {
274 avro_schema_decref(expected_schema);
275 fprintf(stderr, "Unexpected schema for %s\n", name);
276 return EXIT_FAILURE;
277 }
278
279 avro_schema_decref(expected_schema);
280 return EXIT_SUCCESS;
281 }
282
283 #define try(call, msg) \
284 do { \
285 if (call) { \
286 fprintf(stderr, msg ":\n %s\n", avro_strerror()); \
287 return EXIT_FAILURE; \
288 } \
289 } while (0)
290
291 static int
_check_write_read(avro_value_t * val)292 _check_write_read(avro_value_t *val)
293 {
294 static char buf[4096];
295
296 avro_reader_t reader = avro_reader_memory(buf, sizeof(buf));
297 avro_writer_t writer = avro_writer_memory(buf, sizeof(buf));
298
299 if (avro_value_write(writer, val)) {
300 fprintf(stderr, "Unable to write value:\n %s\n",
301 avro_strerror());
302 return EXIT_FAILURE;
303 }
304
305 avro_writer_dump(writer, stderr);
306
307 size_t size;
308 if (avro_value_sizeof(val, &size)) {
309 fprintf(stderr, "Unable to determine size of value:\n %s\n",
310 avro_strerror());
311 return EXIT_FAILURE;
312 }
313
314 if (size != (size_t) avro_writer_tell(writer)) {
315 fprintf(stderr, "Unexpected size of encoded value\n");
316 return EXIT_FAILURE;
317 }
318
319 avro_value_t val_in;
320 if (avro_generic_value_new(val->iface, &val_in)) {
321 fprintf(stderr, "Cannot allocate new value instance:\n %s\n",
322 avro_strerror());
323 return EXIT_FAILURE;
324 }
325
326 if (avro_value_read(reader, &val_in)) {
327 fprintf(stderr, "Unable to read value:\n %s\n",
328 avro_strerror());
329 return EXIT_FAILURE;
330 }
331
332 if (!avro_value_equal(val, &val_in)) {
333 fprintf(stderr, "Round-trip values not equal\n");
334 exit(EXIT_FAILURE);
335 }
336
337 avro_value_decref(&val_in);
338 avro_reader_free(reader);
339 avro_writer_free(writer);
340
341 return EXIT_SUCCESS;
342 }
343
344 #define check_write_read(val) \
345 check_(_check_write_read(val))
346
347 static int
_check_hash(avro_value_t * val1,avro_value_t * val2)348 _check_hash(avro_value_t *val1, avro_value_t *val2)
349 {
350 uint32_t hash1 = avro_value_hash(val1);
351 uint32_t hash2 = avro_value_hash(val2);
352 if (hash1 != hash2) {
353 fprintf(stderr, "Copied hashed not equal\n");
354 return EXIT_FAILURE;
355 }
356 return EXIT_SUCCESS;
357 }
358
359 #define check_hash(val1, val2) \
360 check_(_check_hash(val1, val2))
361
362 static int
_check_copy(avro_value_t * val)363 _check_copy(avro_value_t *val)
364 {
365 avro_value_t copied_val;
366 if (avro_generic_value_new(val->iface, &copied_val)) {
367 fprintf(stderr, "Cannot allocate new value instance:\n %s\n",
368 avro_strerror());
369 return EXIT_FAILURE;
370 }
371
372 if (avro_value_copy_fast(&copied_val, val)) {
373 fprintf(stderr, "Cannot copy value:\n %s\n",
374 avro_strerror());
375 return EXIT_FAILURE;
376 }
377
378 if (!avro_value_equal(val, &copied_val)) {
379 fprintf(stderr, "Copied values not equal\n");
380 return EXIT_FAILURE;
381 }
382
383 check_hash(val, &copied_val);
384
385 avro_value_decref(&copied_val);
386 return EXIT_SUCCESS;
387 }
388
389 #define check_copy(val) \
390 check_(_check_copy(val))
391
392 static int
test_boolean(void)393 test_boolean(void)
394 {
395 int rval;
396
397 int i;
398 for (i = 0; i <= 1; i++) {
399 avro_value_t val;
400 try(avro_generic_boolean_new(&val, i),
401 "Cannot create boolean");
402 check(rval, check_type_and_schema
403 ("boolean", &val,
404 AVRO_BOOLEAN, avro_schema_boolean()));
405 try(avro_value_reset(&val),
406 "Cannot reset boolean");
407 try(avro_value_set_boolean(&val, i),
408 "Cannot set boolean");
409
410 /* Start with the wrong value to make sure _get does
411 * something. */
412 int actual = (int) 23;
413 try(avro_value_get_boolean(&val, &actual),
414 "Cannot get boolean value");
415
416 if (actual != i) {
417 fprintf(stderr, "Unexpected boolean value\n");
418 return EXIT_FAILURE;
419 }
420
421 check_invalid_methods("boolean", &val);
422 check_write_read(&val);
423 check_copy(&val);
424 avro_value_decref(&val);
425 }
426
427 avro_value_t val1;
428 avro_value_t val2;
429 try(avro_generic_boolean_new(&val1, 0),
430 "Cannot create boolean");
431 try(avro_generic_boolean_new(&val2, 1),
432 "Cannot create boolean");
433 if (avro_value_cmp_fast(&val1, &val2) >= 0) {
434 fprintf(stderr, "Incorrect sort order\n");
435 return EXIT_FAILURE;
436 }
437 if (avro_value_cmp_fast(&val2, &val1) <= 0) {
438 fprintf(stderr, "Incorrect sort order\n");
439 return EXIT_FAILURE;
440 }
441 if (avro_value_cmp_fast(&val1, &val1) != 0) {
442 fprintf(stderr, "Incorrect sort order\n");
443 return EXIT_FAILURE;
444 }
445 avro_value_decref(&val1);
446 avro_value_decref(&val2);
447
448 return 0;
449 }
450
451 static int
test_bytes(void)452 test_bytes(void)
453 {
454 int rval;
455
456 char bytes[] = { 0xDE, 0xAD, 0xBE, 0xEF };
457
458 avro_value_t val;
459 try(avro_generic_bytes_new(&val, bytes, sizeof(bytes)),
460 "Cannot create bytes");
461 check(rval, check_type_and_schema
462 ("bytes", &val,
463 AVRO_BYTES, avro_schema_bytes()));
464 try(avro_value_reset(&val),
465 "Cannot reset bytes");
466 try(avro_value_set_bytes(&val, bytes, sizeof(bytes)),
467 "Cannot set bytes");
468
469 const void *actual_buf = NULL;
470 size_t actual_size = 0;
471 try(avro_value_get_bytes(&val, &actual_buf, &actual_size),
472 "Cannot get bytes value");
473
474 if (actual_size != sizeof(bytes)) {
475 fprintf(stderr, "Unexpected bytes size\n");
476 return EXIT_FAILURE;
477 }
478
479 if (memcmp(actual_buf, bytes, sizeof(bytes)) != 0) {
480 fprintf(stderr, "Unexpected bytes contents\n");
481 return EXIT_FAILURE;
482 }
483
484 avro_wrapped_buffer_t wbuf;
485 try(avro_value_grab_bytes(&val, &wbuf),
486 "Cannot grab bytes value");
487
488 if (wbuf.size != sizeof(bytes)) {
489 fprintf(stderr, "Unexpected grabbed bytes size\n");
490 return EXIT_FAILURE;
491 }
492
493 if (memcmp(wbuf.buf, bytes, sizeof(bytes)) != 0) {
494 fprintf(stderr, "Unexpected grabbed bytes contents\n");
495 return EXIT_FAILURE;
496 }
497
498 avro_wrapped_buffer_free(&wbuf);
499
500 check_invalid_methods("bytes", &val);
501 check_write_read(&val);
502 check_copy(&val);
503 avro_value_decref(&val);
504
505 avro_value_t val1;
506 avro_value_t val2;
507 avro_value_t val3;
508 try(avro_generic_bytes_new(&val1, "abcd", 4),
509 "Cannot create bytes");
510 try(avro_generic_bytes_new(&val2, "abcde", 5),
511 "Cannot create bytes");
512 try(avro_generic_bytes_new(&val3, "abce", 4),
513 "Cannot create bytes");
514 if (avro_value_cmp_fast(&val1, &val2) >= 0) {
515 fprintf(stderr, "Incorrect sort order\n");
516 return EXIT_FAILURE;
517 }
518 if (avro_value_cmp_fast(&val2, &val1) <= 0) {
519 fprintf(stderr, "Incorrect sort order\n");
520 return EXIT_FAILURE;
521 }
522 if (avro_value_cmp_fast(&val1, &val3) >= 0) {
523 fprintf(stderr, "Incorrect sort order\n");
524 return EXIT_FAILURE;
525 }
526 if (avro_value_cmp_fast(&val1, &val1) != 0) {
527 fprintf(stderr, "Incorrect sort order\n");
528 return EXIT_FAILURE;
529 }
530 avro_value_decref(&val1);
531 avro_value_decref(&val2);
532 avro_value_decref(&val3);
533
534 return 0;
535 }
536
537 static int
test_double(void)538 test_double(void)
539 {
540 int rval;
541
542 int i;
543 for (i = 0; i < 100; i++) {
544 double expected = rand_number(-1e10, 1e10);
545 avro_value_t val;
546 try(avro_generic_double_new(&val, expected),
547 "Cannot create double");
548 check(rval, check_type_and_schema
549 ("double", &val,
550 AVRO_DOUBLE, avro_schema_double()));
551 try(avro_value_reset(&val),
552 "Cannot reset double");
553 try(avro_value_set_double(&val, expected),
554 "Cannot set double");
555
556 double actual = 0.0;
557 try(avro_value_get_double(&val, &actual),
558 "Cannot get double value");
559
560 if (actual != expected) {
561 fprintf(stderr, "Unexpected double value\n");
562 return EXIT_FAILURE;
563 }
564
565 check_invalid_methods("double", &val);
566 check_write_read(&val);
567 check_copy(&val);
568 avro_value_decref(&val);
569 }
570 return 0;
571 }
572
573 static int
test_float(void)574 test_float(void)
575 {
576 int rval;
577
578 int i;
579 for (i = 0; i < 100; i++) {
580 float expected = rand_number(-1e10, 1e10);
581 avro_value_t val;
582 try(avro_generic_float_new(&val, expected),
583 "Cannot create float");
584 check(rval, check_type_and_schema
585 ("float", &val,
586 AVRO_FLOAT, avro_schema_float()));
587 try(avro_value_reset(&val),
588 "Cannot reset float");
589 try(avro_value_set_float(&val, expected),
590 "Cannot set float");
591
592 float actual = 0.0f;
593 try(avro_value_get_float(&val, &actual),
594 "Cannot get float value");
595
596 if (actual != expected) {
597 fprintf(stderr, "Unexpected float value\n");
598 return EXIT_FAILURE;
599 }
600
601 check_invalid_methods("float", &val);
602 check_write_read(&val);
603 check_copy(&val);
604 avro_value_decref(&val);
605 }
606 return 0;
607 }
608
609 static int
test_int(void)610 test_int(void)
611 {
612 int rval;
613
614 int i;
615 for (i = 0; i < 100; i++) {
616 int32_t expected = rand_int32();
617 avro_value_t val;
618 try(avro_generic_int_new(&val, expected),
619 "Cannot create int");
620 check(rval, check_type_and_schema
621 ("int", &val,
622 AVRO_INT32, avro_schema_int()));
623 try(avro_value_reset(&val),
624 "Cannot reset int");
625 try(avro_value_set_int(&val, expected),
626 "Cannot set int");
627
628 int32_t actual = 0;
629 try(avro_value_get_int(&val, &actual),
630 "Cannot get int value");
631
632 if (actual != expected) {
633 fprintf(stderr, "Unexpected int value\n");
634 return EXIT_FAILURE;
635 }
636
637 check_invalid_methods("int", &val);
638 check_write_read(&val);
639 check_copy(&val);
640 avro_value_decref(&val);
641 }
642
643 avro_value_t val1;
644 avro_value_t val2;
645 try(avro_generic_int_new(&val1, -10),
646 "Cannot create int");
647 try(avro_generic_int_new(&val2, 42),
648 "Cannot create int");
649 if (avro_value_cmp_fast(&val1, &val2) >= 0) {
650 fprintf(stderr, "Incorrect sort order\n");
651 return EXIT_FAILURE;
652 }
653 if (avro_value_cmp_fast(&val2, &val1) <= 0) {
654 fprintf(stderr, "Incorrect sort order\n");
655 return EXIT_FAILURE;
656 }
657 if (avro_value_cmp_fast(&val1, &val1) != 0) {
658 fprintf(stderr, "Incorrect sort order\n");
659 return EXIT_FAILURE;
660 }
661 avro_value_decref(&val1);
662 avro_value_decref(&val2);
663
664 return 0;
665 }
666
667 static int
test_long(void)668 test_long(void)
669 {
670 int rval;
671
672 int i;
673 for (i = 0; i < 100; i++) {
674 int64_t expected = rand_int64();
675 avro_value_t val;
676 try(avro_generic_long_new(&val, expected),
677 "Cannot create long");
678 check(rval, check_type_and_schema
679 ("long", &val,
680 AVRO_INT64, avro_schema_long()));
681 try(avro_value_reset(&val),
682 "Cannot reset long");
683 try(avro_value_set_long(&val, expected),
684 "Cannot set long");
685
686 int64_t actual = 0;
687 try(avro_value_get_long(&val, &actual),
688 "Cannot get long value");
689
690 if (actual != expected) {
691 fprintf(stderr, "Unexpected long value\n");
692 return EXIT_FAILURE;
693 }
694
695 check_invalid_methods("long", &val);
696 check_write_read(&val);
697 check_copy(&val);
698 avro_value_decref(&val);
699 }
700 return 0;
701 }
702
703 static int
test_null(void)704 test_null(void)
705 {
706 int rval;
707
708 avro_value_t val;
709 try(avro_generic_null_new(&val),
710 "Cannot create null");
711 check(rval, check_type_and_schema
712 ("null", &val,
713 AVRO_NULL, avro_schema_null()));
714 try(avro_value_reset(&val),
715 "Cannot reset null");
716 try(avro_value_set_null(&val),
717 "Cannot set null");
718 try(avro_value_get_null(&val),
719 "Cannot get null");
720
721 check_invalid_methods("null", &val);
722 check_write_read(&val);
723 check_copy(&val);
724 avro_value_decref(&val);
725 return 0;
726 }
727
728 static int
test_string(void)729 test_string(void)
730 {
731 int rval;
732
733 char *strings[] = {
734 "Four score and seven years ago",
735 "our father brought forth on this continent",
736 "a new nation",
737 "conceived in Liberty",
738 "and dedicated to the proposition that all men "
739 "are created equal."
740 };
741
742 unsigned int i;
743 for (i = 0; i < sizeof(strings) / sizeof(strings[0]); i++) {
744 avro_value_t val;
745 try(avro_generic_string_new(&val, strings[i]),
746 "Cannot create string");
747 check(rval, check_type_and_schema
748 ("string", &val,
749 AVRO_STRING, avro_schema_string()));
750 try(avro_value_reset(&val),
751 "Cannot reset string");
752 try(avro_value_set_string_len(&val, "", 0),
753 "Cannot set_len dummy string");
754
755 /* First try a round-trip using set_string */
756
757 try(avro_value_set_string(&val, strings[i]),
758 "Cannot set string");
759
760 const char *actual_str = NULL;
761 size_t actual_size = 0;
762 try(avro_value_get_string(&val, &actual_str, &actual_size),
763 "Cannot get string value");
764
765 if (actual_size != strlen(strings[i])+1) {
766 fprintf(stderr, "Unexpected string size\n");
767 return EXIT_FAILURE;
768 }
769
770 if (strcmp(actual_str, strings[i]) != 0) {
771 fprintf(stderr, "Unexpected string contents\n");
772 return EXIT_FAILURE;
773 }
774
775 avro_wrapped_buffer_t wbuf;
776 try(avro_value_grab_string(&val, &wbuf),
777 "Cannot grab string value");
778
779 if (wbuf.size != strlen(strings[i])+1) {
780 fprintf(stderr, "Unexpected grabbed string size\n");
781 return EXIT_FAILURE;
782 }
783
784 if (strcmp((const char *) wbuf.buf, strings[i]) != 0) {
785 fprintf(stderr, "Unexpected grabbed string contents\n");
786 return EXIT_FAILURE;
787 }
788
789 avro_wrapped_buffer_free(&wbuf);
790
791 /* and then again using set_string_len */
792
793 size_t str_length = strlen(strings[i])+1;
794 try(avro_value_set_string_len(&val, strings[i], str_length),
795 "Cannot set_len string");
796
797 actual_str = NULL;
798 actual_size = 0;
799 try(avro_value_get_string(&val, &actual_str, &actual_size),
800 "Cannot get string value");
801
802 if (actual_size != strlen(strings[i])+1) {
803 fprintf(stderr, "Unexpected string size\n");
804 return EXIT_FAILURE;
805 }
806
807 if (strcmp(actual_str, strings[i]) != 0) {
808 fprintf(stderr, "Unexpected string contents\n");
809 return EXIT_FAILURE;
810 }
811
812 try(avro_value_grab_string(&val, &wbuf),
813 "Cannot grab string value");
814
815 if (wbuf.size != strlen(strings[i])+1) {
816 fprintf(stderr, "Unexpected grabbed string size\n");
817 return EXIT_FAILURE;
818 }
819
820 if (strcmp((const char *) wbuf.buf, strings[i]) != 0) {
821 fprintf(stderr, "Unexpected grabbed string contents\n");
822 return EXIT_FAILURE;
823 }
824
825 avro_wrapped_buffer_free(&wbuf);
826
827 check_invalid_methods("string", &val);
828 check_write_read(&val);
829 check_copy(&val);
830 avro_value_decref(&val);
831 }
832
833 return 0;
834 }
835
836 static int
test_array(void)837 test_array(void)
838 {
839 avro_schema_t double_schema = avro_schema_double();
840 avro_schema_t array_schema = avro_schema_array(double_schema);
841
842 avro_value_iface_t *array_class =
843 avro_generic_class_from_schema(array_schema);
844
845 int rval;
846
847 int i;
848 for (i = 0; i < 100; i++) {
849 size_t count = rand_count();
850
851 avro_value_t val;
852 try(avro_generic_value_new(array_class, &val),
853 "Cannot create array");
854 check(rval, check_type_and_schema
855 ("array", &val, AVRO_ARRAY,
856 avro_schema_incref(array_schema)));
857
858 size_t j;
859 for (j = 0; j < count; j++) {
860 avro_value_t element;
861 size_t new_index;
862 try(avro_value_append(&val, &element, &new_index),
863 "Cannot append to array");
864 if (new_index != j) {
865 fprintf(stderr, "Unexpected index\n");
866 return EXIT_FAILURE;
867 }
868
869 double expected = rand_number(-1e10, 1e10);
870 try(avro_value_set_double(&element, expected),
871 "Cannot set double");
872 try(avro_value_get_by_index(&val, j, &element, NULL),
873 "Cannot get from array");
874
875 double actual = 0.0;
876 try(avro_value_get_double(&element, &actual),
877 "Cannot get double value");
878
879 if (actual != expected) {
880 fprintf(stderr, "Unexpected double value\n");
881 return EXIT_FAILURE;
882 }
883 }
884
885 size_t actual_size = 0;
886 try(avro_value_get_size(&val, &actual_size),
887 "Cannot get_size array");
888
889 if (actual_size != count) {
890 fprintf(stderr, "Unexpected size\n");
891 return EXIT_FAILURE;
892 }
893
894 check_write_read(&val);
895 check_copy(&val);
896
897 try(avro_value_reset(&val),
898 "Cannot reset array");
899 try(avro_value_get_size(&val, &actual_size),
900 "Cannot get_size empty array");
901
902 if (actual_size != 0) {
903 fprintf(stderr, "Unexpected empty size\n");
904 return EXIT_FAILURE;
905 }
906
907 check_invalid_methods("array", &val);
908 avro_value_decref(&val);
909 }
910
911 avro_schema_decref(double_schema);
912 avro_schema_decref(array_schema);
913 avro_value_iface_decref(array_class);
914 return 0;
915 }
916
917 static int
test_enum(void)918 test_enum(void)
919 {
920 static const char SCHEMA_JSON[] =
921 "{"
922 " \"type\": \"enum\","
923 " \"name\": \"suits\","
924 " \"symbols\": [\"CLUBS\",\"DIAMONDS\",\"HEARTS\",\"SPADES\"]"
925 "}";
926
927 avro_schema_t enum_schema = NULL;
928 if (avro_schema_from_json_literal(SCHEMA_JSON, &enum_schema)) {
929 fprintf(stderr, "Error parsing schema:\n %s\n",
930 avro_strerror());
931 return EXIT_FAILURE;
932 }
933
934 avro_value_iface_t *enum_class =
935 avro_generic_class_from_schema(enum_schema);
936
937 int rval;
938
939 int i;
940 for (i = 0; i < 4; i++) {
941 int expected = i;
942 avro_value_t val;
943 try(avro_generic_value_new(enum_class, &val),
944 "Cannot create enum");
945 check(rval, check_type_and_schema
946 ("enum", &val, AVRO_ENUM,
947 avro_schema_incref(enum_schema)));
948 try(avro_value_reset(&val),
949 "Cannot reset enum");
950 try(avro_value_set_enum(&val, expected),
951 "Cannot set enum");
952
953 int actual = -1;
954 try(avro_value_get_enum(&val, &actual),
955 "Cannot get enum value");
956
957 if (actual != expected) {
958 fprintf(stderr, "Unexpected enum value\n");
959 return EXIT_FAILURE;
960 }
961
962 check_invalid_methods("enum", &val);
963 check_write_read(&val);
964 check_copy(&val);
965 avro_value_decref(&val);
966 }
967
968 avro_schema_decref(enum_schema);
969 avro_value_iface_decref(enum_class);
970 return 0;
971 }
972
973 static int
test_fixed(void)974 test_fixed(void)
975 {
976 static const char SCHEMA_JSON[] =
977 "{"
978 " \"type\": \"fixed\","
979 " \"name\": \"ipv4\","
980 " \"size\": 4"
981 "}";
982
983 avro_schema_t fixed_schema = NULL;
984 if (avro_schema_from_json_literal(SCHEMA_JSON, &fixed_schema)) {
985 fprintf(stderr, "Error parsing schema:\n %s\n",
986 avro_strerror());
987 return EXIT_FAILURE;
988 }
989
990 avro_value_iface_t *fixed_class =
991 avro_generic_class_from_schema(fixed_schema);
992
993 int rval;
994
995 char fixed[] = { 0xDE, 0xAD, 0xBE, 0xEF };
996
997 avro_value_t val;
998 try(avro_generic_value_new(fixed_class, &val),
999 "Cannot create fixed");
1000 check(rval, check_type_and_schema
1001 ("fixed", &val, AVRO_FIXED,
1002 avro_schema_incref(fixed_schema)));
1003 try(avro_value_reset(&val),
1004 "Cannot reset fixed");
1005
1006 /* verify an error on invalid size */
1007 try(!avro_value_set_fixed(&val, fixed, 0),
1008 "Expected error with invalid size");
1009
1010 try(avro_value_set_fixed(&val, fixed, sizeof(fixed)),
1011 "Cannot set fixed");
1012
1013 const void *actual_buf = NULL;
1014 size_t actual_size = 0;
1015 try(avro_value_get_fixed(&val, &actual_buf, &actual_size),
1016 "Cannot get fixed value");
1017
1018 if (actual_size != sizeof(fixed)) {
1019 fprintf(stderr, "Unexpected fixed size\n");
1020 return EXIT_FAILURE;
1021 }
1022
1023 if (memcmp(actual_buf, fixed, sizeof(fixed)) != 0) {
1024 fprintf(stderr, "Unexpected fixed contents\n");
1025 return EXIT_FAILURE;
1026 }
1027
1028 avro_wrapped_buffer_t wbuf;
1029 try(avro_value_grab_fixed(&val, &wbuf),
1030 "Cannot grab fixed value");
1031
1032 if (wbuf.size != sizeof(fixed)) {
1033 fprintf(stderr, "Unexpected grabbed fixed size\n");
1034 return EXIT_FAILURE;
1035 }
1036
1037 if (memcmp(wbuf.buf, fixed, sizeof(fixed)) != 0) {
1038 fprintf(stderr, "Unexpected grabbed fixed contents\n");
1039 return EXIT_FAILURE;
1040 }
1041
1042 avro_wrapped_buffer_free(&wbuf);
1043
1044 check_invalid_methods("fixed", &val);
1045 check_write_read(&val);
1046 check_copy(&val);
1047 avro_value_decref(&val);
1048 avro_schema_decref(fixed_schema);
1049 avro_value_iface_decref(fixed_class);
1050 return 0;
1051 }
1052
1053 static int
test_map(void)1054 test_map(void)
1055 {
1056 avro_schema_t double_schema = avro_schema_double();
1057 avro_schema_t map_schema = avro_schema_map(double_schema);
1058
1059 avro_value_iface_t *map_class =
1060 avro_generic_class_from_schema(map_schema);
1061
1062 int rval;
1063
1064 int i;
1065 for (i = 0; i < 100; i++) {
1066 size_t count = rand_count();
1067
1068 avro_value_t val;
1069 try(avro_generic_value_new(map_class, &val),
1070 "Cannot create map");
1071 check(rval, check_type_and_schema
1072 ("map", &val, AVRO_MAP,
1073 avro_schema_incref(map_schema)));
1074
1075 size_t j;
1076 for (j = 0; j < count; j++) {
1077 avro_value_t element;
1078 size_t new_index;
1079 int is_new = 0;
1080
1081 char key[64];
1082 snprintf(key, 64, "%" PRIsz, j);
1083
1084 try(avro_value_add(&val, key,
1085 &element, &new_index, &is_new),
1086 "Cannot add to map");
1087
1088 if (new_index != j) {
1089 fprintf(stderr, "Unexpected index\n");
1090 return EXIT_FAILURE;
1091 }
1092
1093 if (!is_new) {
1094 fprintf(stderr, "Expected new element\n");
1095 return EXIT_FAILURE;
1096 }
1097
1098 double expected = rand_number(-1e10, 1e10);
1099 try(avro_value_set_double(&element, expected),
1100 "Cannot set double");
1101 try(avro_value_add(&val, key,
1102 &element, &new_index, &is_new),
1103 "Cannot re-add to map");
1104
1105 if (is_new) {
1106 fprintf(stderr, "Expected non-new element\n");
1107 return EXIT_FAILURE;
1108 }
1109
1110 const char *actual_key = NULL;
1111 try(avro_value_get_by_index(&val, j, &element,
1112 &actual_key),
1113 "Cannot get from map");
1114
1115 if (strcmp(actual_key, key) != 0) {
1116 fprintf(stderr, "Unexpected key\n");
1117 return EXIT_FAILURE;
1118 }
1119
1120 double actual = 0.0;
1121 try(avro_value_get_double(&element, &actual),
1122 "Cannot get double value");
1123
1124 if (actual != expected) {
1125 fprintf(stderr, "Unexpected double value\n");
1126 return EXIT_FAILURE;
1127 }
1128 }
1129
1130 size_t actual_size = 0;
1131 try(avro_value_get_size(&val, &actual_size),
1132 "Cannot get_size map");
1133
1134 if (actual_size != count) {
1135 fprintf(stderr, "Unexpected size\n");
1136 return EXIT_FAILURE;
1137 }
1138
1139 /*
1140 * Create a reversed copy of the map to ensure that the
1141 * element ordering doesn't affect the hash value.
1142 */
1143
1144 avro_value_t reversed;
1145 try(avro_generic_value_new(map_class, &reversed),
1146 "Cannot create map");
1147
1148 for (j = count; j-- > 0; ) {
1149 avro_value_t element;
1150 const char *key = NULL;
1151 double element_value = 0.0;
1152 try(avro_value_get_by_index(&val, j, &element, &key),
1153 "Cannot get from map");
1154 try(avro_value_get_double(&element, &element_value),
1155 "Cannot get double value");
1156
1157 try(avro_value_add(&reversed, key, &element, NULL, NULL),
1158 "Cannot add to map");
1159 try(avro_value_set_double(&element, element_value),
1160 "Cannot set double");
1161 }
1162
1163 check_hash(&val, &reversed);
1164 if (!avro_value_equal(&val, &reversed)) {
1165 fprintf(stderr, "Reversed values not equal\n");
1166 return EXIT_FAILURE;
1167 }
1168
1169 /* Final tests and cleanup */
1170
1171 check_write_read(&val);
1172 check_copy(&val);
1173
1174 try(avro_value_reset(&val),
1175 "Cannot reset map");
1176 try(avro_value_get_size(&val, &actual_size),
1177 "Cannot get_size empty map");
1178
1179 if (actual_size != 0) {
1180 fprintf(stderr, "Unexpected empty size\n");
1181 return EXIT_FAILURE;
1182 }
1183
1184 check_invalid_methods("map", &val);
1185 avro_value_decref(&val);
1186 avro_value_decref(&reversed);
1187 }
1188
1189 avro_schema_decref(double_schema);
1190 avro_schema_decref(map_schema);
1191 avro_value_iface_decref(map_class);
1192 return 0;
1193 }
1194
1195 static int
test_record(void)1196 test_record(void)
1197 {
1198 static const char SCHEMA_JSON[] =
1199 "{"
1200 " \"type\": \"record\","
1201 " \"name\": \"test\","
1202 " \"fields\": ["
1203 " { \"name\": \"b\", \"type\": \"boolean\" },"
1204 " { \"name\": \"i\", \"type\": \"int\" },"
1205 " { \"name\": \"s\", \"type\": \"string\" },"
1206 " { \"name\": \"ds\", \"type\": "
1207 " { \"type\": \"array\", \"items\": \"double\" } },"
1208 " { \"name\": \"sub\", \"type\": "
1209 " {"
1210 " \"type\": \"record\","
1211 " \"name\": \"subtest\","
1212 " \"fields\": ["
1213 " { \"name\": \"f\", \"type\": \"float\" },"
1214 " { \"name\": \"l\", \"type\": \"long\" }"
1215 " ]"
1216 " }"
1217 " },"
1218 " { \"name\": \"nested\", \"type\": [\"null\", \"test\"] }"
1219 " ]"
1220 "}";
1221
1222 avro_schema_t record_schema = NULL;
1223 if (avro_schema_from_json_literal(SCHEMA_JSON, &record_schema)) {
1224 fprintf(stderr, "Error parsing schema:\n %s\n",
1225 avro_strerror());
1226 return EXIT_FAILURE;
1227 }
1228
1229 avro_value_iface_t *record_class =
1230 avro_generic_class_from_schema(record_schema);
1231
1232 int rval;
1233
1234 avro_value_t val;
1235 try(avro_generic_value_new(record_class, &val),
1236 "Cannot create record");
1237 check(rval, check_type_and_schema
1238 ("record", &val, AVRO_RECORD,
1239 avro_schema_incref(record_schema)));
1240
1241 size_t field_count;
1242 try(avro_value_get_size(&val, &field_count),
1243 "Cannot get field count");
1244 if (field_count != 6) {
1245 fprintf(stderr, "Unexpected field count\n");
1246 return EXIT_FAILURE;
1247 }
1248
1249 /* Assign to each field */
1250 avro_value_t field;
1251 avro_value_t element;
1252 avro_value_t subfield;
1253 avro_value_t branch;
1254 const char *name;
1255 size_t index;
1256
1257 try(avro_value_get_by_index(&val, 0, &field, NULL),
1258 "Cannot get field 0");
1259 try(avro_value_set_boolean(&field, 1),
1260 "Cannot set field 0");
1261
1262 try(avro_value_get_by_index(&val, 1, &field, &name),
1263 "Cannot get field 1");
1264 try(avro_value_set_int(&field, 42),
1265 "Cannot set field 1");
1266 if (strcmp(name, "i") != 0) {
1267 fprintf(stderr, "Unexpected name for field 1: %s\n", name);
1268 return EXIT_FAILURE;
1269 }
1270
1271 try(avro_value_get_by_index(&val, 2, &field, NULL),
1272 "Cannot get field 2");
1273 try(avro_value_set_string(&field, "Hello world!"),
1274 "Cannot set field 2");
1275
1276 try(avro_value_get_by_name(&val, "i", &field, &index),
1277 "Cannot get \"i\" field");
1278 if (index != 1) {
1279 fprintf(stderr, "Unexpected index for \"i\" field: %" PRIsz "\n", index);
1280 return EXIT_FAILURE;
1281 }
1282
1283 try(avro_value_get_by_index(&val, 3, &field, NULL),
1284 "Cannot get field 3");
1285 try(avro_value_append(&field, &element, NULL),
1286 "Cannot append to field 3");
1287 try(avro_value_set_double(&element, 10.0),
1288 "Cannot set field 3, element 0");
1289
1290 try(avro_value_get_by_index(&val, 4, &field, NULL),
1291 "Cannot get field 4");
1292
1293 try(avro_value_get_by_index(&field, 0, &subfield, NULL),
1294 "Cannot get field 4, subfield 0");
1295 try(avro_value_set_float(&subfield, 5.0f),
1296 "Cannot set field 4, subfield 0");
1297
1298 try(avro_value_get_by_index(&field, 1, &subfield, NULL),
1299 "Cannot get field 4, subfield 1");
1300 try(avro_value_set_long(&subfield, 10000),
1301 "Cannot set field 4, subfield 1");
1302
1303 try(avro_value_get_by_index(&val, 5, &field, NULL),
1304 "Cannot get field 5");
1305 try(avro_value_set_branch(&field, 0, &branch),
1306 "Cannot select null branch");
1307
1308 check_write_read(&val);
1309 check_copy(&val);
1310
1311 /* Reset and verify that the fields are empty again */
1312 try(avro_value_reset(&val),
1313 "Cannot reset record");
1314
1315 int bval;
1316 try(avro_value_get_by_index(&val, 0, &field, NULL),
1317 "Cannot get field 0");
1318 try(avro_value_get_boolean(&field, &bval),
1319 "Cannot get field 0 value");
1320 if (bval) {
1321 fprintf(stderr, "Unexpected value for field 0\n");
1322 return EXIT_FAILURE;
1323 }
1324
1325 size_t count;
1326 try(avro_value_get_by_index(&val, 3, &field, NULL),
1327 "Cannot get field 3");
1328 try(avro_value_get_size(&field, &count),
1329 "Cannot get field 3 size");
1330 if (count != 0) {
1331 fprintf(stderr, "Unexpected size for field 3\n");
1332 return EXIT_FAILURE;
1333 }
1334
1335 check_invalid_methods("record", &val);
1336 avro_value_decref(&val);
1337 avro_value_iface_decref(record_class);
1338 avro_schema_decref(record_schema);
1339 return EXIT_SUCCESS;
1340 }
1341
1342 static int
test_union(void)1343 test_union(void)
1344 {
1345 static const char SCHEMA_JSON[] =
1346 "["
1347 " \"null\","
1348 " \"int\","
1349 " \"double\","
1350 " \"bytes\""
1351 "]";
1352
1353 avro_schema_t union_schema = NULL;
1354 if (avro_schema_from_json_literal(SCHEMA_JSON, &union_schema)) {
1355 fprintf(stderr, "Error parsing schema:\n %s\n",
1356 avro_strerror());
1357 return EXIT_FAILURE;
1358 }
1359
1360 avro_value_iface_t *union_class =
1361 avro_generic_class_from_schema(union_schema);
1362
1363 int rval;
1364
1365 avro_value_t val;
1366 try(avro_generic_value_new(union_class, &val),
1367 "Cannot create union");
1368 check(rval, check_type_and_schema
1369 ("union", &val, AVRO_UNION,
1370 avro_schema_incref(union_schema)));
1371
1372 int discriminant = 0;
1373 try(avro_value_get_discriminant(&val, &discriminant),
1374 "Cannot get union discriminant");
1375
1376 if (discriminant != -1) {
1377 fprintf(stderr, "Unexpected union discriminant\n");
1378 return EXIT_FAILURE;
1379 }
1380
1381 avro_value_t branch;
1382 try(!avro_value_get_current_branch(&val, &branch),
1383 "Expected error getting empty current branch");
1384
1385 try(avro_value_set_branch(&val, 0, &branch),
1386 "Cannot select null branch");
1387 try(avro_value_set_null(&branch),
1388 "Cannot set null branch value");
1389
1390 try(avro_value_set_branch(&val, 1, &branch),
1391 "Cannot select int branch");
1392 try(avro_value_set_int(&branch, 42),
1393 "Cannot set int branch value");
1394
1395 try(avro_value_set_branch(&val, 1, &branch),
1396 "Cannot select int branch");
1397 try(avro_value_set_int(&branch, 10),
1398 "Cannot set int branch value");
1399
1400 try(avro_value_set_branch(&val, 2, &branch),
1401 "Cannot select double branch");
1402 try(avro_value_set_double(&branch, 10.0),
1403 "Cannot set double branch value");
1404
1405 char bytes[] = { 0xDE, 0xAD, 0xBE, 0xEF };
1406 try(avro_value_set_branch(&val, 3, &branch),
1407 "Cannot select bytes branch");
1408 try(avro_value_set_bytes(&branch, bytes, sizeof(bytes)),
1409 "Cannot set bytes branch value");
1410
1411 check_invalid_methods("union", &val);
1412 check_write_read(&val);
1413 check_copy(&val);
1414 avro_value_decref(&val);
1415
1416 avro_schema_decref(union_schema);
1417 avro_value_iface_decref(union_class);
1418 return 0;
1419 }
1420
main(void)1421 int main(void)
1422 {
1423 avro_set_allocator(test_allocator, NULL);
1424
1425 unsigned int i;
1426 struct avro_tests {
1427 char *name;
1428 avro_test func;
1429 } tests[] = {
1430 { "boolean", test_boolean },
1431 { "bytes", test_bytes },
1432 { "double", test_double },
1433 { "float", test_float },
1434 { "int", test_int },
1435 { "long", test_long },
1436 { "null", test_null },
1437 { "string", test_string },
1438 { "array", test_array },
1439 { "enum", test_enum },
1440 { "fixed", test_fixed },
1441 { "map", test_map },
1442 { "record", test_record },
1443 { "union", test_union }
1444 };
1445
1446 init_rand();
1447 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
1448 struct avro_tests *test = tests + i;
1449 fprintf(stderr, "**** Running %s tests ****\n", test->name);
1450 if (test->func() != 0) {
1451 return EXIT_FAILURE;
1452 }
1453 }
1454 return EXIT_SUCCESS;
1455 }
1456