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 <setjmp.h>
9#include <stdarg.h>
10#include <stddef.h>
11#include <stdint.h>
12#include <string.h>
13
14#include <cmocka.h>
15
16#include "assertions.h"
17#include "cbor.h"
18#include "test_allocator.h"
19
20cbor_item_t *map;
21struct cbor_load_result res;
22
23unsigned char empty_map[] = {0xA0};
24
25static void test_empty_map(void **_CBOR_UNUSED(_state)) {
26  map = cbor_load(empty_map, 1, &res);
27  assert_non_null(map);
28  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
29  assert_true(cbor_isa_map(map));
30  assert_true(cbor_map_size(map) == 0);
31  assert_true(res.read == 1);
32  assert_size_equal(cbor_map_allocated(map), 0);
33  cbor_decref(&map);
34  assert_null(map);
35}
36
37unsigned char simple_map[] = {0xA2, 0x01, 0x02, 0x03, 0x04};
38
39/* {1: 2, 3: 4} */
40static void test_simple_map(void **_CBOR_UNUSED(_state)) {
41  map = cbor_load(simple_map, 5, &res);
42  assert_non_null(map);
43  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
44  assert_true(cbor_isa_map(map));
45  assert_true(cbor_map_is_definite(map));
46  assert_true(cbor_map_size(map) == 2);
47  assert_true(res.read == 5);
48  struct cbor_pair *handle = cbor_map_handle(map);
49  assert_uint8(handle[0].key, 1);
50  assert_uint8(handle[0].value, 2);
51  assert_uint8(handle[1].key, 3);
52  assert_uint8(handle[1].value, 4);
53  cbor_decref(&map);
54  assert_null(map);
55}
56
57unsigned char simple_indef_map[] = {0xBF, 0x01, 0x02, 0x03, 0x04, 0xFF};
58
59/* {_ 1: 2, 3: 4} */
60static void test_indef_simple_map(void **_CBOR_UNUSED(_state)) {
61  map = cbor_load(simple_indef_map, 6, &res);
62  assert_non_null(map);
63  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
64  assert_true(cbor_isa_map(map));
65  assert_true(cbor_map_is_indefinite(map));
66  assert_true(cbor_map_size(map) == 2);
67  assert_true(res.read == 6);
68  struct cbor_pair *handle = cbor_map_handle(map);
69  assert_uint8(handle[0].key, 1);
70  assert_uint8(handle[0].value, 2);
71  assert_uint8(handle[1].key, 3);
72  assert_uint8(handle[1].value, 4);
73  cbor_decref(&map);
74  assert_null(map);
75}
76
77//{
78//	"glossary": {
79//		"title": "example glossary"
80//	}
81//}
82unsigned char def_nested_map[] = {
83    0xA1, 0x68, 0x67, 0x6C, 0x6F, 0x73, 0x73, 0x61, 0x72, 0x79, 0xA1, 0x65,
84    0x74, 0x69, 0x74, 0x6C, 0x65, 0x70, 0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C,
85    0x65, 0x20, 0x67, 0x6C, 0x6F, 0x73, 0x73, 0x61, 0x72, 0x79};
86
87static void test_def_nested_map(void **_CBOR_UNUSED(_state)) {
88  map = cbor_load(def_nested_map, 34, &res);
89  assert_non_null(map);
90  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
91  assert_true(cbor_isa_map(map));
92  assert_true(cbor_map_is_definite(map));
93  assert_true(cbor_map_size(map) == 1);
94  assert_true(res.read == 34);
95  struct cbor_pair *handle = cbor_map_handle(map);
96  assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
97  assert_true(cbor_typeof(handle[0].value) == CBOR_TYPE_MAP);
98  struct cbor_pair *inner_handle = cbor_map_handle(handle[0].value);
99  assert_true(cbor_typeof(inner_handle[0].key) == CBOR_TYPE_STRING);
100  assert_true(cbor_typeof(inner_handle[0].value) == CBOR_TYPE_STRING);
101  assert_memory_equal(cbor_string_handle(inner_handle[0].value),
102                      "example glossary", strlen("example glossary"));
103  cbor_decref(&map);
104  assert_null(map);
105}
106
107unsigned char streamed_key_map[] = {0xA1, 0x7F, 0x61, 0x61,
108                                    0x61, 0x62, 0xFF, 0xA0};
109
110/* '{ (_"a" "b"): {}}' */
111static void test_streamed_key_map(void **_CBOR_UNUSED(_state)) {
112  map = cbor_load(streamed_key_map, 8, &res);
113  assert_non_null(map);
114  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
115  assert_true(cbor_isa_map(map));
116  assert_true(cbor_map_is_definite(map));
117  assert_true(cbor_map_size(map) == 1);
118  assert_true(res.read == 8);
119  struct cbor_pair *handle = cbor_map_handle(map);
120  assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
121  assert_true(cbor_string_is_indefinite(handle[0].key));
122  assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
123  assert_true(cbor_isa_map(handle[0].value));
124  assert_size_equal(cbor_map_size(handle[0].value), 0);
125  cbor_decref(&map);
126  assert_null(map);
127}
128
129unsigned char streamed_kv_map[] = {0xA1, 0x7F, 0x61, 0x61, 0x61, 0x62, 0xFF,
130                                   0x7F, 0x61, 0x63, 0x61, 0x64, 0xFF};
131
132/* '{ (_"a" "b"): (_"c", "d")}' */
133static void test_streamed_kv_map(void **_CBOR_UNUSED(_state)) {
134  map = cbor_load(streamed_kv_map, 13, &res);
135  assert_non_null(map);
136  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
137  assert_true(cbor_isa_map(map));
138  assert_true(cbor_map_is_definite(map));
139  assert_size_equal(cbor_map_size(map), 1);
140  assert_size_equal(res.read, 13);
141  struct cbor_pair *handle = cbor_map_handle(map);
142  assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
143  assert_true(cbor_string_is_indefinite(handle[0].key));
144  assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
145  assert_true(cbor_typeof(handle[0].value) == CBOR_TYPE_STRING);
146  assert_true(cbor_string_is_indefinite(handle[0].value));
147  assert_size_equal(cbor_string_chunk_count(handle[0].value), 2);
148  assert_memory_equal(
149      cbor_string_handle(cbor_string_chunks_handle(handle[0].value)[1]), "d",
150      1);
151  cbor_decref(&map);
152  assert_null(map);
153}
154
155unsigned char streamed_streamed_kv_map[] = {0xBF, 0x7F, 0x61, 0x61, 0x61,
156                                            0x62, 0xFF, 0x7F, 0x61, 0x63,
157                                            0x61, 0x64, 0xFF, 0xFF};
158
159/* '{_ (_"a" "b"): (_"c", "d")}' */
160static void test_streamed_streamed_kv_map(void **_CBOR_UNUSED(_state)) {
161  map = cbor_load(streamed_streamed_kv_map, 14, &res);
162  assert_non_null(map);
163  assert_true(cbor_typeof(map) == CBOR_TYPE_MAP);
164  assert_true(cbor_isa_map(map));
165  assert_true(cbor_map_is_indefinite(map));
166  assert_size_equal(cbor_map_size(map), 1);
167  assert_size_equal(res.read, 14);
168  struct cbor_pair *handle = cbor_map_handle(map);
169  assert_true(cbor_typeof(handle[0].key) == CBOR_TYPE_STRING);
170  assert_true(cbor_string_is_indefinite(handle[0].key));
171  assert_size_equal(cbor_string_chunk_count(handle[0].key), 2);
172  assert_true(cbor_typeof(handle[0].value) == CBOR_TYPE_STRING);
173  assert_true(cbor_string_is_indefinite(handle[0].value));
174  assert_size_equal(cbor_string_chunk_count(handle[0].value), 2);
175  assert_memory_equal(
176      cbor_string_handle(cbor_string_chunks_handle(handle[0].value)[1]), "d",
177      1);
178  cbor_decref(&map);
179  assert_null(map);
180}
181
182static void test_map_add_full(void **_CBOR_UNUSED(_state)) {
183  map = cbor_new_definite_map(0);
184  cbor_item_t *one = cbor_build_uint8(1);
185  cbor_item_t *two = cbor_build_uint8(2);
186
187  assert_false(cbor_map_add(map, (struct cbor_pair){.key = one, .value = two}));
188
189  cbor_decref(&map);
190  cbor_decref(&one);
191  cbor_decref(&two);
192}
193
194static void test_map_add_too_big_to_realloc(void **_CBOR_UNUSED(_state)) {
195  map = cbor_new_indefinite_map();
196  struct _cbor_map_metadata *metadata =
197      (struct _cbor_map_metadata *)&map->metadata;
198  // Pretend we already have a huge memory block
199  metadata->allocated = SIZE_MAX;
200  metadata->end_ptr = SIZE_MAX;
201  cbor_item_t *one = cbor_build_uint8(1);
202  cbor_item_t *two = cbor_build_uint8(2);
203
204  assert_false(cbor_map_add(map, (struct cbor_pair){.key = one, .value = two}));
205
206  metadata->allocated = 0;
207  metadata->end_ptr = 0;
208  cbor_decref(&map);
209  cbor_decref(&one);
210  cbor_decref(&two);
211}
212
213static void test_map_creation(void **_CBOR_UNUSED(_state)) {
214  WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_map(42)); });
215  WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_map(42)); }, 2, MALLOC,
216                   MALLOC_FAIL);
217
218  WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_map()); });
219}
220
221static void test_map_add(void **_CBOR_UNUSED(_state)) {
222  WITH_MOCK_MALLOC(
223      {
224        cbor_item_t *map = cbor_new_indefinite_map();
225        cbor_item_t *key = cbor_build_uint8(0);
226        cbor_item_t *value = cbor_build_bool(true);
227
228        assert_false(
229            cbor_map_add(map, (struct cbor_pair){.key = key, .value = value}));
230        assert_size_equal(cbor_map_allocated(map), 0);
231        assert_null(map->data);
232
233        cbor_decref(&map);
234        cbor_decref(&key);
235        cbor_decref(&value);
236      },
237      4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
238}
239
240static unsigned char test_indef_map[] = {0xBF, 0x01, 0x02, 0x03, 0x04, 0xFF};
241static void test_indef_map_decode(void **_CBOR_UNUSED(_state)) {
242  WITH_MOCK_MALLOC(
243      {
244        cbor_item_t *map;
245        struct cbor_load_result res;
246        map = cbor_load(test_indef_map, 6, &res);
247
248        assert_null(map);
249        assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
250      },
251      4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
252}
253
254int main(void) {
255  const struct CMUnitTest tests[] = {
256      cmocka_unit_test(test_empty_map),
257      cmocka_unit_test(test_simple_map),
258      cmocka_unit_test(test_indef_simple_map),
259      cmocka_unit_test(test_def_nested_map),
260      cmocka_unit_test(test_streamed_key_map),
261      cmocka_unit_test(test_streamed_kv_map),
262      cmocka_unit_test(test_streamed_streamed_kv_map),
263      cmocka_unit_test(test_map_add_full),
264      cmocka_unit_test(test_map_add_too_big_to_realloc),
265      cmocka_unit_test(test_map_creation),
266      cmocka_unit_test(test_map_add),
267      cmocka_unit_test(test_indef_map_decode),
268  };
269  return cmocka_run_group_tests(tests, NULL, NULL);
270}
271