1/*
2 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3 *
4 * libcbor is free software; you can redistribute it and/or modify
5 * it under the terms of the MIT license. See LICENSE for details.
6 */
7
8#include "assertions.h"
9#include "cbor.h"
10#include "test_allocator.h"
11
12cbor_item_t *tag;
13struct cbor_load_result res;
14
15unsigned char embedded_tag_data[] = {0xC0, 0x00};
16
17static void test_refcounting(void **_CBOR_UNUSED(_state)) {
18  tag = cbor_load(embedded_tag_data, 2, &res);
19  assert_true(cbor_refcount(tag) == 1);
20  cbor_item_t *item = cbor_tag_item(tag);
21  assert_true(cbor_refcount(item) == 2);
22  cbor_decref(&tag);
23  assert_null(tag);
24  assert_true(cbor_refcount(item) == 1);
25  cbor_decref(&item);
26  assert_null(item);
27}
28
29/* Tag 0 + uint 0 */
30static void test_embedded_tag(void **_CBOR_UNUSED(_state)) {
31  tag = cbor_load(embedded_tag_data, 2, &res);
32  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
33  assert_true(cbor_tag_value(tag) == 0);
34  assert_uint8(cbor_move(cbor_tag_item(tag)), 0);
35  cbor_decref(&tag);
36  assert_null(tag);
37}
38
39unsigned char int8_tag_data[] = {0xD8, 0xFF, 0x01};
40
41/* Tag 255 + uint 1 */
42static void test_int8_tag(void **_CBOR_UNUSED(_state)) {
43  tag = cbor_load(int8_tag_data, 3, &res);
44  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
45  assert_true(cbor_tag_value(tag) == 255);
46  assert_uint8(cbor_move(cbor_tag_item(tag)), 1);
47  cbor_decref(&tag);
48  assert_null(tag);
49}
50
51unsigned char int16_tag_data[] = {0xD9, 0xFF, 0x00, 0x02};
52
53/* Tag 255 << 8 + uint 2 */
54static void test_int16_tag(void **_CBOR_UNUSED(_state)) {
55  tag = cbor_load(int16_tag_data, 4, &res);
56  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
57  assert_true(cbor_tag_value(tag) == 255 << 8);
58  assert_uint8(cbor_move(cbor_tag_item(tag)), 2);
59  cbor_decref(&tag);
60  assert_null(tag);
61}
62
63unsigned char int32_tag_data[] = {0xDA, 0xFF, 0x00, 0x00, 0x00, 0x03};
64
65/* uint 3 */
66static void test_int32_tag(void **_CBOR_UNUSED(_state)) {
67  tag = cbor_load(int32_tag_data, 6, &res);
68  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
69  assert_true(cbor_tag_value(tag) == 4278190080ULL);
70  assert_uint8(cbor_move(cbor_tag_item(tag)), 3);
71  cbor_decref(&tag);
72  assert_null(tag);
73}
74
75unsigned char int64_tag_data[] = {0xDB, 0xFF, 0x00, 0x00, 0x00,
76                                  0x00, 0x00, 0x00, 0x00, 0x04};
77
78/* uint 4 */
79static void test_int64_tag(void **_CBOR_UNUSED(_state)) {
80  tag = cbor_load(int64_tag_data, 10, &res);
81  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
82  assert_true(cbor_tag_value(tag) == 18374686479671623680ULL);
83  assert_uint8(cbor_move(cbor_tag_item(tag)), 4);
84  cbor_decref(&tag);
85  assert_null(tag);
86}
87
88unsigned char nested_tag_data[] = {0xC0, 0xC1, 0x18, 0x2A};
89
90/* Tag 0, tag 1 + uint 0 */
91static void test_nested_tag(void **_CBOR_UNUSED(_state)) {
92  tag = cbor_load(nested_tag_data, 4, &res);
93  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
94  assert_true(cbor_tag_value(tag) == 0);
95  cbor_item_t *nested_tag = cbor_tag_item(tag);
96  assert_true(cbor_typeof(nested_tag) == CBOR_TYPE_TAG);
97  assert_true(cbor_tag_value(nested_tag) == 1);
98  assert_uint8(cbor_move(cbor_tag_item(nested_tag)), 42);
99  cbor_decref(&tag);
100  assert_null(tag);
101  cbor_decref(&nested_tag);
102  assert_null(nested_tag);
103}
104
105static void test_all_tag_values_supported(void **_CBOR_UNUSED(_state)) {
106  /* Test all items in the protected range of
107   * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */
108  for (int64_t tag_value = 0; tag_value <= 32767; tag_value++) {
109    cbor_item_t *tag_item =
110        cbor_build_tag(tag_value, cbor_move(cbor_build_uint8(42)));
111    unsigned char *serialized_tag;
112    size_t serialized_tag_size =
113        cbor_serialize_alloc(tag_item, &serialized_tag, NULL);
114    assert_true(serialized_tag_size > 0);
115    tag = cbor_load(serialized_tag, serialized_tag_size, &res);
116    assert_true(res.read == serialized_tag_size);
117    assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
118    assert_true(cbor_tag_value(tag) == tag_value);
119    cbor_decref(&tag);
120    assert_null(tag);
121    cbor_decref(&tag_item);
122    assert_null(tag_item);
123    free(serialized_tag);
124  }
125}
126
127static void test_build_tag(void **_CBOR_UNUSED(_state)) {
128  tag = cbor_build_tag(1, cbor_move(cbor_build_uint8(42)));
129
130  assert_true(cbor_typeof(tag) == CBOR_TYPE_TAG);
131  assert_size_equal(cbor_tag_value(tag), 1);
132  assert_uint8(cbor_move(cbor_tag_item(tag)), 42);
133
134  cbor_decref(&tag);
135}
136
137static void test_build_tag_failure(void **_CBOR_UNUSED(_state)) {
138  cbor_item_t *tagged_item = cbor_build_uint8(42);
139
140  WITH_FAILING_MALLOC({ assert_null(cbor_build_tag(1, tagged_item)); });
141  assert_size_equal(cbor_refcount(tagged_item), 1);
142
143  cbor_decref(&tagged_item);
144}
145
146static void test_tag_creation(void **_CBOR_UNUSED(_state)) {
147  WITH_FAILING_MALLOC({ assert_null(cbor_new_tag(42)); });
148}
149
150int main(void) {
151  const struct CMUnitTest tests[] = {
152      cmocka_unit_test(test_refcounting),
153      cmocka_unit_test(test_embedded_tag),
154      cmocka_unit_test(test_int8_tag),
155      cmocka_unit_test(test_int16_tag),
156      cmocka_unit_test(test_int32_tag),
157      cmocka_unit_test(test_int64_tag),
158      cmocka_unit_test(test_nested_tag),
159      cmocka_unit_test(test_all_tag_values_supported),
160      cmocka_unit_test(test_build_tag),
161      cmocka_unit_test(test_build_tag_failure),
162      cmocka_unit_test(test_tag_creation),
163  };
164  return cmocka_run_group_tests(tests, NULL, NULL);
165}
166