Branch data Line data Source code
1 : : // Copyright 2021-2025 David Robillard <d@drobilla.net>
2 : : // SPDX-License-Identifier: ISC
3 : :
4 : : #undef NDEBUG
5 : :
6 : : #include "decimal_test_utils.h"
7 : : #include "double_test_utils.h"
8 : : #include "float_test_utils.h"
9 : : #include "integer_test_utils.h"
10 : : #include "write_test_utils.h"
11 : :
12 : : #include <exess/exess.h>
13 : :
14 : : #include <assert.h>
15 : : #include <math.h>
16 : : #include <stdbool.h>
17 : : #include <stdint.h>
18 : : #include <string.h>
19 : :
20 : : #define VALUE_SIZE 28U
21 : : #define STRING_SIZE 20U
22 : :
23 : : static const ExessDuration duration = {14,
24 : : (3 * 24 * 60 * 60) + (4 * 60 * 60) +
25 : : (5 * 60) + 6,
26 : : 0};
27 : :
28 : : static const ExessDateTime datetime =
29 : : {2001, 2, 3, EXESS_TIMEZONE_LOCAL, 4, 5, 6, 0};
30 : :
31 : : static const ExessTime time = {EXESS_TIMEZONE_UTC, 1, 2, 3, 0};
32 : : static const ExessDate date = {2001, 2, 3, EXESS_TIMEZONE_UTC};
33 : :
34 : : static void
35 : 65 : check_read(void* value,
36 : : const ExessDatatype datatype,
37 : : const char* const string,
38 : : const ExessStatus expected_status,
39 : : const size_t expected_read_count)
40 : : {
41 : : const ExessVariableResult r =
42 : 65 : exess_read_value(datatype, string, EXESS_MAX_FIXED_SIZE, value);
43 : :
44 [ - + ]: 65 : assert(r.status == expected_status);
45 [ - + ]: 65 : assert(r.read_count == expected_read_count);
46 [ + + ]: 65 : if (!r.status) {
47 [ + + - + ]: 29 : assert(!exess_value_sizes[datatype] ||
48 : : r.write_count == exess_value_sizes[datatype]);
49 : :
50 : : } else {
51 [ - + ]: 36 : assert(!r.write_count);
52 : : }
53 : 65 : }
54 : :
55 : : static void
56 : 5 : check_decimal_value(const void* const decimal, const double number)
57 : : {
58 : 5 : EXESS_ALIGN uint8_t check[VALUE_SIZE] = {0};
59 : 5 : const size_t size = set_decimal_value(sizeof(check), check, number);
60 [ - + ]: 5 : assert(!memcmp(decimal, check, size));
61 : 5 : }
62 : :
63 : : static void
64 : 1 : check_integer_value(const void* const integer, const int64_t number)
65 : : {
66 : 1 : EXESS_ALIGN uint8_t check[VALUE_SIZE] = {0};
67 : 1 : const size_t size = set_integer_value(sizeof(check), check, number);
68 [ - + ]: 1 : assert(!memcmp(integer, check, size));
69 : 1 : }
70 : :
71 : : static void
72 : 1 : test_read_value(void)
73 : : {
74 : : {
75 : 1 : int64_t a_long = 0;
76 : : const ExessVariableResult bad =
77 : 1 : exess_read_value(EXESS_LONG, "1", 7, &a_long);
78 [ - + ]: 1 : assert(bad.status == EXESS_NO_SPACE);
79 : : }
80 : : {
81 : 1 : bool a_bool = false;
82 : 1 : check_read(&a_bool, EXESS_BOOLEAN, "x", EXESS_EXPECTED_BOOLEAN, 0);
83 : 1 : check_read(&a_bool, EXESS_BOOLEAN, "true", EXESS_SUCCESS, 4);
84 [ - + ]: 1 : assert(a_bool);
85 : : }
86 : : {
87 : 1 : EXESS_ALIGN uint8_t a_decimal[VALUE_SIZE] = {0};
88 : 1 : check_read(a_decimal, EXESS_DECIMAL, "1.2", EXESS_SUCCESS, 3);
89 : 1 : check_decimal_value(a_decimal, 1.2);
90 : : }
91 : : {
92 : 1 : double a_double = (double)NAN;
93 : 1 : check_read(&a_double, EXESS_DOUBLE, "3.4", EXESS_SUCCESS, 3);
94 [ - + ]: 1 : assert(double_matches(a_double, 3.4));
95 : : }
96 : : {
97 : 1 : float a_float = NAN;
98 : 1 : check_read(&a_float, EXESS_FLOAT, "x", EXESS_EXPECTED_DIGIT, 0);
99 : :
100 : 1 : check_read(&a_float, EXESS_FLOAT, "5.6", EXESS_SUCCESS, 3);
101 [ - + ]: 1 : assert(float_matches(a_float, 5.6f));
102 : : }
103 : : {
104 : 1 : EXESS_ALIGN uint8_t a_decimal[VALUE_SIZE] = {0};
105 : :
106 : 1 : check_read(a_decimal, EXESS_NOTHING, "42", EXESS_UNSUPPORTED, 0);
107 : :
108 : 1 : check_read(a_decimal, EXESS_INTEGER, "x", EXESS_EXPECTED_DIGIT, 0);
109 : 1 : check_read(a_decimal, EXESS_INTEGER, "7", EXESS_SUCCESS, 1);
110 : 1 : check_decimal_value(a_decimal, 7.0);
111 : :
112 : 1 : check_read(
113 : : a_decimal, EXESS_NON_POSITIVE_INTEGER, "x", EXESS_EXPECTED_DIGIT, 0);
114 : 1 : check_read(
115 : : a_decimal, EXESS_NON_POSITIVE_INTEGER, "1", EXESS_OUT_OF_RANGE, 1);
116 : 1 : check_read(a_decimal, EXESS_NON_POSITIVE_INTEGER, "-8", EXESS_SUCCESS, 2);
117 : 1 : check_decimal_value(a_decimal, -8.0);
118 : :
119 : 1 : check_read(a_decimal, EXESS_NEGATIVE_INTEGER, "x", EXESS_EXPECTED_DIGIT, 0);
120 : 1 : check_read(a_decimal, EXESS_NEGATIVE_INTEGER, "1", EXESS_OUT_OF_RANGE, 1);
121 : 1 : check_read(a_decimal, EXESS_NEGATIVE_INTEGER, "-9", EXESS_SUCCESS, 2);
122 : 1 : check_decimal_value(a_decimal, -9.0);
123 : :
124 : 1 : check_read(
125 : : a_decimal, EXESS_NON_NEGATIVE_INTEGER, "x", EXESS_EXPECTED_DIGIT, 0);
126 : 1 : check_read(
127 : : a_decimal, EXESS_NON_NEGATIVE_INTEGER, "-1", EXESS_OUT_OF_RANGE, 2);
128 : 1 : check_read(a_decimal, EXESS_NON_NEGATIVE_INTEGER, "-0", EXESS_SUCCESS, 2);
129 : 1 : check_read(a_decimal, EXESS_NON_NEGATIVE_INTEGER, "0", EXESS_SUCCESS, 1);
130 : 1 : check_read(a_decimal, EXESS_NON_NEGATIVE_INTEGER, "+0", EXESS_SUCCESS, 2);
131 : 1 : check_read(a_decimal, EXESS_NON_NEGATIVE_INTEGER, "43", EXESS_SUCCESS, 2);
132 : 1 : check_decimal_value(a_decimal, 43.0);
133 : : }
134 : : {
135 : 1 : int64_t a_long = 0;
136 : 1 : check_read(&a_long, EXESS_LONG, "10", EXESS_SUCCESS, 2);
137 [ - + ]: 1 : assert(a_long == 10);
138 : : }
139 : : {
140 : 1 : int32_t a_int = 0;
141 : 1 : check_read(&a_int, EXESS_INT, "x", EXESS_EXPECTED_DIGIT, 0);
142 : 1 : check_read(&a_int, EXESS_INT, "11", EXESS_SUCCESS, 2);
143 [ - + ]: 1 : assert(a_int == 11);
144 : : }
145 : : {
146 : 1 : int16_t a_short = 0;
147 : 1 : check_read(&a_short, EXESS_SHORT, "x", EXESS_EXPECTED_DIGIT, 0);
148 : 1 : check_read(&a_short, EXESS_SHORT, "12", EXESS_SUCCESS, 2);
149 [ - + ]: 1 : assert(a_short == 12);
150 : : }
151 : : {
152 : 1 : int8_t a_byte = 0;
153 : 1 : check_read(&a_byte, EXESS_BYTE, "x", EXESS_EXPECTED_DIGIT, 0);
154 : 1 : check_read(&a_byte, EXESS_BYTE, "13", EXESS_SUCCESS, 2);
155 [ - + ]: 1 : assert(a_byte == 13);
156 : : }
157 : : {
158 : 1 : uint64_t a_ulong = 0U;
159 : 1 : check_read(&a_ulong, EXESS_ULONG, "x", EXESS_EXPECTED_DIGIT, 0);
160 : 1 : check_read(&a_ulong, EXESS_ULONG, "14", EXESS_SUCCESS, 2);
161 [ - + ]: 1 : assert(a_ulong == 14U);
162 : : }
163 : : {
164 : 1 : uint32_t a_uint = 0U;
165 : 1 : check_read(&a_uint, EXESS_UINT, "x", EXESS_EXPECTED_DIGIT, 0);
166 : 1 : check_read(&a_uint, EXESS_UINT, "15", EXESS_SUCCESS, 2);
167 [ - + ]: 1 : assert(a_uint == 15U);
168 : : }
169 : : {
170 : 1 : uint16_t a_ushort = 0U;
171 : 1 : check_read(&a_ushort, EXESS_USHORT, "x", EXESS_EXPECTED_DIGIT, 0);
172 : 1 : check_read(&a_ushort, EXESS_USHORT, "16", EXESS_SUCCESS, 2);
173 [ - + ]: 1 : assert(a_ushort == 16U);
174 : : }
175 : : {
176 : 1 : uint8_t a_ubyte = 0U;
177 : 1 : check_read(&a_ubyte, EXESS_UBYTE, "x", EXESS_EXPECTED_DIGIT, 0);
178 : 1 : check_read(&a_ubyte, EXESS_UBYTE, "17", EXESS_SUCCESS, 2);
179 [ - + ]: 1 : assert(a_ubyte == 17U);
180 : : }
181 : : {
182 : 1 : EXESS_ALIGN uint8_t a_integer[VALUE_SIZE] = {0};
183 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "E", EXESS_EXPECTED_DIGIT, 0);
184 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "-1", EXESS_OUT_OF_RANGE, 2);
185 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "-0", EXESS_OUT_OF_RANGE, 2);
186 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "0", EXESS_OUT_OF_RANGE, 1);
187 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "+0", EXESS_OUT_OF_RANGE, 2);
188 : 1 : check_read(a_integer, EXESS_POSITIVE_INTEGER, "18", EXESS_SUCCESS, 2);
189 : 1 : check_integer_value(a_integer, 18);
190 : : }
191 : : {
192 : 1 : ExessDuration a_duration = {1, 2, 3};
193 : 1 : check_read(&a_duration, EXESS_DURATION, "x", EXESS_EXPECTED_DURATION, 0);
194 : :
195 : 1 : check_read(
196 : : &a_duration, EXESS_DURATION, "P1MT2.000000003S", EXESS_SUCCESS, 16);
197 : :
198 [ - + ]: 1 : assert(a_duration.months == 1);
199 [ - + ]: 1 : assert(a_duration.seconds == 2);
200 [ - + ]: 1 : assert(a_duration.nanoseconds == 3);
201 : :
202 : 1 : check_read(
203 : : &a_duration, EXESS_YEAR_MONTH_DURATION, "x", EXESS_EXPECTED_DURATION, 0);
204 : 1 : check_read(
205 : : &a_duration, EXESS_DAY_TIME_DURATION, "x", EXESS_EXPECTED_DURATION, 0);
206 : :
207 : 1 : check_read(&a_duration, EXESS_YEAR_MONTH_DURATION, "P1M", EXESS_SUCCESS, 3);
208 : 1 : check_read(
209 : : &a_duration, EXESS_DAY_TIME_DURATION, "PT2.3S", EXESS_SUCCESS, 6);
210 : :
211 : 1 : check_read(
212 : : &a_duration, EXESS_YEAR_MONTH_DURATION, "PT0.1S", EXESS_BAD_VALUE, 6);
213 : 1 : check_read(
214 : : &a_duration, EXESS_YEAR_MONTH_DURATION, "PT1.0S", EXESS_BAD_VALUE, 6);
215 : 1 : check_read(
216 : : &a_duration, EXESS_YEAR_MONTH_DURATION, "PT1.2S", EXESS_BAD_VALUE, 6);
217 : 1 : check_read(&a_duration, EXESS_DAY_TIME_DURATION, "P1M", EXESS_BAD_VALUE, 3);
218 : : }
219 : : {
220 : 1 : ExessDateTime a_datetime = datetime;
221 : 1 : check_read(&a_datetime, EXESS_DATE_TIME, "x", EXESS_EXPECTED_DIGIT, 0);
222 : :
223 : 1 : check_read(&a_datetime,
224 : : EXESS_DATE_TIME,
225 : : "2001-01-02T12:15:01.25",
226 : : EXESS_SUCCESS,
227 : : 22);
228 : :
229 [ - + ]: 1 : assert(a_datetime.year == 2001);
230 [ - + ]: 1 : assert(a_datetime.month == 1);
231 [ - + ]: 1 : assert(a_datetime.day == 2);
232 [ - + ]: 1 : assert(a_datetime.hour == 12);
233 [ - + ]: 1 : assert(a_datetime.minute == 15);
234 [ - + ]: 1 : assert(a_datetime.second == 1);
235 [ - + ]: 1 : assert(a_datetime.nanosecond == 250000000);
236 : :
237 : 1 : check_read(
238 : : &a_datetime, EXESS_DATE_TIME_STAMP, "x", EXESS_EXPECTED_DIGIT, 0);
239 : :
240 : 1 : check_read(&a_datetime,
241 : : EXESS_DATE_TIME_STAMP,
242 : : "2001-01-02T12:15:16Z",
243 : : EXESS_SUCCESS,
244 : : 20);
245 : :
246 : 1 : check_read(&a_datetime,
247 : : EXESS_DATE_TIME_STAMP,
248 : : "2001-01-02T12:15:16",
249 : : EXESS_BAD_VALUE,
250 : : 19);
251 : : }
252 : : {
253 : 1 : ExessDate a_date = date;
254 : 1 : check_read(&a_date, EXESS_DATE, "x", EXESS_EXPECTED_DIGIT, 0);
255 : 1 : check_read(&a_date, EXESS_DATE, "2001-01-02", EXESS_SUCCESS, 10);
256 [ - + ]: 1 : assert(a_date.year == 2001);
257 [ - + ]: 1 : assert(a_date.month == 1);
258 [ - + ]: 1 : assert(a_date.day == 2);
259 : : }
260 : : {
261 : 1 : ExessTime a_time = time;
262 : 1 : check_read(&a_time, EXESS_TIME, "x", EXESS_EXPECTED_DIGIT, 0);
263 : 1 : check_read(&a_time, EXESS_TIME, "12:15:01.25", EXESS_SUCCESS, 11);
264 [ - + ]: 1 : assert(a_time.hour == 12);
265 [ - + ]: 1 : assert(a_time.minute == 15);
266 [ - + ]: 1 : assert(a_time.second == 1);
267 [ - + ]: 1 : assert(a_time.nanosecond == 250000000);
268 : : }
269 : : {
270 : 1 : char a_blob[] = {1, 2, 3};
271 : 1 : check_read(a_blob, EXESS_HEX, "!", EXESS_EXPECTED_HEX, 0);
272 : 1 : check_read(a_blob, EXESS_HEX, "666F6F", EXESS_SUCCESS, 6);
273 [ - + ]: 1 : assert(!strncmp(a_blob, "foo", sizeof(a_blob)));
274 : : }
275 : : {
276 : 1 : char a_blob[] = {1, 2, 3};
277 : 1 : check_read(a_blob, EXESS_BASE64, "!", EXESS_EXPECTED_BASE64, 0);
278 : 1 : check_read(a_blob, EXESS_BASE64, "Zm9v", EXESS_SUCCESS, 4);
279 [ - + ]: 1 : assert(!strncmp(a_blob, "foo", sizeof(a_blob)));
280 : : }
281 : 1 : }
282 : :
283 : : static void
284 : 23 : check_write(const ExessDatatype datatype,
285 : : const size_t value_size,
286 : : const void* value,
287 : : const size_t buf_size,
288 : : const char* const expected_string)
289 : : {
290 : 23 : char buf[STRING_SIZE] = {42};
291 : :
292 [ - + ]: 23 : assert(buf_size <= sizeof(buf));
293 : 23 : init_out_buf(sizeof(buf), buf);
294 : :
295 : : const ExessResult r =
296 : 23 : exess_write_value(datatype, value_size, value, buf_size, buf);
297 : :
298 [ - + ]: 23 : assert(!r.status);
299 [ - + ]: 23 : assert(r.count + 1U == buf_size);
300 [ - + ]: 23 : assert(r.count == strlen(buf));
301 [ - + ]: 23 : assert(!strcmp(buf, expected_string));
302 : :
303 [ + + ]: 137 : for (size_t space = 0U; space < r.count; ++space) {
304 : 114 : buf[0] = 1;
305 : :
306 : : const ExessResult s =
307 : 114 : exess_write_value(datatype, value_size, value, space, buf);
308 : :
309 [ - + ]: 114 : assert(s.status == EXESS_NO_SPACE);
310 [ - + ]: 114 : assert(s.count == r.count);
311 [ - + ]: 114 : assert(buf[0] == (space ? 0 : 1));
312 : : }
313 : 23 : }
314 : :
315 : : static void
316 : 1 : test_write_value(void)
317 : : {
318 : 1 : uint8_t a_blob[] = {'f', 'o', 'o'};
319 : :
320 : 1 : EXESS_ALIGN uint8_t a_decimal[VALUE_SIZE] = {0};
321 : 1 : set_decimal_value(sizeof(a_decimal), a_decimal, 1.2);
322 : :
323 : 1 : const bool a_bool = true;
324 : 1 : const double a_double = 3.4;
325 : 1 : const float a_float = 5.6f;
326 : 1 : const int64_t a_long = 7;
327 : 1 : const int32_t a_int = 8;
328 : 1 : const int16_t a_short = 9;
329 : 1 : const int8_t a_byte = 10;
330 : 1 : const uint64_t a_ulong = 11U;
331 : 1 : const uint32_t a_uint = 12U;
332 : 1 : const uint16_t a_ushort = 13U;
333 : 1 : const uint8_t a_ubyte = 14U;
334 : 1 : const ExessDuration a_duration = duration;
335 : 1 : const ExessDateTime a_datetime = datetime;
336 : 1 : const ExessTime a_time = time;
337 : 1 : const ExessDate a_date = date;
338 : :
339 : : {
340 : 1 : char buf = '\0';
341 [ - + ]: 1 : assert(exess_write_value(EXESS_NOTHING, 1, &buf, 1, &buf).status ==
342 : : EXESS_BAD_VALUE);
343 : : }
344 : :
345 : 1 : check_write(EXESS_BOOLEAN, sizeof(a_bool), &a_bool, 5, "true");
346 : 1 : check_write(EXESS_DECIMAL, sizeof(a_decimal), &a_decimal, 4, "1.2");
347 : 1 : check_write(EXESS_DOUBLE, sizeof(a_double), &a_double, 6, "3.4E0");
348 : 1 : check_write(EXESS_FLOAT, sizeof(a_float), &a_float, 12, "5.5999999E0");
349 : 1 : check_write(EXESS_LONG, sizeof(a_long), &a_long, 2, "7");
350 : 1 : check_write(EXESS_INT, sizeof(a_int), &a_int, 2, "8");
351 : 1 : check_write(EXESS_SHORT, sizeof(a_short), &a_short, 2, "9");
352 : 1 : check_write(EXESS_BYTE, sizeof(a_byte), &a_byte, 3, "10");
353 : 1 : check_write(EXESS_ULONG, sizeof(a_ulong), &a_ulong, 3, "11");
354 : 1 : check_write(EXESS_UINT, sizeof(a_uint), &a_uint, 3, "12");
355 : 1 : check_write(EXESS_USHORT, sizeof(a_ushort), &a_ushort, 3, "13");
356 : 1 : check_write(EXESS_UBYTE, sizeof(a_ubyte), &a_ubyte, 3, "14");
357 : :
358 : : {
359 : 1 : EXESS_ALIGN uint8_t a_integer[VALUE_SIZE] = {0};
360 : :
361 : 1 : set_integer_value(sizeof(a_integer), a_integer, -15);
362 : 1 : check_write(EXESS_INTEGER, sizeof(a_integer), &a_integer, 4, "-15");
363 : 1 : check_write(
364 : : EXESS_NON_POSITIVE_INTEGER, sizeof(a_integer), &a_integer, 4, "-15");
365 : 1 : check_write(
366 : : EXESS_NEGATIVE_INTEGER, sizeof(a_integer), &a_integer, 4, "-15");
367 : :
368 : 1 : set_integer_value(sizeof(a_integer), a_integer, -16);
369 : 1 : check_write(
370 : : EXESS_NON_NEGATIVE_INTEGER, sizeof(a_integer), &a_integer, 4, "-16");
371 : 1 : check_write(
372 : : EXESS_POSITIVE_INTEGER, sizeof(a_integer), &a_integer, 4, "-16");
373 : : }
374 : :
375 : 1 : check_write(
376 : : EXESS_DURATION, sizeof(a_duration), &a_duration, 15, "P1Y2M3DT4H5M6S");
377 : :
378 : 1 : check_write(EXESS_DATE_TIME,
379 : : sizeof(a_datetime),
380 : : &a_datetime,
381 : : 20,
382 : : "2001-02-03T04:05:06");
383 : :
384 : 1 : check_write(EXESS_TIME, sizeof(a_time), &a_time, 10, "01:02:03Z");
385 : 1 : check_write(EXESS_DATE, sizeof(a_date), &a_date, 12, "2001-02-03Z");
386 : :
387 : 1 : check_write(EXESS_HEX, sizeof(a_blob), a_blob, 7, "666F6F");
388 : 1 : check_write(EXESS_BASE64, sizeof(a_blob), a_blob, 5, "Zm9v");
389 : 1 : }
390 : :
391 : : int
392 : 1 : main(void)
393 : : {
394 : 1 : test_read_value();
395 : 1 : test_write_value();
396 : :
397 : 1 : return 0;
398 : : }
|