xref: /freebsd/contrib/libcbor/test/string_test.c (revision abd872540f24cfc7dbd1ea29b6918c7082a22108)
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 <string.h>
9 #include "assertions.h"
10 #include "cbor.h"
11 #include "test_allocator.h"
12 
13 cbor_item_t *string;
14 struct cbor_load_result res;
15 
16 unsigned char empty_string_data[] = {0x60};
17 
18 static void test_empty_string(void **_CBOR_UNUSED(_state)) {
19   string = cbor_load(empty_string_data, 1, &res);
20   assert_non_null(string);
21   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
22   assert_true(cbor_isa_string(string));
23   assert_size_equal(cbor_string_length(string), 0);
24   assert_size_equal(cbor_string_codepoint_count(string), 0);
25   assert_true(res.read == 1);
26   cbor_decref(&string);
27   assert_null(string);
28 }
29 
30 unsigned char short_string_data[] = {0x6C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20,
31                                      0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21};
32 
33 /*                              0x60 + 12 | Hello world! */
34 static void test_short_string(void **_CBOR_UNUSED(_state)) {
35   string = cbor_load(short_string_data, 13, &res);
36   assert_non_null(string);
37   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
38   assert_true(cbor_isa_string(string));
39   assert_size_equal(cbor_string_length(string), 12);
40   assert_size_equal(cbor_string_codepoint_count(string), 12);
41   assert_memory_equal(&"Hello world!", cbor_string_handle(string), 12);
42   assert_true(res.read == 13);
43   cbor_decref(&string);
44   assert_null(string);
45 }
46 
47 unsigned char short_multibyte_string_data[] = {
48     0x6F, 0xC4, 0x8C, 0x61, 0x75, 0x65, 0x73, 0x20,
49     0xC3, 0x9F, 0x76, 0xC4, 0x9B, 0x74, 0x65, 0x21};
50 
51 /*                              0x60 + 15 | Čaues ßvěte! */
52 static void test_short_multibyte_string(void **_CBOR_UNUSED(_state)) {
53   string = cbor_load(short_multibyte_string_data, 16, &res);
54   assert_non_null(string);
55   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
56   assert_true(cbor_isa_string(string));
57   assert_size_equal(cbor_string_length(string), 15);
58   assert_size_equal(cbor_string_codepoint_count(string), 12);
59   assert_memory_equal(&"Čaues ßvěte!", cbor_string_handle(string), 15);
60   assert_true(res.read == 16);
61   cbor_decref(&string);
62   assert_null(string);
63 }
64 
65 unsigned char int8_string_data[] = {
66     0x78, 0x96, 0x4C, 0x6F, 0x72, 0x65, 0x6D, 0x20, 0x69, 0x70, 0x73, 0x75,
67     0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20,
68     0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63,
69     0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73,
70     0x63, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x69, 0x74, 0x2E, 0x20, 0x44,
71     0x6F, 0x6E, 0x65, 0x63, 0x20, 0x6D, 0x69, 0x20, 0x74, 0x65, 0x6C, 0x6C,
72     0x75, 0x73, 0x2C, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6C, 0x69, 0x73, 0x20,
73     0x6E, 0x65, 0x63, 0x20, 0x76, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6C,
74     0x75, 0x6D, 0x20, 0x71, 0x75, 0x69, 0x73, 0x2C, 0x20, 0x66, 0x65, 0x72,
75     0x6D, 0x65, 0x6E, 0x74, 0x75, 0x6D, 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x66,
76     0x65, 0x6C, 0x69, 0x73, 0x2E, 0x20, 0x4D, 0x61, 0x65, 0x63, 0x65, 0x6E,
77     0x61, 0x73, 0x20, 0x75, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x6F, 0x20,
78     0x70, 0x6F, 0x73, 0x75, 0x65, 0x72, 0x65, 0x2E};
79 
80 /*                                          150 | Lorem ....*/
81 static void test_int8_string(void **_CBOR_UNUSED(_state)) {
82   string = cbor_load(int8_string_data, 152, &res);
83   assert_non_null(string);
84   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
85   assert_true(cbor_isa_string(string));
86   assert_size_equal(cbor_string_length(string), 150);
87   assert_size_equal(cbor_string_codepoint_count(string), 150);
88   assert_memory_equal(
89 		&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
90 		cbor_string_handle(string),
91 		150
92 	);
93   assert_true(res.read == 152);
94   cbor_decref(&string);
95   assert_null(string);
96 }
97 
98 unsigned char int16_string_data[] = {
99     0x79, 0x00, 0x96, 0x4C, 0x6F, 0x72, 0x65, 0x6D, 0x20, 0x69, 0x70, 0x73,
100     0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74,
101     0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65,
102     0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69,
103     0x73, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x69, 0x74, 0x2E, 0x20,
104     0x44, 0x6F, 0x6E, 0x65, 0x63, 0x20, 0x6D, 0x69, 0x20, 0x74, 0x65, 0x6C,
105     0x6C, 0x75, 0x73, 0x2C, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6C, 0x69, 0x73,
106     0x20, 0x6E, 0x65, 0x63, 0x20, 0x76, 0x65, 0x73, 0x74, 0x69, 0x62, 0x75,
107     0x6C, 0x75, 0x6D, 0x20, 0x71, 0x75, 0x69, 0x73, 0x2C, 0x20, 0x66, 0x65,
108     0x72, 0x6D, 0x65, 0x6E, 0x74, 0x75, 0x6D, 0x20, 0x6E, 0x6F, 0x6E, 0x20,
109     0x66, 0x65, 0x6C, 0x69, 0x73, 0x2E, 0x20, 0x4D, 0x61, 0x65, 0x63, 0x65,
110     0x6E, 0x61, 0x73, 0x20, 0x75, 0x74, 0x20, 0x6A, 0x75, 0x73, 0x74, 0x6F,
111     0x20, 0x70, 0x6F, 0x73, 0x75, 0x65, 0x72, 0x65, 0x2E};
112 /*                                          150 | Lorem ....*/
113 /* This valid but not realistic - length 150 could be encoded in a single
114  * uint8_t (but we need to keep the test files reasonably compact) */
115 static void test_int16_string(void **_CBOR_UNUSED(_state)) {
116   string = cbor_load(int16_string_data, 153, &res);
117   assert_non_null(string);
118   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
119   assert_true(cbor_isa_string(string));
120   assert_size_equal(cbor_string_length(string), 150);
121   assert_size_equal(cbor_string_codepoint_count(string), 150);
122   assert_memory_equal(
123 		&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
124 		cbor_string_handle(string),
125 		150
126 	);
127   assert_true(res.read == 153);
128   cbor_decref(&string);
129   assert_null(string);
130 }
131 
132 unsigned char int32_string_data[] = {
133     0x7A, 0x00, 0x00, 0x00, 0x96, 0x4C, 0x6F, 0x72, 0x65, 0x6D, 0x20, 0x69,
134     0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73,
135     0x69, 0x74, 0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E,
136     0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72, 0x20, 0x61, 0x64, 0x69,
137     0x70, 0x69, 0x73, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6C, 0x69, 0x74,
138     0x2E, 0x20, 0x44, 0x6F, 0x6E, 0x65, 0x63, 0x20, 0x6D, 0x69, 0x20, 0x74,
139     0x65, 0x6C, 0x6C, 0x75, 0x73, 0x2C, 0x20, 0x69, 0x61, 0x63, 0x75, 0x6C,
140     0x69, 0x73, 0x20, 0x6E, 0x65, 0x63, 0x20, 0x76, 0x65, 0x73, 0x74, 0x69,
141     0x62, 0x75, 0x6C, 0x75, 0x6D, 0x20, 0x71, 0x75, 0x69, 0x73, 0x2C, 0x20,
142     0x66, 0x65, 0x72, 0x6D, 0x65, 0x6E, 0x74, 0x75, 0x6D, 0x20, 0x6E, 0x6F,
143     0x6E, 0x20, 0x66, 0x65, 0x6C, 0x69, 0x73, 0x2E, 0x20, 0x4D, 0x61, 0x65,
144     0x63, 0x65, 0x6E, 0x61, 0x73, 0x20, 0x75, 0x74, 0x20, 0x6A, 0x75, 0x73,
145     0x74, 0x6F, 0x20, 0x70, 0x6F, 0x73, 0x75, 0x65, 0x72, 0x65, 0x2E};
146 
147 /*                                          150 | Lorem ....*/
148 static void test_int32_string(void **_CBOR_UNUSED(_state)) {
149   string = cbor_load(int32_string_data, 155, &res);
150   assert_non_null(string);
151   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
152   assert_true(cbor_isa_string(string));
153   assert_size_equal(cbor_string_length(string), 150);
154   assert_size_equal(cbor_string_codepoint_count(string), 150);
155   assert_memory_equal(
156 		&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
157 		cbor_string_handle(string),
158 		150
159 	);
160   assert_true(res.read == 155);
161   cbor_decref(&string);
162   assert_null(string);
163 }
164 
165 unsigned char int64_string_data[] = {
166     0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x4C, 0x6F, 0x72,
167     0x65, 0x6D, 0x20, 0x69, 0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C,
168     0x6F, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C,
169     0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74, 0x75, 0x72,
170     0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, 0x69, 0x6E, 0x67, 0x20,
171     0x65, 0x6C, 0x69, 0x74, 0x2E, 0x20, 0x44, 0x6F, 0x6E, 0x65, 0x63, 0x20,
172     0x6D, 0x69, 0x20, 0x74, 0x65, 0x6C, 0x6C, 0x75, 0x73, 0x2C, 0x20, 0x69,
173     0x61, 0x63, 0x75, 0x6C, 0x69, 0x73, 0x20, 0x6E, 0x65, 0x63, 0x20, 0x76,
174     0x65, 0x73, 0x74, 0x69, 0x62, 0x75, 0x6C, 0x75, 0x6D, 0x20, 0x71, 0x75,
175     0x69, 0x73, 0x2C, 0x20, 0x66, 0x65, 0x72, 0x6D, 0x65, 0x6E, 0x74, 0x75,
176     0x6D, 0x20, 0x6E, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x6C, 0x69, 0x73, 0x2E,
177     0x20, 0x4D, 0x61, 0x65, 0x63, 0x65, 0x6E, 0x61, 0x73, 0x20, 0x75, 0x74,
178     0x20, 0x6A, 0x75, 0x73, 0x74, 0x6F, 0x20, 0x70, 0x6F, 0x73, 0x75, 0x65,
179     0x72, 0x65, 0x2E};
180 
181 /*                                          150 | Lorem ....*/
182 static void test_int64_string(void **_CBOR_UNUSED(_state)) {
183   string = cbor_load(int64_string_data, 159, &res);
184   assert_non_null(string);
185   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
186   assert_true(cbor_isa_string(string));
187   assert_size_equal(cbor_string_length(string), 150);
188   assert_size_equal(cbor_string_codepoint_count(string), 150);
189   assert_memory_equal(
190 		&"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec mi tellus, iaculis nec vestibulum quis, fermentum non felis. Maecenas ut justo posuere.",
191 		cbor_string_handle(string),
192 		150
193 	);
194   assert_true(res.read == 159);
195   cbor_decref(&string);
196   assert_null(string);
197 }
198 
199 unsigned char short_indef_string_data[] = {0x7F, 0x78, 0x01, 0x65, 0xFF, 0xFF};
200 
201 /*                                         start |   string      | break| extra
202  */
203 
204 static void test_short_indef_string(void **_CBOR_UNUSED(_state)) {
205   string = cbor_load(short_indef_string_data, 6, &res);
206   assert_non_null(string);
207   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
208   assert_true(cbor_isa_string(string));
209   assert_true(cbor_string_length(string) == 0);
210   assert_true(cbor_string_is_indefinite(string));
211   assert_true(cbor_string_chunk_count(string) == 1);
212   assert_true(res.read == 5);
213   assert_true(cbor_isa_string(cbor_string_chunks_handle(string)[0]));
214   assert_true(cbor_string_length(cbor_string_chunks_handle(string)[0]) == 1);
215   assert_true(*cbor_string_handle(cbor_string_chunks_handle(string)[0]) == 'e');
216   cbor_decref(&string);
217   assert_null(string);
218 }
219 
220 static void test_invalid_utf(void **_CBOR_UNUSED(_state)) {
221   /* 0x60 + 1 | 0xC5 (invalid unfinished 2B codepoint) */
222   unsigned char string_data[] = {0x61, 0xC5};
223   string = cbor_load(string_data, 2, &res);
224 
225   assert_non_null(string);
226   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
227   assert_true(cbor_isa_string(string));
228   assert_size_equal(cbor_string_length(string), 1);
229   assert_size_equal(cbor_string_codepoint_count(string), 0);
230   assert_true(cbor_string_is_definite(string));
231   assert_true(res.read == 2);
232 
233   cbor_decref(&string);
234 }
235 
236 static void test_inline_creation(void **_CBOR_UNUSED(_state)) {
237   string = cbor_build_string("Hello!");
238   assert_memory_equal(cbor_string_handle(string), "Hello!", strlen("Hello!"));
239   cbor_decref(&string);
240 }
241 
242 static void test_string_creation(void **_CBOR_UNUSED(_state)) {
243   WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_string()); });
244 
245   WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_string()); });
246   WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_string()); }, 2, MALLOC,
247                    MALLOC_FAIL);
248 
249   WITH_FAILING_MALLOC({ assert_null(cbor_build_string("Test")); });
250   WITH_MOCK_MALLOC({ assert_null(cbor_build_string("Test")); }, 2, MALLOC,
251                    MALLOC_FAIL);
252 
253   WITH_FAILING_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); });
254   WITH_MOCK_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); }, 2, MALLOC,
255                    MALLOC_FAIL);
256 }
257 
258 static void test_string_add_chunk(void **_CBOR_UNUSED(_state)) {
259   WITH_MOCK_MALLOC(
260       {
261         cbor_item_t *string = cbor_new_indefinite_string();
262         cbor_item_t *chunk = cbor_build_string("Hello!");
263 
264         assert_false(cbor_string_add_chunk(string, chunk));
265         assert_size_equal(cbor_string_chunk_count(string), 0);
266         assert_size_equal(((struct cbor_indefinite_string_data *)string->data)
267                               ->chunk_capacity,
268                           0);
269 
270         cbor_decref(&chunk);
271         cbor_decref(&string);
272       },
273       5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
274 }
275 
276 static void test_add_chunk_reallocation_overflow(void **_CBOR_UNUSED(_state)) {
277   string = cbor_new_indefinite_string();
278   cbor_item_t *chunk = cbor_build_string("Hello!");
279   struct cbor_indefinite_string_data *metadata =
280       (struct cbor_indefinite_string_data *)string->data;
281   // Pretend we already have many chunks allocated
282   metadata->chunk_count = SIZE_MAX;
283   metadata->chunk_capacity = SIZE_MAX;
284 
285   assert_false(cbor_string_add_chunk(string, chunk));
286   assert_size_equal(cbor_refcount(chunk), 1);
287 
288   metadata->chunk_count = 0;
289   metadata->chunk_capacity = 0;
290   cbor_decref(&chunk);
291   cbor_decref(&string);
292 }
293 
294 static void test_set_handle(void **_CBOR_UNUSED(_state)) {
295   string = cbor_new_definite_string();
296   char *test_string = "Hello";
297   unsigned char *string_data = malloc(strlen(test_string));
298   memcpy(string_data, test_string, strlen(test_string));
299   assert_ptr_not_equal(string_data, NULL);
300   cbor_string_set_handle(string, string_data, strlen(test_string));
301 
302   assert_ptr_equal(cbor_string_handle(string), string_data);
303   assert_size_equal(cbor_string_length(string), 5);
304   assert_size_equal(cbor_string_codepoint_count(string), 5);
305 
306   cbor_decref(&string);
307 }
308 
309 static void test_set_handle_multibyte_codepoint(void **_CBOR_UNUSED(_state)) {
310   string = cbor_new_definite_string();
311   // "Štěstíčko" in UTF-8
312   char *test_string = "\xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko";
313   unsigned char *string_data = malloc(strlen(test_string));
314   memcpy(string_data, test_string, strlen(test_string));
315   assert_ptr_not_equal(string_data, NULL);
316   cbor_string_set_handle(string, string_data, strlen(test_string));
317 
318   assert_ptr_equal(cbor_string_handle(string), string_data);
319   assert_size_equal(cbor_string_length(string), 13);
320   assert_size_equal(cbor_string_codepoint_count(string), 9);
321 
322   cbor_decref(&string);
323 }
324 
325 static void test_set_handle_invalid_utf(void **_CBOR_UNUSED(_state)) {
326   string = cbor_new_definite_string();
327   // Invalid multi-byte character (missing the second byte).
328   char *test_string = "Test: \xc5";
329   unsigned char *string_data = malloc(strlen(test_string));
330   memcpy(string_data, test_string, strlen(test_string));
331   assert_ptr_not_equal(string_data, NULL);
332   cbor_string_set_handle(string, string_data, strlen(test_string));
333 
334   assert_ptr_equal(cbor_string_handle(string), string_data);
335   assert_size_equal(cbor_string_length(string), 7);
336   assert_size_equal(cbor_string_codepoint_count(string), 0);
337 
338   cbor_decref(&string);
339 }
340 
341 int main(void) {
342   const struct CMUnitTest tests[] = {
343       cmocka_unit_test(test_empty_string),
344       cmocka_unit_test(test_short_string),
345       cmocka_unit_test(test_short_multibyte_string),
346       cmocka_unit_test(test_int8_string),
347       cmocka_unit_test(test_int16_string),
348       cmocka_unit_test(test_int32_string),
349       cmocka_unit_test(test_int64_string),
350       cmocka_unit_test(test_short_indef_string),
351       cmocka_unit_test(test_invalid_utf),
352       cmocka_unit_test(test_inline_creation),
353       cmocka_unit_test(test_string_creation),
354       cmocka_unit_test(test_string_add_chunk),
355       cmocka_unit_test(test_add_chunk_reallocation_overflow),
356       cmocka_unit_test(test_set_handle),
357       cmocka_unit_test(test_set_handle_multibyte_codepoint),
358       cmocka_unit_test(test_set_handle_invalid_utf),
359   };
360   return cmocka_run_group_tests(tests, NULL, NULL);
361 }
362