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 <stdio.h>
9#include <string.h>
10
11#include "assertions.h"
12#include "cbor.h"
13
14void assert_describe_result(cbor_item_t *item, char *expected_result) {
15#if CBOR_PRETTY_PRINTER
16  // We know the expected size based on `expected_result`, but read everything
17  // in order to get the full actual output in a useful error message.
18  const size_t buffer_size = 512;
19  FILE *outfile = tmpfile();
20  cbor_describe(item, outfile);
21  rewind(outfile);
22  // Treat string as null-terminated since cmocka doesn't have asserts
23  // for explicit length strings.
24  char *output = malloc(buffer_size);
25  assert_non_null(output);
26  size_t output_size = fread(output, sizeof(char), buffer_size, outfile);
27  output[output_size] = '\0';
28  assert_string_equal(output, expected_result);
29  assert_true(feof(outfile));
30  free(output);
31  fclose(outfile);
32#endif
33}
34
35static void test_uint(void **_CBOR_UNUSED(_state)) {
36  cbor_item_t *item = cbor_build_uint8(42);
37  assert_describe_result(item, "[CBOR_TYPE_UINT] Width: 1B, Value: 42\n");
38  cbor_decref(&item);
39}
40
41static void test_negint(void **_CBOR_UNUSED(_state)) {
42  cbor_item_t *item = cbor_build_negint16(40);
43  assert_describe_result(item,
44                         "[CBOR_TYPE_NEGINT] Width: 2B, Value: -40 - 1\n");
45  cbor_decref(&item);
46}
47
48static void test_definite_bytestring(void **_CBOR_UNUSED(_state)) {
49  unsigned char data[] = {0x01, 0x02, 0x03};
50  cbor_item_t *item = cbor_build_bytestring(data, 3);
51  assert_describe_result(item,
52                         "[CBOR_TYPE_BYTESTRING] Definite, Length: 3B, Data:\n"
53                         "    010203\n");
54  cbor_decref(&item);
55}
56
57static void test_indefinite_bytestring(void **_CBOR_UNUSED(_state)) {
58  unsigned char data[] = {0x01, 0x02, 0x03};
59  cbor_item_t *item = cbor_new_indefinite_bytestring();
60  assert_true(cbor_bytestring_add_chunk(
61      item, cbor_move(cbor_build_bytestring(data, 3))));
62  assert_true(cbor_bytestring_add_chunk(
63      item, cbor_move(cbor_build_bytestring(data, 2))));
64  assert_describe_result(
65      item,
66      "[CBOR_TYPE_BYTESTRING] Indefinite, Chunks: 2, Chunk data:\n"
67      "    [CBOR_TYPE_BYTESTRING] Definite, Length: 3B, Data:\n"
68      "        010203\n"
69      "    [CBOR_TYPE_BYTESTRING] Definite, Length: 2B, Data:\n"
70      "        0102\n");
71  cbor_decref(&item);
72}
73
74static void test_definite_string(void **_CBOR_UNUSED(_state)) {
75  char *string = "Hello!";
76  cbor_item_t *item = cbor_build_string(string);
77  assert_describe_result(
78      item,
79      "[CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
80      "    Hello!\n");
81  cbor_decref(&item);
82}
83
84static void test_indefinite_string(void **_CBOR_UNUSED(_state)) {
85  char *string = "Hello!";
86  cbor_item_t *item = cbor_new_indefinite_string();
87  assert_true(
88      cbor_string_add_chunk(item, cbor_move(cbor_build_string(string))));
89  assert_true(
90      cbor_string_add_chunk(item, cbor_move(cbor_build_string(string))));
91  assert_describe_result(
92      item,
93      "[CBOR_TYPE_STRING] Indefinite, Chunks: 2, Chunk data:\n"
94      "    [CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
95      "        Hello!\n"
96      "    [CBOR_TYPE_STRING] Definite, Length: 6B, Codepoints: 6, Data:\n"
97      "        Hello!\n");
98  cbor_decref(&item);
99}
100
101static void test_multibyte_string(void **_CBOR_UNUSED(_state)) {
102  // "��t��st����ko" in UTF-8
103  char *string = "\xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko";
104  cbor_item_t *item = cbor_build_string(string);
105  assert_describe_result(
106      item,
107      "[CBOR_TYPE_STRING] Definite, Length: 13B, Codepoints: 9, Data:\n"
108      "    \xc5\xa0t\xc4\x9bst\xc3\xad\xc4\x8dko\n");
109  cbor_decref(&item);
110}
111
112static void test_definite_array(void **_CBOR_UNUSED(_state)) {
113  cbor_item_t *item = cbor_new_definite_array(2);
114  assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(1))));
115  assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(2))));
116  assert_describe_result(item,
117                         "[CBOR_TYPE_ARRAY] Definite, Size: 2, Contents:\n"
118                         "    [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
119                         "    [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
120  cbor_decref(&item);
121}
122
123static void test_indefinite_array(void **_CBOR_UNUSED(_state)) {
124  cbor_item_t *item = cbor_new_indefinite_array();
125  assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(1))));
126  assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(2))));
127  assert_describe_result(item,
128                         "[CBOR_TYPE_ARRAY] Indefinite, Size: 2, Contents:\n"
129                         "    [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
130                         "    [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
131  cbor_decref(&item);
132}
133
134static void test_definite_map(void **_CBOR_UNUSED(_state)) {
135  cbor_item_t *item = cbor_new_definite_map(1);
136  assert_true(cbor_map_add(
137      item, (struct cbor_pair){.key = cbor_move(cbor_build_uint8(1)),
138                               .value = cbor_move(cbor_build_uint8(2))}));
139  assert_describe_result(item,
140                         "[CBOR_TYPE_MAP] Definite, Size: 1, Contents:\n"
141                         "    Map entry 0\n"
142                         "        [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
143                         "        [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
144  cbor_decref(&item);
145}
146
147static void test_indefinite_map(void **_CBOR_UNUSED(_state)) {
148  cbor_item_t *item = cbor_new_indefinite_map();
149  assert_true(cbor_map_add(
150      item, (struct cbor_pair){.key = cbor_move(cbor_build_uint8(1)),
151                               .value = cbor_move(cbor_build_uint8(2))}));
152  assert_describe_result(item,
153                         "[CBOR_TYPE_MAP] Indefinite, Size: 1, Contents:\n"
154                         "    Map entry 0\n"
155                         "        [CBOR_TYPE_UINT] Width: 1B, Value: 1\n"
156                         "        [CBOR_TYPE_UINT] Width: 1B, Value: 2\n");
157  cbor_decref(&item);
158}
159
160static void test_tag(void **_CBOR_UNUSED(_state)) {
161  cbor_item_t *item = cbor_build_tag(42, cbor_move(cbor_build_uint8(1)));
162  assert_describe_result(item,
163                         "[CBOR_TYPE_TAG] Value: 42\n"
164                         "    [CBOR_TYPE_UINT] Width: 1B, Value: 1\n");
165  cbor_decref(&item);
166}
167
168static void test_floats(void **_CBOR_UNUSED(_state)) {
169  cbor_item_t *item = cbor_new_indefinite_array();
170  assert_true(cbor_array_push(item, cbor_move(cbor_build_bool(true))));
171  assert_true(
172      cbor_array_push(item, cbor_move(cbor_build_ctrl(CBOR_CTRL_UNDEF))));
173  assert_true(
174      cbor_array_push(item, cbor_move(cbor_build_ctrl(CBOR_CTRL_NULL))));
175  assert_true(cbor_array_push(item, cbor_move(cbor_build_ctrl(24))));
176  assert_true(cbor_array_push(item, cbor_move(cbor_build_float4(3.14f))));
177  assert_describe_result(
178      item,
179      "[CBOR_TYPE_ARRAY] Indefinite, Size: 5, Contents:\n"
180      "    [CBOR_TYPE_FLOAT_CTRL] Bool: true\n"
181      "    [CBOR_TYPE_FLOAT_CTRL] Undefined\n"
182      "    [CBOR_TYPE_FLOAT_CTRL] Null\n"
183      "    [CBOR_TYPE_FLOAT_CTRL] Simple value: 24\n"
184      "    [CBOR_TYPE_FLOAT_CTRL] Width: 4B, Value: 3.140000\n");
185  cbor_decref(&item);
186}
187
188int main(void) {
189  const struct CMUnitTest tests[] = {
190      cmocka_unit_test(test_uint),
191      cmocka_unit_test(test_negint),
192      cmocka_unit_test(test_definite_bytestring),
193      cmocka_unit_test(test_indefinite_bytestring),
194      cmocka_unit_test(test_definite_string),
195      cmocka_unit_test(test_indefinite_string),
196      cmocka_unit_test(test_multibyte_string),
197      cmocka_unit_test(test_definite_array),
198      cmocka_unit_test(test_indefinite_array),
199      cmocka_unit_test(test_definite_map),
200      cmocka_unit_test(test_indefinite_map),
201      cmocka_unit_test(test_tag),
202      cmocka_unit_test(test_floats),
203  };
204  return cmocka_run_group_tests(tests, NULL, NULL);
205}
206