/* * Copyright (c) 2015 SPUDlib authors. See LICENSE file. */ #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <stdio.h> #include <assert.h> #include <string.h> #include "cn-cbor/cn-cbor.h" #define CTEST_MAIN #include "ctest.h" int main(int argc, const char *argv[]) { return ctest_main(argc, argv); } #ifdef USE_CBOR_CONTEXT #define CONTEXT_NULL , NULL #define CONTEXT_NULL_COMMA NULL, #else #define CONTEXT_NULL #define CONTEXT_NULL_COMMA #endif typedef struct _buffer { size_t sz; unsigned char *ptr; } buffer; static bool parse_hex(char *inp, buffer *b) { int len = strlen(inp); size_t i; if (len%2 != 0) { b->sz = -1; b->ptr = NULL; return false; } b->sz = len / 2; b->ptr = malloc(b->sz); for (i=0; i<b->sz; i++) { sscanf(inp+(2*i), "%02hhx", &b->ptr[i]); } return true; } CTEST(cbor, error) { ASSERT_STR(cn_cbor_error_str[CN_CBOR_NO_ERROR], "CN_CBOR_NO_ERROR"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_OUT_OF_DATA], "CN_CBOR_ERR_OUT_OF_DATA"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED], "CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_ODD_SIZE_INDEF_MAP], "CN_CBOR_ERR_ODD_SIZE_INDEF_MAP"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_BREAK_OUTSIDE_INDEF], "CN_CBOR_ERR_BREAK_OUTSIDE_INDEF"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_MT_UNDEF_FOR_INDEF], "CN_CBOR_ERR_MT_UNDEF_FOR_INDEF"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_RESERVED_AI], "CN_CBOR_ERR_RESERVED_AI"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING], "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_INVALID_PARAMETER], "CN_CBOR_ERR_INVALID_PARAMETER"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_OUT_OF_MEMORY], "CN_CBOR_ERR_OUT_OF_MEMORY"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_FLOAT_NOT_SUPPORTED], "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED"); } CTEST(cbor, parse) { cn_cbor_errback err; char *tests[] = { "00", // 0 "01", // 1 "17", // 23 "1818", // 24 "190100", // 256 "1a00010000", // 65536 "1b0000000100000000", // 4294967296 "20", // -1 "37", // -24 "3818", // -25 "390100", // -257 "3a00010000", // -65537 "3b0000000100000000", // -4294967297 "4161", // h"a" "6161", // "a" "80", // [] "8100", // [0] "820102", // [1,2] "818100", // [[0]] "a1616100", // {"a":0} "d8184100", // tag "f4", // false "f5", // true "f6", // null "f7", // undefined "f8ff", // simple(255) #ifndef CBOR_NO_FLOAT "f93c00", // 1.0 "f9bc00", // -1.0 "f903ff", // 6.097555160522461e-05 "f90400", // 6.103515625e-05 "f907ff", // 0.00012201070785522461 "f90800", // 0.0001220703125 "fa47800000", // 65536.0 "fb3ff199999999999a", // 1.1 "f97e00", // NaN #endif /* CBOR_NO_FLOAT */ "5f42010243030405ff", // (_ h'0102', h'030405') "7f61616161ff", // (_ "a", "a") "9fff", // [_ ] "9f9f9fffffff", // [_ [_ [_ ]]] "9f009f00ff00ff", // [_ 0, [_ 0], 0] "bf61610161629f0203ffff", // {_ "a": 1, "b": [_ 2, 3]} }; cn_cbor *cb; buffer b; size_t i; unsigned char encoded[1024]; ssize_t enc_sz; for (i=0; i<sizeof(tests)/sizeof(char*); i++) { ASSERT_TRUE(parse_hex(tests[i], &b)); err.err = CN_CBOR_NO_ERROR; cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); //CTEST_LOG("%s: %s", tests[i], cn_cbor_error_str[err.err]); ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); ASSERT_NOT_NULL(cb); enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); } } CTEST(cbor, parse_normalize) { cn_cbor_errback err; char *basic_tests[] = { "00", "00", // 0 "1800", "00", "1818", "1818", "190000", "00", "190018", "1818", "1a00000000", "00", "1b0000000000000000", "00", "20", "20", // -1 "3800", "20", "c600", "c600", // 6(0) (undefined tag) "d80600", "c600", "d9000600", "c600", }; char *float_tests[] = { "fb3ff0000000000000", "f93c00", // 1.0 "fbbff0000000000000", "f9bc00", // -1.0 "fb40f86a0000000000", "fa47c35000", // 100000.0 "fb7ff8000000000000", "f97e00", // NaN "fb3e70000000000000", "f90001", // 5.960464477539063e-08 "fb3e78000000000000", "fa33c00000", // 8.940696716308594e-08 "fb3e80000000000000", "f90002", // 1.1920928955078125e-07 }; cn_cbor *cb; buffer b, b2; size_t i; unsigned char encoded[1024]; ssize_t enc_sz; for (i=0; i<sizeof(basic_tests)/sizeof(char*); i+=2) { ASSERT_TRUE(parse_hex(basic_tests[i], &b)); ASSERT_TRUE(parse_hex(basic_tests[i+1], &b2)); err.err = CN_CBOR_NO_ERROR; cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); CTEST_LOG("%s: %s", basic_tests[i], cn_cbor_error_str[err.err]); ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); ASSERT_NOT_NULL(cb); enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz); free(b.ptr); free(b2.ptr); cn_cbor_free(cb CONTEXT_NULL); } for (i=0; i<sizeof(float_tests)/sizeof(char*); i+=2) { ASSERT_TRUE(parse_hex(float_tests[i], &b)); ASSERT_TRUE(parse_hex(float_tests[i+1], &b2)); err.err = CN_CBOR_NO_ERROR; cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); CTEST_LOG("%s: %s", float_tests[i], cn_cbor_error_str[err.err]); #ifndef CBOR_NO_FLOAT ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); ASSERT_NOT_NULL(cb); #else /* CBOR_NO_FLOAT */ ASSERT_EQUAL(err.err, CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); ASSERT_NULL(cb); #endif /* CBOR_NO_FLOAT */ /* enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); */ /* ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz); */ free(b.ptr); free(b2.ptr); cn_cbor_free(cb CONTEXT_NULL); } } typedef struct _cbor_failure { char *hex; cn_cbor_error err; } cbor_failure; CTEST(cbor, fail) { cn_cbor_errback err; cbor_failure tests[] = { {"81", CN_CBOR_ERR_OUT_OF_DATA}, {"0000", CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED}, {"bf00ff", CN_CBOR_ERR_ODD_SIZE_INDEF_MAP}, {"ff", CN_CBOR_ERR_BREAK_OUTSIDE_INDEF}, {"1f", CN_CBOR_ERR_MT_UNDEF_FOR_INDEF}, {"1c", CN_CBOR_ERR_RESERVED_AI}, {"7f4100", CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING}, }; cn_cbor *cb; buffer b; size_t i; uint8_t buf[10]; cn_cbor inv = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL}; ASSERT_EQUAL(-1, cn_cbor_encoder_write(buf, 0, sizeof(buf), &inv)); for (i=0; i<sizeof(tests)/sizeof(cbor_failure); i++) { ASSERT_TRUE(parse_hex(tests[i].hex, &b)); cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NULL(cb); ASSERT_EQUAL(err.err, tests[i].err); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); } } // Decoder loses float size information CTEST(cbor, float) { #ifndef CBOR_NO_FLOAT cn_cbor_errback err; char *tests[] = { "f90001", // 5.960464477539063e-08 "f9c400", // -4.0 "fa47c35000", // 100000.0 "f97e00", // Half NaN, half beast "f9fc00", // -Inf "f97c00", // Inf }; cn_cbor *cb; buffer b; size_t i; unsigned char encoded[1024]; ssize_t enc_sz; for (i=0; i<sizeof(tests)/sizeof(char*); i++) { ASSERT_TRUE(parse_hex(tests[i], &b)); cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb); enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); } #endif /* CBOR_NO_FLOAT */ } CTEST(cbor, getset) { buffer b; cn_cbor *cb; cn_cbor *val; cn_cbor_errback err; ASSERT_TRUE(parse_hex("a40000436363630262626201616100", &b)); cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb); val = cn_cbor_mapget_string(cb, "a"); ASSERT_NOT_NULL(val); val = cn_cbor_mapget_string(cb, "bb"); ASSERT_NOT_NULL(val); val = cn_cbor_mapget_string(cb, "ccc"); ASSERT_NOT_NULL(val); val = cn_cbor_mapget_string(cb, "b"); ASSERT_NULL(val); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); ASSERT_TRUE(parse_hex("a3616100006161206162", &b)); cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb); val = cn_cbor_mapget_int(cb, 0); ASSERT_NOT_NULL(val); val = cn_cbor_mapget_int(cb, -1); ASSERT_NOT_NULL(val); val = cn_cbor_mapget_int(cb, 1); ASSERT_NULL(val); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); ASSERT_TRUE(parse_hex("8100", &b)); cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb); val = cn_cbor_index(cb, 0); ASSERT_NOT_NULL(val); val = cn_cbor_index(cb, 1); ASSERT_NULL(val); val = cn_cbor_index(cb, -1); ASSERT_NULL(val); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); } CTEST(cbor, create) { cn_cbor_errback err; const cn_cbor* val; const char* data = "abc"; cn_cbor *cb_map = cn_cbor_map_create(CONTEXT_NULL_COMMA &err); cn_cbor *cb_int; cn_cbor *cb_data; ASSERT_NOT_NULL(cb_map); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); cb_int = cn_cbor_int_create(256 CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb_int); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); cb_data = cn_cbor_data_create((const uint8_t*)data, 4 CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb_data); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); cn_cbor_mapput_int(cb_map, 5, cb_int CONTEXT_NULL, &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_TRUE(cb_map->length == 2); cn_cbor_mapput_int(cb_map, -7, cb_data CONTEXT_NULL, &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_TRUE(cb_map->length == 4); cn_cbor_mapput_string(cb_map, "foo", cn_cbor_string_create(data CONTEXT_NULL, &err) CONTEXT_NULL, &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_TRUE(cb_map->length == 6); cn_cbor_map_put(cb_map, cn_cbor_string_create("bar" CONTEXT_NULL, &err), cn_cbor_string_create("qux" CONTEXT_NULL, &err), &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_TRUE(cb_map->length == 8); val = cn_cbor_mapget_int(cb_map, 5); ASSERT_NOT_NULL(val); ASSERT_TRUE(val->v.sint == 256); val = cn_cbor_mapget_int(cb_map, -7); ASSERT_NOT_NULL(val); ASSERT_STR(val->v.str, "abc"); cn_cbor_free(cb_map CONTEXT_NULL); } CTEST(cbor, map_errors) { cn_cbor_errback err; cn_cbor *ci; ci = cn_cbor_int_create(65536, CONTEXT_NULL_COMMA &err); cn_cbor_mapput_int(ci, -5, NULL, CONTEXT_NULL_COMMA &err); ASSERT_EQUAL(err.err, CN_CBOR_ERR_INVALID_PARAMETER); cn_cbor_mapput_string(ci, "foo", NULL, CONTEXT_NULL_COMMA &err); ASSERT_EQUAL(err.err, CN_CBOR_ERR_INVALID_PARAMETER); cn_cbor_map_put(ci, NULL, NULL, &err); } CTEST(cbor, array) { cn_cbor_errback err; cn_cbor *a = cn_cbor_array_create(CONTEXT_NULL_COMMA &err); ASSERT_NOT_NULL(a); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_EQUAL(a->length, 0); cn_cbor_array_append(a, cn_cbor_int_create(256, CONTEXT_NULL_COMMA &err), &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_EQUAL(a->length, 1); cn_cbor_array_append(a, cn_cbor_string_create("five", CONTEXT_NULL_COMMA &err), &err); ASSERT_TRUE(err.err == CN_CBOR_NO_ERROR); ASSERT_EQUAL(a->length, 2); } CTEST(cbor, array_errors) { cn_cbor_errback err; cn_cbor *ci = cn_cbor_int_create(12, CONTEXT_NULL_COMMA &err); cn_cbor_array_append(NULL, ci, &err); ASSERT_EQUAL(err.err, CN_CBOR_ERR_INVALID_PARAMETER); cn_cbor_array_append(ci, NULL, &err); ASSERT_EQUAL(err.err, CN_CBOR_ERR_INVALID_PARAMETER); } CTEST(cbor, create_encode) { cn_cbor *map; cn_cbor *cdata; char data[] = "data"; unsigned char encoded[1024]; ssize_t enc_sz; map = cn_cbor_map_create(CONTEXT_NULL_COMMA NULL); ASSERT_NOT_NULL(map); cdata = cn_cbor_data_create((uint8_t*)data, sizeof(data)-1, CONTEXT_NULL_COMMA NULL); ASSERT_NOT_NULL(cdata); ASSERT_TRUE(cn_cbor_mapput_int(map, 0, cdata, CONTEXT_NULL_COMMA NULL)); enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), map); ASSERT_EQUAL(7, enc_sz); }