Branch data Line data Source code
1 : : // Copyright 2011-2025 David Robillard <d@drobilla.net>
2 : : // SPDX-License-Identifier: ISC
3 : :
4 : : #undef NDEBUG
5 : :
6 : : #include <exess/exess.h>
7 : :
8 : : #include <assert.h>
9 : : #include <stdint.h>
10 : : #include <stdlib.h>
11 : : #include <string.h>
12 : :
13 : : static void
14 : 16 : check(const size_t expected_read_count,
15 : : const char* const string,
16 : : const ExessStatus expected_status,
17 : : const size_t expected_write_count,
18 : : const char* const expected_value)
19 : : {
20 : 16 : char buf[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
21 : :
22 : 16 : ExessVariableResult r = exess_read_hex(string, sizeof(buf), buf);
23 [ - + ]: 16 : assert(r.status == expected_status);
24 [ - + ]: 16 : assert(r.read_count == expected_read_count);
25 [ - + ]: 16 : assert(r.write_count == expected_write_count);
26 [ + + - + ]: 16 : assert(r.write_count > 0 || buf[0] == 1);
27 [ + + ]: 16 : if (expected_write_count > 0) {
28 [ - + ]: 6 : assert(!strncmp(buf, expected_value, expected_write_count));
29 [ - + ]: 6 : assert(r.write_count <= exess_decoded_hex_size(strlen(string)));
30 : : }
31 : 16 : }
32 : :
33 : : static void
34 : 1 : test_lowercase(void)
35 : : {
36 : 1 : char buf[6] = {1, 2, 3, 4, 5, 6};
37 : :
38 : 1 : ExessVariableResult r = exess_read_hex("6A6B6C6D6E6F", sizeof(buf), buf);
39 [ - + ]: 1 : assert(r.status == EXESS_SUCCESS);
40 [ - + ]: 1 : assert(r.read_count == 12);
41 [ - + ]: 1 : assert(r.write_count == 6);
42 [ - + ]: 1 : assert(!strncmp(buf, "jklmno", 6));
43 : :
44 : 1 : r = exess_read_hex("6a6b6c6d6e6f", sizeof(buf), buf);
45 [ - + ]: 1 : assert(r.status == EXESS_SUCCESS);
46 [ - + ]: 1 : assert(r.read_count == 12);
47 [ - + ]: 1 : assert(r.write_count == 6);
48 [ - + ]: 1 : assert(!strncmp(buf, "jklmno", 6));
49 : 1 : }
50 : :
51 : : static void
52 : 1 : test_whitespace(void)
53 : : {
54 : 1 : check(6, "666F6F", EXESS_SUCCESS, 3, "foo");
55 : 1 : check(10, "\t\n\r 666F6F", EXESS_SUCCESS, 3, "foo");
56 : 1 : check(6, "666F6F\t\n\r ", EXESS_SUCCESS, 3, "foo");
57 : 1 : check(1, "6\f66F6F", EXESS_EXPECTED_HEX, 0, NULL);
58 : 1 : check(2, "66\n6F6F", EXESS_SUCCESS, 1, "f");
59 : 1 : check(3, "666\rF6F", EXESS_EXPECTED_HEX, 1, "f");
60 : 1 : check(4, "666F\t6F", EXESS_SUCCESS, 2, "fo");
61 : 1 : }
62 : :
63 : : static void
64 : 1 : test_syntax_errors(void)
65 : : {
66 : 1 : check(0, "G6", EXESS_EXPECTED_HEX, 0, NULL);
67 : 1 : check(0, "g6", EXESS_EXPECTED_HEX, 0, NULL);
68 : 1 : check(0, "!6", EXESS_EXPECTED_HEX, 0, NULL);
69 : 1 : check(0, "^6", EXESS_EXPECTED_HEX, 0, NULL);
70 : 1 : check(1, "6G", EXESS_EXPECTED_HEX, 0, NULL);
71 : 1 : check(1, "6g", EXESS_EXPECTED_HEX, 0, NULL);
72 : 1 : check(1, "6!", EXESS_EXPECTED_HEX, 0, NULL);
73 : 1 : check(1, "6^", EXESS_EXPECTED_HEX, 0, NULL);
74 : 1 : check(1, "6", EXESS_EXPECTED_HEX, 0, NULL);
75 : 1 : }
76 : :
77 : : static void
78 : 1 : test_read_overflow(void)
79 : : {
80 : 1 : char buf[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
81 : :
82 : 1 : ExessVariableResult r = exess_read_hex("666F6F", 0U, buf);
83 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
84 [ - + ]: 1 : assert(r.read_count == 6U);
85 [ - + ]: 1 : assert(r.write_count == 3U);
86 [ - + ]: 1 : assert(buf[0] == 1);
87 : :
88 : 1 : r = exess_read_hex("666F6F", 1U, buf);
89 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
90 [ - + ]: 1 : assert(r.read_count == 6U);
91 [ - + ]: 1 : assert(r.write_count == 3U);
92 [ - + ]: 1 : assert(buf[0] == 'f');
93 : :
94 : 1 : r = exess_read_hex("666F6F", 2U, buf);
95 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
96 [ - + ]: 1 : assert(r.read_count == 6U);
97 [ - + ]: 1 : assert(r.write_count == 3U);
98 [ - + ]: 1 : assert(buf[0] == 'f');
99 [ - + ]: 1 : assert(buf[1] == 'o');
100 : :
101 : 1 : r = exess_read_hex("666F6F", 3U, buf);
102 [ - + ]: 1 : assert(r.status == EXESS_SUCCESS);
103 [ - + ]: 1 : assert(r.read_count == 6U);
104 [ - + ]: 1 : assert(r.write_count == 3U);
105 [ - + ]: 1 : assert(!strncmp(buf, "foo", 3));
106 : 1 : }
107 : :
108 : : static void
109 : 1 : test_round_trip(void)
110 : : {
111 [ + + ]: 256 : for (size_t size = 1; size < 256; ++size) {
112 : : // Allocate and generate data
113 : 255 : uint8_t* const data = (uint8_t*)malloc(size);
114 [ - + ]: 255 : assert(data);
115 [ + + ]: 32895 : for (size_t i = 0; i < size; ++i) {
116 : 32640 : data[i] = (uint8_t)((size + i) % 256);
117 : : }
118 : :
119 : : // Allocate buffer for encoding with minimum required size
120 : 255 : const size_t str_len = exess_write_hex(size, data, 0, NULL).count;
121 : 255 : char* const str = (char*)malloc(str_len + 1);
122 [ - + ]: 255 : assert(str);
123 : :
124 : : // Encode data to string buffer
125 [ - + ]: 255 : assert(!exess_write_hex(size, data, str_len + 1, str).status);
126 [ - + ]: 255 : assert(strlen(str) == str_len);
127 [ - + ]: 255 : assert(str_len % 2 == 0);
128 : :
129 : : // Allocate buffer for decoded data with the same size as the input
130 : 255 : uint8_t* const decoded = (uint8_t*)malloc(size);
131 [ - + ]: 255 : assert(decoded);
132 : :
133 : : // Decode and check that data matches the original input
134 : 255 : const ExessVariableResult r = exess_read_hex(str, size, decoded);
135 [ - + ]: 255 : assert(!r.status);
136 [ - + ]: 255 : assert(r.read_count == str_len);
137 [ - + ]: 255 : assert(r.write_count == size);
138 [ - + ]: 255 : assert(!memcmp(decoded, data, size));
139 : :
140 : 255 : free(decoded);
141 : 255 : free(str);
142 : 255 : free(data);
143 : : }
144 : 1 : }
145 : :
146 : : int
147 : 1 : main(void)
148 : : {
149 : 1 : test_lowercase();
150 : 1 : test_whitespace();
151 : 1 : test_syntax_errors();
152 : 1 : test_read_overflow();
153 : 1 : test_round_trip();
154 : :
155 : 1 : return 0;
156 : : }
|