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 *arr;
13struct cbor_load_result res;
14
15unsigned char data1[] = {0x80, 0xFF};
16
17static void test_empty_array(void **_CBOR_UNUSED(_state)) {
18  arr = cbor_load(data1, 2, &res);
19  assert_non_null(arr);
20  assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
21  assert_true(cbor_isa_array(arr));
22  assert_true(cbor_array_size(arr) == 0);
23  assert_true(res.read == 1);
24  cbor_decref(&arr);
25  assert_null(arr);
26}
27
28unsigned char data2[] = {0x81, 0x01, 0xFF};
29
30static void test_simple_array(void **_CBOR_UNUSED(_state)) {
31  arr = cbor_load(data2, 3, &res);
32  assert_non_null(arr);
33  assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
34  assert_true(cbor_isa_array(arr));
35  assert_size_equal(cbor_array_size(arr), 1);
36  assert_true(res.read == 2);
37  assert_size_equal(cbor_array_allocated(arr), 1);
38  /* Check the values */
39  assert_uint8(cbor_array_handle(arr)[0], 1);
40  cbor_item_t *intermediate = cbor_array_get(arr, 0);
41  assert_uint8(intermediate, 1);
42
43  cbor_item_t *new_val = cbor_build_uint8(10);
44  assert_false(cbor_array_set(arr, 1, new_val));
45  assert_false(cbor_array_set(arr, 3, new_val));
46  cbor_decref(&new_val);
47
48  cbor_decref(&arr);
49  cbor_decref(&intermediate);
50  assert_null(arr);
51  assert_null(intermediate);
52}
53
54unsigned char data3[] = {0x82, 0x01, 0x81, 0x01, 0xFF};
55
56static void test_nested_arrays(void **_CBOR_UNUSED(_state)) {
57  arr = cbor_load(data3, 5, &res);
58  assert_non_null(arr);
59  assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
60  assert_true(cbor_isa_array(arr));
61  assert_true(cbor_array_size(arr) == 2);
62  assert_true(res.read == 4);
63  /* Check the values */
64  assert_uint8(cbor_array_handle(arr)[0], 1);
65
66  cbor_item_t *nested = cbor_array_handle(arr)[1];
67  assert_true(cbor_isa_array(nested));
68  assert_true(cbor_array_size(nested) == 1);
69  assert_uint8(cbor_array_handle(nested)[0], 1);
70
71  cbor_decref(&arr);
72  assert_null(arr);
73}
74
75unsigned char test_indef_arrays_data[] = {0x9f, 0x01, 0x02, 0xFF};
76
77static void test_indef_arrays(void **_CBOR_UNUSED(_state)) {
78  arr = cbor_load(test_indef_arrays_data, 4, &res);
79  assert_non_null(arr);
80  assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
81  assert_true(cbor_isa_array(arr));
82  assert_true(cbor_array_size(arr) == 2);
83  assert_true(res.read == 4);
84  /* Check the values */
85  assert_uint8(cbor_array_handle(arr)[0], 1);
86  assert_uint8(cbor_array_handle(arr)[1], 2);
87
88  assert_true(cbor_array_set(arr, 1, cbor_move(cbor_build_uint8(10))));
89
90  cbor_decref(&arr);
91  assert_null(arr);
92}
93
94unsigned char test_nested_indef_arrays_data[] = {0x9f, 0x01, 0x9f, 0x02,
95                                                 0xFF, 0x03, 0xFF};
96
97static void test_nested_indef_arrays(void **_CBOR_UNUSED(_state)) {
98  arr = cbor_load(test_nested_indef_arrays_data, 7, &res);
99  assert_non_null(arr);
100  assert_true(cbor_typeof(arr) == CBOR_TYPE_ARRAY);
101  assert_true(cbor_isa_array(arr));
102  assert_size_equal(cbor_array_size(arr), 3);
103  assert_true(res.read == 7);
104  /* Check the values */
105  assert_uint8(cbor_array_handle(arr)[0], 1);
106
107  cbor_item_t *nested = cbor_array_handle(arr)[1];
108  assert_true(cbor_isa_array(nested));
109  assert_true(cbor_array_size(nested) == 1);
110  assert_uint8(cbor_array_handle(nested)[0], 2);
111
112  cbor_decref(&arr);
113  assert_null(arr);
114}
115
116static void test_array_replace(void **_CBOR_UNUSED(_state)) {
117  cbor_item_t *array = cbor_new_definite_array(2);
118  assert_size_equal(cbor_array_size(array), 0);
119  cbor_item_t *one = cbor_build_uint8(1);
120  cbor_item_t *three = cbor_build_uint8(3);
121  assert_size_equal(cbor_refcount(one), 1);
122  assert_size_equal(cbor_refcount(three), 1);
123
124  // No item to replace
125  assert_false(cbor_array_replace(array, 0, three));
126  assert_size_equal(cbor_refcount(three), 1);
127
128  // Add items [1, 2]
129  assert_true(cbor_array_push(array, one));
130  assert_true(cbor_array_push(array, cbor_move(cbor_build_uint8(2))));
131  assert_size_equal(cbor_refcount(one), 2);
132  assert_size_equal(cbor_array_size(array), 2);
133
134  // Array has only two items
135  assert_false(cbor_array_replace(array, 2, three));
136  assert_size_equal(cbor_refcount(three), 1);
137
138  // Change [1, 2] to [3, 2]
139  assert_true(cbor_array_replace(array, 0, three));
140  assert_size_equal(cbor_refcount(one), 1);
141  assert_size_equal(cbor_refcount(three), 2);
142  assert_uint8(cbor_move(cbor_array_get(array, 0)), 3);
143  assert_uint8(cbor_move(cbor_array_get(array, 1)), 2);
144
145  cbor_decref(&one);
146  cbor_decref(&three);
147  cbor_decref(&array);
148}
149
150static void test_array_push_overflow(void **_CBOR_UNUSED(_state)) {
151  cbor_item_t *array = cbor_new_indefinite_array();
152  cbor_item_t *one = cbor_build_uint8(1);
153  struct _cbor_array_metadata *metadata =
154      (struct _cbor_array_metadata *)&array->metadata;
155  // Pretend we already have a huge block allocated
156  metadata->allocated = SIZE_MAX;
157  metadata->end_ptr = SIZE_MAX;
158
159  assert_false(cbor_array_push(array, one));
160  assert_size_equal(cbor_refcount(one), 1);
161
162  cbor_decref(&one);
163  metadata->allocated = 0;
164  metadata->end_ptr = 0;
165  cbor_decref(&array);
166}
167
168static void test_array_creation(void **_CBOR_UNUSED(_state)) {
169  WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_array(42)); });
170  WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_array(42)); }, 2, MALLOC,
171                   MALLOC_FAIL);
172
173  WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_array()); });
174}
175
176static void test_array_push(void **_CBOR_UNUSED(_state)) {
177  WITH_MOCK_MALLOC(
178      {
179        cbor_item_t *array = cbor_new_indefinite_array();
180        cbor_item_t *string = cbor_build_string("Hello!");
181
182        assert_false(cbor_array_push(array, string));
183        assert_size_equal(cbor_array_allocated(array), 0);
184        assert_null(array->data);
185        assert_size_equal(array->metadata.array_metadata.end_ptr, 0);
186
187        cbor_decref(&string);
188        cbor_decref(&array);
189      },
190      4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
191}
192
193static unsigned char simple_indef_array[] = {0x9F, 0x01, 0x02, 0xFF};
194static void test_indef_array_decode(void **_CBOR_UNUSED(_state)) {
195  WITH_MOCK_MALLOC(
196      {
197        cbor_item_t *array;
198        struct cbor_load_result res;
199        array = cbor_load(simple_indef_array, 4, &res);
200
201        assert_null(array);
202        assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
203      },
204      4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
205}
206
207int main(void) {
208  const struct CMUnitTest tests[] = {
209      cmocka_unit_test(test_empty_array),
210      cmocka_unit_test(test_simple_array),
211      cmocka_unit_test(test_nested_arrays),
212      cmocka_unit_test(test_indef_arrays),
213      cmocka_unit_test(test_nested_indef_arrays),
214      cmocka_unit_test(test_array_replace),
215      cmocka_unit_test(test_array_push_overflow),
216      cmocka_unit_test(test_array_creation),
217      cmocka_unit_test(test_array_push),
218      cmocka_unit_test(test_indef_array_decode),
219  };
220
221  return cmocka_run_group_tests(tests, NULL, NULL);
222}
223