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 "write_test_utils.h"
7 : :
8 : : #include <exess/exess.h>
9 : :
10 : : #include <assert.h>
11 : : #include <stdint.h>
12 : : #include <string.h>
13 : :
14 : : #define VALUE_SIZE 27U
15 : : #define STRING_SIZE 23U
16 : :
17 : : static const char* const min_long_str = "-9223372036854775808";
18 : : static const char* const max_long_str = "9223372036854775807";
19 : : static const char* const max_ulong_str = "18446744073709551615";
20 : :
21 : : typedef struct {
22 : : EXESS_ALIGN uint8_t value[VALUE_SIZE];
23 : : EXESS_ALIGN uint8_t coerced[VALUE_SIZE];
24 : : ExessVariableResult r_value;
25 : : ExessResult r_coerced;
26 : : } CheckState;
27 : :
28 : : static void
29 : 465 : check_conversions(CheckState* const state,
30 : : const ExessDatatype from_datatype,
31 : : const char* const from_string,
32 : : const ExessCoercions coercions,
33 : : const ExessDatatype to_datatype,
34 : : const char* const to_string)
35 : : {
36 : 465 : char coerced_str[STRING_SIZE] = {42};
37 : 465 : init_out_buf(sizeof(coerced_str), coerced_str);
38 : :
39 : : // Read original value
40 : 465 : state->r_value = exess_read_value(
41 : 465 : from_datatype, from_string, sizeof(state->value), state->value);
42 : :
43 [ - + ]: 465 : assert(!state->r_value.status);
44 : :
45 : : // Coerce to target datatype
46 : 465 : state->r_coerced = exess_coerce_value(coercions,
47 : : from_datatype,
48 : : state->r_value.write_count,
49 : 465 : state->value,
50 : : to_datatype,
51 : : sizeof(state->coerced),
52 : 465 : state->coerced);
53 : :
54 [ - + ]: 465 : assert(!state->r_coerced.status);
55 [ - + ]: 465 : assert(state->r_coerced.count >= exess_value_sizes[to_datatype]);
56 : :
57 : : // Write coerced value and check string against expectation
58 : 465 : const ExessResult coerced_str_r = exess_write_value(to_datatype,
59 : : state->r_coerced.count,
60 : 465 : state->coerced,
61 : : sizeof(coerced_str),
62 : : coerced_str);
63 : :
64 [ - + ]: 465 : assert(!coerced_str_r.status);
65 [ - + ]: 465 : assert(!strcmp(coerced_str, to_string));
66 : :
67 : : // Check that coercion fails with inadequate space
68 [ - + ]: 465 : assert(exess_coerce_value(coercions,
69 : : from_datatype,
70 : : state->r_value.write_count,
71 : : state->value,
72 : : to_datatype,
73 : : state->r_coerced.count - 1U,
74 : : state->coerced)
75 : : .status == EXESS_NO_SPACE);
76 : 465 : }
77 : :
78 : : // Check a perfect (lossless/bidirectional) coercion
79 : : static void
80 : 59 : check_perf(const ExessDatatype from_datatype,
81 : : const char* const from_string,
82 : : const ExessDatatype to_datatype,
83 : : const char* const to_string)
84 : : {
85 : 59 : CheckState state = {{0}, {0}, {EXESS_SUCCESS, 0, 0}, {EXESS_SUCCESS, 0}};
86 : :
87 : 59 : check_conversions(
88 : : &state, from_datatype, from_string, 0U, to_datatype, to_string);
89 : :
90 : 59 : EXESS_ALIGN uint8_t tripped[VALUE_SIZE] = {0};
91 : 59 : char tripped_str[STRING_SIZE] = {42};
92 : 59 : init_out_buf(sizeof(tripped_str), tripped_str);
93 : :
94 : : // Coerce the value back to the original type
95 : 59 : const ExessResult tripped_r = exess_coerce_value(0U,
96 : : to_datatype,
97 : : state.r_coerced.count,
98 : : state.coerced,
99 : : from_datatype,
100 : : sizeof(tripped),
101 : : tripped);
102 : :
103 [ - + ]: 59 : assert(!tripped_r.status);
104 [ - + ]: 59 : assert(tripped_r.count >= exess_value_sizes[from_datatype]);
105 : :
106 : : // Write round-tripped value and check string against the original
107 : 59 : const ExessResult tr = exess_write_value(
108 : 59 : from_datatype, tripped_r.count, tripped, sizeof(tripped_str), tripped_str);
109 : :
110 [ - + ]: 59 : assert(!tr.status);
111 [ - + ]: 59 : assert(!strcmp(tripped_str, from_string));
112 : 59 : }
113 : :
114 : : // Check that a failed lossless coercion returns the expected error
115 : : static void
116 : 136 : check_fail(const ExessDatatype from_datatype,
117 : : const char* const from_string,
118 : : const ExessDatatype to_datatype,
119 : : const ExessStatus expected_status)
120 : : {
121 : 136 : EXESS_ALIGN uint8_t value[VALUE_SIZE] = {0};
122 : 136 : EXESS_ALIGN uint8_t coerced[VALUE_SIZE] = {0};
123 : :
124 : : // Read original value
125 : : const ExessVariableResult vr =
126 : 136 : exess_read_value(from_datatype, from_string, sizeof(value), value);
127 : :
128 [ - + ]: 136 : assert(!vr.status);
129 : :
130 : : // Try to coerce to target datatype
131 : 136 : const ExessResult coerced_r = exess_coerce_value(0U,
132 : : from_datatype,
133 : 136 : vr.write_count,
134 : : value,
135 : : to_datatype,
136 : : sizeof(coerced),
137 : : coerced);
138 : :
139 [ - + ]: 136 : assert(coerced_r.status == expected_status);
140 : 136 : }
141 : :
142 : : // Check a lossy coercion in one direction only
143 : : static void
144 : 405 : check_loss(const ExessDatatype from_datatype,
145 : : const char* const from_string,
146 : : const ExessDatatype to_datatype,
147 : : const char* const to_string,
148 : : const ExessCoercions coercions)
149 : : {
150 : 405 : CheckState state = {{0}, {0}, {EXESS_SUCCESS, 0, 0}, {EXESS_SUCCESS, 0}};
151 : :
152 : 405 : check_conversions(
153 : : &state, from_datatype, from_string, coercions, to_datatype, to_string);
154 : :
155 [ - + ]: 405 : assert(exess_coerce_value(0U,
156 : : from_datatype,
157 : : state.r_value.write_count,
158 : : state.value,
159 : : to_datatype,
160 : : state.r_coerced.count,
161 : : state.coerced)
162 : : .status == EXESS_LOSS);
163 : 405 : }
164 : :
165 : : // Check a widening coercions that's only lossless in one direction
166 : : static void
167 : 1 : check_wide(const ExessDatatype from_datatype,
168 : : const char* const from_string,
169 : : const ExessDatatype to_datatype,
170 : : const char* const to_string)
171 : : {
172 : 1 : CheckState state = {{0}, {0}, {EXESS_SUCCESS, 0, 0}, {EXESS_SUCCESS, 0}};
173 : :
174 : 1 : check_conversions(
175 : : &state, from_datatype, from_string, 0U, to_datatype, to_string);
176 : :
177 : : // Ensure that converting coerced value back isn't lossless
178 [ - + ]: 1 : assert(exess_coerce_value(0U,
179 : : to_datatype,
180 : : state.r_coerced.count,
181 : : state.coerced,
182 : : from_datatype,
183 : : state.r_value.write_count,
184 : : state.value)
185 : : .status == EXESS_LOSS);
186 : 1 : }
187 : :
188 : : // Check a truncating coercion
189 : : static void
190 : 186 : check_trunc(const ExessDatatype from_datatype,
191 : : const char* const from_string,
192 : : const ExessDatatype to_datatype,
193 : : const char* const to_string)
194 : : {
195 : 186 : check_loss(
196 : : from_datatype, from_string, to_datatype, to_string, EXESS_TRUNCATE);
197 : 186 : }
198 : :
199 : : // Check a rounding coercion
200 : : static void
201 : 213 : check_round(const ExessDatatype from_datatype,
202 : : const char* const from_string,
203 : : const ExessDatatype to_datatype,
204 : : const char* const to_string)
205 : : {
206 : 213 : check_loss(from_datatype, from_string, to_datatype, to_string, EXESS_ROUND);
207 : 213 : }
208 : :
209 : : static void
210 : 1 : test_overflow(void)
211 : : {
212 : 1 : const uint32_t v = 4294967295U;
213 : 1 : uint16_t o = 42U;
214 : :
215 : : ExessResult r =
216 : 1 : exess_coerce_value(0U, EXESS_SHORT, 1U, &v, EXESS_LONG, sizeof(o), &o);
217 : :
218 [ - + ]: 1 : assert(r.status == EXESS_BAD_VALUE);
219 [ - + ]: 1 : assert(o == 42U);
220 : :
221 : 1 : r = exess_coerce_value(
222 : : 0U, EXESS_SHORT, sizeof(v), &v, EXESS_LONG, sizeof(o), &o);
223 : :
224 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
225 [ - + ]: 1 : assert(o == 42U);
226 : :
227 : 1 : r = exess_coerce_value(
228 : : 0U, EXESS_HEX, sizeof(v), &v, EXESS_BASE64, sizeof(o), &o);
229 : :
230 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
231 [ - + ]: 1 : assert(o == 42U);
232 : 1 : }
233 : :
234 : : static void
235 : 1 : test_unknown(void)
236 : : {
237 : 1 : const int64_t long_value = 1;
238 : 1 : const uint64_t ulong_value = 1U;
239 : :
240 : 1 : uint8_t in[32] = {0U};
241 : 1 : uint8_t out[32] = {0U};
242 : :
243 [ - + ]: 1 : assert(exess_coerce_value(
244 : : 0U, EXESS_NOTHING, sizeof(in), in, EXESS_LONG, sizeof(out), out)
245 : : .status);
246 : :
247 [ - + ]: 1 : assert(exess_coerce_value(
248 : : 0U, EXESS_NOTHING, sizeof(in), in, EXESS_ULONG, sizeof(out), out)
249 : : .status);
250 : :
251 [ - + ]: 1 : assert(exess_coerce_value(0U,
252 : : EXESS_LONG,
253 : : sizeof(long_value),
254 : : &long_value,
255 : : EXESS_NOTHING,
256 : : sizeof(out),
257 : : out)
258 : : .status);
259 : :
260 [ - + ]: 1 : assert(exess_coerce_value(0U,
261 : : EXESS_ULONG,
262 : : sizeof(ulong_value),
263 : : &ulong_value,
264 : : EXESS_NOTHING,
265 : : sizeof(out),
266 : : out)
267 : : .status);
268 : 1 : }
269 : :
270 : : static void
271 : 1 : test_floating(void)
272 : : {
273 : 1 : check_wide(EXESS_FLOAT, "1.2E3", EXESS_DOUBLE, "1.2E3");
274 : :
275 : 1 : check_loss(
276 : : EXESS_DOUBLE, "1.0000000000001E0", EXESS_FLOAT, "1.0E0", EXESS_APPROXIMATE);
277 : :
278 : 1 : check_loss(EXESS_DOUBLE, "1.5E0", EXESS_FLOAT, "1.5E0", EXESS_APPROXIMATE);
279 : 1 : }
280 : :
281 : : static void
282 : 1 : test_decimal(void)
283 : : {
284 : 1 : check_perf(EXESS_DECIMAL, "1.0", EXESS_INTEGER, "1");
285 : 1 : check_perf(EXESS_DECIMAL, "1.2", EXESS_DECIMAL, "1.2");
286 : 1 : check_perf(EXESS_FLOAT, "1.2E3", EXESS_DECIMAL, "1200.0");
287 : 1 : check_perf(EXESS_DOUBLE, "1.2E4", EXESS_DECIMAL, "12000.0");
288 : :
289 : : // Approximation to fixed-size binary floating point
290 : 1 : check_loss(
291 : : EXESS_DECIMAL, "1.000000001", EXESS_FLOAT, "1.0E0", EXESS_APPROXIMATE);
292 : 1 : check_loss(EXESS_DECIMAL,
293 : : "1.00000000000000001",
294 : : EXESS_DOUBLE,
295 : : "1.0E0",
296 : : EXESS_APPROXIMATE);
297 : :
298 : : // Truncation to fixed-size integer
299 : 1 : check_loss(EXESS_DECIMAL, "0.00000001", EXESS_LONG, "0", EXESS_TRUNCATE);
300 : 1 : check_loss(EXESS_DECIMAL, "0.00000001", EXESS_ULONG, "0", EXESS_TRUNCATE);
301 : :
302 : : // Truncation to big integer
303 : 1 : check_trunc(EXESS_DECIMAL, "-4.8", EXESS_INTEGER, "-4");
304 : 1 : check_trunc(EXESS_DECIMAL, "4.8", EXESS_INTEGER, "4");
305 : 1 : check_trunc(EXESS_DECIMAL, "0.01", EXESS_INTEGER, "0");
306 : 1 : check_fail(EXESS_DECIMAL, "1.2", EXESS_INTEGER, EXESS_LOSS);
307 : :
308 : : // Rounding to big integer
309 : 1 : check_round(EXESS_DECIMAL, "-4.8", EXESS_INTEGER, "-5");
310 : 1 : check_round(EXESS_DECIMAL, "4.8", EXESS_INTEGER, "5");
311 : 1 : check_round(EXESS_DECIMAL, "0.01", EXESS_INTEGER, "0");
312 : :
313 : : // One away from signed long limits
314 : 1 : check_perf(EXESS_DECIMAL,
315 : : "-9223372036854775807.0",
316 : : EXESS_LONG,
317 : : "-9223372036854775807");
318 : 1 : check_perf(EXESS_DECIMAL,
319 : : "9223372036854775806.0", //
320 : : EXESS_LONG,
321 : : "9223372036854775806");
322 : :
323 : : // Signed long limits
324 : 1 : check_perf(EXESS_DECIMAL,
325 : : "-9223372036854775808.0", //
326 : : EXESS_LONG,
327 : : "-9223372036854775808");
328 : 1 : check_perf(EXESS_DECIMAL,
329 : : "9223372036854775807.0", //
330 : : EXESS_LONG,
331 : : "9223372036854775807");
332 : :
333 : : // Beyond signed long limits
334 : 1 : check_fail(EXESS_DECIMAL,
335 : : "-9223372036854775809.0", //
336 : : EXESS_LONG,
337 : : EXESS_OUT_OF_RANGE);
338 : 1 : check_trunc(EXESS_DECIMAL,
339 : : "-9223372036854775808.01", //
340 : : EXESS_LONG,
341 : : "-9223372036854775808");
342 : 1 : check_trunc(
343 : : EXESS_DECIMAL, "9223372036854775807.01", EXESS_LONG, "9223372036854775807");
344 : 1 : check_fail(
345 : : EXESS_DECIMAL, "9223372036854775808.0", EXESS_LONG, EXESS_OUT_OF_RANGE);
346 : 1 : check_fail(
347 : : EXESS_DECIMAL, "100000000000000000000.0", EXESS_LONG, EXESS_OUT_OF_RANGE);
348 : :
349 : : // Unsigned long limit
350 : 1 : check_perf(EXESS_DECIMAL,
351 : : "18446744073709551615.0",
352 : : EXESS_ULONG,
353 : : "18446744073709551615");
354 : :
355 : : // Beyond unsigned long limit
356 : 1 : check_trunc(EXESS_DECIMAL,
357 : : "18446744073709551615.09",
358 : : EXESS_ULONG,
359 : : "18446744073709551615");
360 : 1 : check_fail(
361 : : EXESS_DECIMAL, "18446744073709551616.0", EXESS_ULONG, EXESS_OUT_OF_RANGE);
362 : 1 : check_fail(
363 : : EXESS_DECIMAL, "100000000000000000000.0", EXESS_ULONG, EXESS_OUT_OF_RANGE);
364 : 1 : }
365 : :
366 : : static void
367 : 1 : test_boolean(void)
368 : : {
369 : : // Exactly from 0 or 1, lossy from 0 or non-zero
370 : 1 : check_perf(EXESS_BOOLEAN, "false", EXESS_FLOAT, "0.0E0");
371 : 1 : check_perf(EXESS_BOOLEAN, "true", EXESS_FLOAT, "1.0E0");
372 : 1 : check_perf(EXESS_BOOLEAN, "false", EXESS_DOUBLE, "0.0E0");
373 : 1 : check_perf(EXESS_BOOLEAN, "true", EXESS_DOUBLE, "1.0E0");
374 : 1 : check_perf(EXESS_BOOLEAN, "false", EXESS_LONG, "0");
375 : 1 : check_perf(EXESS_BOOLEAN, "true", EXESS_LONG, "1");
376 : 1 : check_fail(EXESS_LONG, "-1", EXESS_BOOLEAN, EXESS_LOSS);
377 : 1 : check_fail(EXESS_LONG, "2", EXESS_BOOLEAN, EXESS_LOSS);
378 : 1 : check_trunc(EXESS_LONG, "42", EXESS_BOOLEAN, "true");
379 : 1 : check_trunc(EXESS_LONG, "-1", EXESS_BOOLEAN, "true");
380 : 1 : check_perf(EXESS_BOOLEAN, "false", EXESS_ULONG, "0");
381 : 1 : check_perf(EXESS_BOOLEAN, "true", EXESS_ULONG, "1");
382 : 1 : check_fail(EXESS_LONG, "2", EXESS_BOOLEAN, EXESS_LOSS);
383 : 1 : check_trunc(EXESS_ULONG, "42", EXESS_BOOLEAN, "true");
384 : :
385 : : // Not convertible to any time types
386 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DURATION, EXESS_UNSUPPORTED);
387 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
388 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_TIME, EXESS_UNSUPPORTED);
389 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DATE, EXESS_UNSUPPORTED);
390 : 1 : }
391 : :
392 : : static void
393 : 1 : test_round_trunc(void)
394 : : {
395 : : static const ExessDatatype float_types[] = {
396 : : EXESS_DOUBLE, EXESS_FLOAT, EXESS_DECIMAL, EXESS_NOTHING};
397 : : static const ExessDatatype unsigned_types[] = {
398 : : EXESS_ULONG, EXESS_UINT, EXESS_USHORT, EXESS_UBYTE, EXESS_NOTHING};
399 : : static const ExessDatatype signed_types[] = {EXESS_LONG,
400 : : EXESS_INT,
401 : : EXESS_SHORT,
402 : : EXESS_BYTE,
403 : : EXESS_INTEGER,
404 : : EXESS_NOTHING};
405 : :
406 [ + + ]: 4 : for (const ExessDatatype* f = float_types; *f; ++f) {
407 [ + + ]: 18 : for (const ExessDatatype* t = signed_types; *t; ++t) {
408 : 15 : check_round(*f, "-3.5E0", *t, "-4");
409 : 15 : check_round(*f, "-2.5E0", *t, "-2");
410 : 15 : check_round(*f, "-1.5E0", *t, "-2");
411 : 15 : check_round(*f, "-1.4E0", *t, "-1");
412 : 15 : check_round(*f, "-0.5E0", *t, "0");
413 : 15 : check_round(*f, "0.5E0", *t, "0");
414 : 15 : check_round(*f, "1.4E0", *t, "1");
415 : 15 : check_round(*f, "1.5E0", *t, "2");
416 : 15 : check_round(*f, "2.5E0", *t, "2");
417 : 15 : check_round(*f, "3.5E0", *t, "4");
418 : : }
419 : :
420 [ + + ]: 15 : for (const ExessDatatype* t = unsigned_types; *t; ++t) {
421 : 12 : check_round(*f, "0.5E0", *t, "0");
422 : 12 : check_round(*f, "1.5E0", *t, "2");
423 : 12 : check_round(*f, "2.5E0", *t, "2");
424 : 12 : check_round(*f, "3.5E0", *t, "4");
425 : : }
426 : :
427 [ + + ]: 18 : for (const ExessDatatype* t = signed_types; *t; ++t) {
428 : 15 : check_trunc(*f, "-3.5E0", *t, "-3");
429 : 15 : check_trunc(*f, "-2.5E0", *t, "-2");
430 : 15 : check_trunc(*f, "-1.5E0", *t, "-1");
431 : 15 : check_trunc(*f, "-0.5E0", *t, "0");
432 : 15 : check_trunc(*f, "0.5E0", *t, "0");
433 : 15 : check_trunc(*f, "1.5E0", *t, "1");
434 : 15 : check_trunc(*f, "2.5E0", *t, "2");
435 : 15 : check_trunc(*f, "3.5E0", *t, "3");
436 : : }
437 : :
438 [ + + ]: 15 : for (const ExessDatatype* t = unsigned_types; *t; ++t) {
439 : 12 : check_trunc(*f, "0.5E0", *t, "0");
440 : 12 : check_trunc(*f, "1.5E0", *t, "1");
441 : 12 : check_trunc(*f, "2.5E0", *t, "2");
442 : 12 : check_trunc(*f, "3.5E0", *t, "3");
443 : : }
444 : : }
445 : 1 : }
446 : :
447 : : static void
448 : 1 : test_long(void)
449 : : {
450 : : // Truncating boolean conversion
451 : 1 : check_trunc(EXESS_LONG, "42", EXESS_BOOLEAN, "true");
452 : 1 : check_trunc(EXESS_LONG, "-1", EXESS_BOOLEAN, "true");
453 : :
454 : : // All smaller integer types
455 : 1 : check_perf(EXESS_LONG, "-2147483648", EXESS_INT, "-2147483648");
456 : 1 : check_fail(EXESS_LONG, "-2147483649", EXESS_INT, EXESS_OUT_OF_RANGE);
457 : 1 : check_perf(EXESS_LONG, "-32768", EXESS_SHORT, "-32768");
458 : 1 : check_fail(EXESS_LONG, "-32769", EXESS_SHORT, EXESS_OUT_OF_RANGE);
459 : 1 : check_perf(EXESS_LONG, "-128", EXESS_BYTE, "-128");
460 : 1 : check_fail(EXESS_LONG, "-129", EXESS_BYTE, EXESS_OUT_OF_RANGE);
461 : :
462 : : // Positive values to/from all unsigned types
463 : 1 : check_perf(EXESS_LONG, max_long_str, EXESS_ULONG, max_long_str);
464 : 1 : check_fail(EXESS_LONG, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
465 : 1 : check_perf(EXESS_LONG, "4294967295", EXESS_UINT, "4294967295");
466 : 1 : check_fail(EXESS_LONG, "-1", EXESS_UINT, EXESS_OUT_OF_RANGE);
467 : 1 : check_perf(EXESS_LONG, "65535", EXESS_USHORT, "65535");
468 : 1 : check_fail(EXESS_LONG, "-1", EXESS_USHORT, EXESS_OUT_OF_RANGE);
469 : 1 : check_perf(EXESS_LONG, "255", EXESS_UBYTE, "255");
470 : 1 : check_fail(EXESS_LONG, "-1", EXESS_UBYTE, EXESS_OUT_OF_RANGE);
471 : :
472 : : // Any value to/from integer
473 : 1 : check_perf(EXESS_LONG, min_long_str, EXESS_INTEGER, min_long_str);
474 : 1 : check_perf(EXESS_LONG, max_long_str, EXESS_INTEGER, max_long_str);
475 : :
476 : : // Non-positive values to/from nonPositiveInteger
477 : 1 : check_perf(
478 : : EXESS_LONG, min_long_str, EXESS_NON_POSITIVE_INTEGER, min_long_str);
479 : 1 : check_perf(EXESS_LONG, "0", EXESS_NON_POSITIVE_INTEGER, "0");
480 : 1 : check_fail(EXESS_LONG, "1", EXESS_NON_POSITIVE_INTEGER, EXESS_OUT_OF_RANGE);
481 : :
482 : : // Negative values to/from negativeInteger
483 : 1 : check_perf(EXESS_LONG, min_long_str, EXESS_NEGATIVE_INTEGER, min_long_str);
484 : 1 : check_perf(EXESS_LONG, "-1", EXESS_NEGATIVE_INTEGER, "-1");
485 : 1 : check_fail(EXESS_LONG, "0", EXESS_NEGATIVE_INTEGER, EXESS_OUT_OF_RANGE);
486 : :
487 : : // Non-negative values to/from nonNegativeInteger
488 : 1 : check_fail(EXESS_LONG, "-1", EXESS_NON_NEGATIVE_INTEGER, EXESS_OUT_OF_RANGE);
489 : 1 : check_perf(EXESS_LONG, "0", EXESS_NON_NEGATIVE_INTEGER, "0");
490 : 1 : check_perf(
491 : : EXESS_LONG, max_long_str, EXESS_NON_NEGATIVE_INTEGER, max_long_str);
492 : :
493 : : // Positive values to/from positiveInteger
494 : 1 : check_fail(EXESS_LONG, "-1", EXESS_POSITIVE_INTEGER, EXESS_OUT_OF_RANGE);
495 : 1 : check_fail(EXESS_LONG, "0", EXESS_POSITIVE_INTEGER, EXESS_OUT_OF_RANGE);
496 : 1 : check_perf(EXESS_LONG, max_long_str, EXESS_POSITIVE_INTEGER, max_long_str);
497 : 1 : check_fail(EXESS_POSITIVE_INTEGER,
498 : : "9223372036854775808",
499 : : EXESS_LONG,
500 : : EXESS_OUT_OF_RANGE);
501 : :
502 : : // Float
503 : 1 : check_fail(EXESS_FLOAT, "1.5", EXESS_LONG, EXESS_LOSS);
504 : 1 : check_fail(EXESS_FLOAT, "1E38", EXESS_LONG, EXESS_OUT_OF_RANGE);
505 : 1 : check_perf(EXESS_LONG, "-16777215", EXESS_FLOAT, "-1.6777215E7");
506 : 1 : check_fail(EXESS_LONG, "-16777216", EXESS_FLOAT, EXESS_OUT_OF_RANGE);
507 : 1 : check_fail(EXESS_FLOAT, "-16777216", EXESS_LONG, EXESS_OUT_OF_RANGE);
508 : 1 : check_perf(EXESS_LONG, "16777215", EXESS_FLOAT, "1.6777215E7");
509 : 1 : check_fail(EXESS_LONG, "16777216", EXESS_FLOAT, EXESS_OUT_OF_RANGE);
510 : 1 : check_fail(EXESS_FLOAT, "16777216", EXESS_LONG, EXESS_OUT_OF_RANGE);
511 : 1 : check_perf(EXESS_FLOAT, "1.0E0", EXESS_LONG, "1");
512 : 1 : check_round(EXESS_FLOAT, "1.5E0", EXESS_LONG, "2");
513 : 1 : check_round(EXESS_FLOAT, "2.5E0", EXESS_LONG, "2");
514 : 1 : check_round(EXESS_FLOAT, "3.5E0", EXESS_LONG, "4");
515 : :
516 : : // Double
517 : 1 : check_fail(EXESS_DOUBLE, "1.5", EXESS_LONG, EXESS_LOSS);
518 : 1 : check_fail(EXESS_DOUBLE, "1E38", EXESS_LONG, EXESS_OUT_OF_RANGE);
519 : 1 : check_perf(
520 : : EXESS_LONG, "-9007199254740991", EXESS_DOUBLE, "-9.007199254740991E15");
521 : 1 : check_fail(EXESS_LONG, "-9007199254740992", EXESS_DOUBLE, EXESS_OUT_OF_RANGE);
522 : 1 : check_fail(EXESS_DOUBLE, "-9007199254740992", EXESS_LONG, EXESS_OUT_OF_RANGE);
523 : 1 : check_perf(
524 : : EXESS_LONG, "9007199254740991", EXESS_DOUBLE, "9.007199254740991E15");
525 : 1 : check_fail(EXESS_LONG, "9007199254740992", EXESS_DOUBLE, EXESS_OUT_OF_RANGE);
526 : 1 : check_fail(EXESS_DOUBLE, "9007199254740992", EXESS_LONG, EXESS_OUT_OF_RANGE);
527 : 1 : check_perf(EXESS_DOUBLE, "1.0E0", EXESS_LONG, "1");
528 : 1 : check_round(EXESS_DOUBLE, "1.5E0", EXESS_LONG, "2");
529 : 1 : check_round(EXESS_DOUBLE, "2.5E0", EXESS_LONG, "2");
530 : 1 : check_round(EXESS_DOUBLE, "3.5E0", EXESS_LONG, "4");
531 : 1 : }
532 : :
533 : : static void
534 : 1 : test_ulong(void)
535 : : {
536 : : // Truncating boolean conversion
537 : 1 : check_trunc(EXESS_ULONG, "42", EXESS_BOOLEAN, "true");
538 : :
539 : : // All integer types
540 : 1 : check_perf(EXESS_ULONG, max_long_str, EXESS_LONG, max_long_str);
541 : 1 : check_fail(EXESS_ULONG, max_ulong_str, EXESS_LONG, EXESS_OUT_OF_RANGE);
542 : 1 : check_perf(EXESS_ULONG, "2147483647", EXESS_INT, "2147483647");
543 : 1 : check_fail(EXESS_ULONG, "2147483648", EXESS_INT, EXESS_OUT_OF_RANGE);
544 : 1 : check_fail(EXESS_INT, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
545 : 1 : check_perf(EXESS_ULONG, "32767", EXESS_SHORT, "32767");
546 : 1 : check_fail(EXESS_ULONG, "32768", EXESS_SHORT, EXESS_OUT_OF_RANGE);
547 : 1 : check_fail(EXESS_SHORT, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
548 : 1 : check_perf(EXESS_ULONG, "127", EXESS_BYTE, "127");
549 : 1 : check_fail(EXESS_ULONG, "128", EXESS_BYTE, EXESS_OUT_OF_RANGE);
550 : 1 : check_fail(EXESS_BYTE, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
551 : :
552 : : // All unsigned types
553 : 1 : check_perf(EXESS_ULONG, "4294967295", EXESS_UINT, "4294967295");
554 : 1 : check_fail(EXESS_ULONG, "4294967296", EXESS_UINT, EXESS_OUT_OF_RANGE);
555 : 1 : check_perf(EXESS_ULONG, "65535", EXESS_USHORT, "65535");
556 : 1 : check_fail(EXESS_ULONG, "65536", EXESS_USHORT, EXESS_OUT_OF_RANGE);
557 : 1 : check_perf(EXESS_ULONG, "255", EXESS_UBYTE, "255");
558 : 1 : check_fail(EXESS_ULONG, "256", EXESS_UBYTE, EXESS_OUT_OF_RANGE);
559 : :
560 : : // Limits
561 : 1 : check_perf(EXESS_ULONG, "0", EXESS_INTEGER, "0");
562 : :
563 : : // Only zero to/from nonPositiveInteger
564 : 1 : check_perf(EXESS_ULONG, "0", EXESS_NON_POSITIVE_INTEGER, "0");
565 : 1 : check_fail(EXESS_ULONG, "1", EXESS_NON_POSITIVE_INTEGER, EXESS_OUT_OF_RANGE);
566 : :
567 : : // Not convertible to/from negativeInteger
568 : 1 : check_fail(EXESS_ULONG, "0", EXESS_NEGATIVE_INTEGER, EXESS_OUT_OF_RANGE);
569 : 1 : check_fail(EXESS_ULONG, "1", EXESS_NEGATIVE_INTEGER, EXESS_OUT_OF_RANGE);
570 : :
571 : : // Any value to/from nonNegativeInteger
572 : 1 : check_perf(EXESS_ULONG, "0", EXESS_NON_NEGATIVE_INTEGER, "0");
573 : 1 : check_perf(
574 : : EXESS_ULONG, max_ulong_str, EXESS_NON_NEGATIVE_INTEGER, max_ulong_str);
575 : :
576 : : // Positive values to/from positiveInteger
577 : 1 : check_fail(EXESS_ULONG, "0", EXESS_POSITIVE_INTEGER, EXESS_OUT_OF_RANGE);
578 : 1 : check_perf(EXESS_ULONG, "1", EXESS_POSITIVE_INTEGER, "1");
579 : :
580 : : // Float
581 : 1 : check_fail(EXESS_FLOAT, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
582 : 1 : check_fail(EXESS_FLOAT, "1.5", EXESS_ULONG, EXESS_LOSS);
583 : 1 : check_perf(EXESS_ULONG, "0", EXESS_FLOAT, "0.0E0");
584 : 1 : check_perf(EXESS_ULONG, "16777215", EXESS_FLOAT, "1.6777215E7");
585 : 1 : check_fail(EXESS_ULONG, "16777216", EXESS_FLOAT, EXESS_OUT_OF_RANGE);
586 : 1 : check_fail(EXESS_FLOAT, "16777216", EXESS_ULONG, EXESS_OUT_OF_RANGE);
587 : 1 : check_perf(EXESS_FLOAT, "1.0E0", EXESS_ULONG, "1");
588 : 1 : check_round(EXESS_FLOAT, "1.5E0", EXESS_ULONG, "2");
589 : 1 : check_round(EXESS_FLOAT, "2.5E0", EXESS_ULONG, "2");
590 : 1 : check_round(EXESS_FLOAT, "3.5E0", EXESS_ULONG, "4");
591 : :
592 : : // Double
593 : 1 : check_fail(EXESS_DOUBLE, "-1", EXESS_ULONG, EXESS_OUT_OF_RANGE);
594 : 1 : check_fail(EXESS_DOUBLE, "1.5", EXESS_ULONG, EXESS_LOSS);
595 : 1 : check_perf(EXESS_ULONG, "0", EXESS_DOUBLE, "0.0E0");
596 : 1 : check_perf(
597 : : EXESS_ULONG, "9007199254740991", EXESS_DOUBLE, "9.007199254740991E15");
598 : 1 : check_fail(EXESS_ULONG, "9007199254740992", EXESS_DOUBLE, EXESS_OUT_OF_RANGE);
599 : 1 : check_fail(EXESS_DOUBLE, "9007199254740992", EXESS_ULONG, EXESS_OUT_OF_RANGE);
600 : 1 : check_perf(EXESS_DOUBLE, "1.0E0", EXESS_ULONG, "1");
601 : 1 : check_round(EXESS_DOUBLE, "1.5E0", EXESS_ULONG, "2");
602 : 1 : check_round(EXESS_DOUBLE, "2.5E0", EXESS_ULONG, "2");
603 : 1 : check_round(EXESS_DOUBLE, "3.5E0", EXESS_ULONG, "4");
604 : 1 : }
605 : :
606 : : static void
607 : 1 : test_large_integers(void)
608 : : {
609 : 1 : check_fail(EXESS_TIME, "00:00:00", EXESS_INTEGER, EXESS_UNSUPPORTED);
610 : 1 : check_fail(
611 : : EXESS_TIME, "00:00:00", EXESS_NON_POSITIVE_INTEGER, EXESS_UNSUPPORTED);
612 : 1 : check_fail(EXESS_TIME, "00:00:00", EXESS_NEGATIVE_INTEGER, EXESS_UNSUPPORTED);
613 : 1 : check_fail(
614 : : EXESS_TIME, "00:00:00", EXESS_NON_NEGATIVE_INTEGER, EXESS_UNSUPPORTED);
615 : 1 : check_fail(EXESS_TIME, "00:00:00", EXESS_POSITIVE_INTEGER, EXESS_UNSUPPORTED);
616 : 1 : }
617 : :
618 : : static void
619 : 1 : test_date_time(void)
620 : : {
621 : 1 : check_fail(EXESS_DATE_TIME, "2001-02-03T04:05:06", EXESS_TIME, EXESS_LOSS);
622 : :
623 : 1 : check_trunc(EXESS_DATE_TIME, "2001-02-03T04:05:06", EXESS_TIME, "04:05:06");
624 : :
625 : 1 : check_trunc(EXESS_DATE_TIME, "2001-02-03T04:05:06Z", EXESS_TIME, "04:05:06Z");
626 : :
627 : 1 : check_trunc(
628 : : EXESS_DATE_TIME, "2001-02-03T04:05:06+07:30", EXESS_TIME, "04:05:06+07:30");
629 : :
630 : 1 : check_trunc(EXESS_DATE_TIME, "2001-02-03T04:05:06", EXESS_DATE, "2001-02-03");
631 : :
632 : 1 : check_trunc(
633 : : EXESS_DATE_TIME, "2001-02-03T04:05:06Z", EXESS_DATE, "2001-02-03Z");
634 : :
635 : 1 : check_trunc(EXESS_DATE_TIME,
636 : : "2001-02-03T04:05:06+07:30",
637 : : EXESS_DATE,
638 : : "2001-02-03+07:30");
639 : 1 : }
640 : :
641 : : static void
642 : 1 : test_number_to_time(void)
643 : : {
644 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DURATION, EXESS_UNSUPPORTED);
645 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
646 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_TIME, EXESS_UNSUPPORTED);
647 : 1 : check_fail(EXESS_BOOLEAN, "true", EXESS_DATE, EXESS_UNSUPPORTED);
648 : :
649 : 1 : check_fail(EXESS_LONG, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
650 : 1 : check_fail(EXESS_LONG, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
651 : 1 : check_fail(EXESS_LONG, "1", EXESS_TIME, EXESS_UNSUPPORTED);
652 : 1 : check_fail(EXESS_LONG, "1", EXESS_DATE, EXESS_UNSUPPORTED);
653 : :
654 : 1 : check_fail(EXESS_INT, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
655 : 1 : check_fail(EXESS_INT, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
656 : 1 : check_fail(EXESS_INT, "1", EXESS_TIME, EXESS_UNSUPPORTED);
657 : 1 : check_fail(EXESS_INT, "1", EXESS_DATE, EXESS_UNSUPPORTED);
658 : :
659 : 1 : check_fail(EXESS_SHORT, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
660 : 1 : check_fail(EXESS_SHORT, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
661 : 1 : check_fail(EXESS_SHORT, "1", EXESS_TIME, EXESS_UNSUPPORTED);
662 : 1 : check_fail(EXESS_SHORT, "1", EXESS_DATE, EXESS_UNSUPPORTED);
663 : :
664 : 1 : check_fail(EXESS_BYTE, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
665 : 1 : check_fail(EXESS_BYTE, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
666 : 1 : check_fail(EXESS_BYTE, "1", EXESS_TIME, EXESS_UNSUPPORTED);
667 : 1 : check_fail(EXESS_BYTE, "1", EXESS_DATE, EXESS_UNSUPPORTED);
668 : :
669 : 1 : check_fail(EXESS_ULONG, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
670 : 1 : check_fail(EXESS_ULONG, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
671 : 1 : check_fail(EXESS_ULONG, "1", EXESS_TIME, EXESS_UNSUPPORTED);
672 : 1 : check_fail(EXESS_ULONG, "1", EXESS_DATE, EXESS_UNSUPPORTED);
673 : :
674 : 1 : check_fail(EXESS_UINT, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
675 : 1 : check_fail(EXESS_UINT, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
676 : 1 : check_fail(EXESS_UINT, "1", EXESS_TIME, EXESS_UNSUPPORTED);
677 : 1 : check_fail(EXESS_UINT, "1", EXESS_DATE, EXESS_UNSUPPORTED);
678 : :
679 : 1 : check_fail(EXESS_USHORT, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
680 : 1 : check_fail(EXESS_USHORT, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
681 : 1 : check_fail(EXESS_USHORT, "1", EXESS_TIME, EXESS_UNSUPPORTED);
682 : 1 : check_fail(EXESS_USHORT, "1", EXESS_DATE, EXESS_UNSUPPORTED);
683 : :
684 : 1 : check_fail(EXESS_UBYTE, "1", EXESS_DURATION, EXESS_UNSUPPORTED);
685 : 1 : check_fail(EXESS_UBYTE, "1", EXESS_DATE_TIME, EXESS_UNSUPPORTED);
686 : 1 : check_fail(EXESS_UBYTE, "1", EXESS_TIME, EXESS_UNSUPPORTED);
687 : 1 : check_fail(EXESS_UBYTE, "1", EXESS_DATE, EXESS_UNSUPPORTED);
688 : 1 : }
689 : :
690 : : static void
691 : 1 : test_time_to_number(void)
692 : : {
693 : : static const char* const duration_str = "P1Y";
694 : : static const char* const datetime_str = "2001-02-03T04:05:06";
695 : : static const char* const time_str = "04:05:06";
696 : : static const char* const date_str = "2001-02-03";
697 : :
698 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_BOOLEAN, EXESS_UNSUPPORTED);
699 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_BOOLEAN, EXESS_UNSUPPORTED);
700 : 1 : check_fail(EXESS_TIME, time_str, EXESS_BOOLEAN, EXESS_UNSUPPORTED);
701 : 1 : check_fail(EXESS_DATE, date_str, EXESS_BOOLEAN, EXESS_UNSUPPORTED);
702 : :
703 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_INT, EXESS_UNSUPPORTED);
704 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_INT, EXESS_UNSUPPORTED);
705 : 1 : check_fail(EXESS_TIME, time_str, EXESS_INT, EXESS_UNSUPPORTED);
706 : 1 : check_fail(EXESS_DATE, date_str, EXESS_INT, EXESS_UNSUPPORTED);
707 : :
708 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_SHORT, EXESS_UNSUPPORTED);
709 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_SHORT, EXESS_UNSUPPORTED);
710 : 1 : check_fail(EXESS_TIME, time_str, EXESS_SHORT, EXESS_UNSUPPORTED);
711 : 1 : check_fail(EXESS_DATE, date_str, EXESS_SHORT, EXESS_UNSUPPORTED);
712 : :
713 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_BYTE, EXESS_UNSUPPORTED);
714 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_BYTE, EXESS_UNSUPPORTED);
715 : 1 : check_fail(EXESS_TIME, time_str, EXESS_BYTE, EXESS_UNSUPPORTED);
716 : 1 : check_fail(EXESS_DATE, date_str, EXESS_BYTE, EXESS_UNSUPPORTED);
717 : :
718 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_ULONG, EXESS_UNSUPPORTED);
719 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_ULONG, EXESS_UNSUPPORTED);
720 : 1 : check_fail(EXESS_TIME, time_str, EXESS_ULONG, EXESS_UNSUPPORTED);
721 : 1 : check_fail(EXESS_DATE, date_str, EXESS_ULONG, EXESS_UNSUPPORTED);
722 : :
723 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_UINT, EXESS_UNSUPPORTED);
724 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_UINT, EXESS_UNSUPPORTED);
725 : 1 : check_fail(EXESS_TIME, time_str, EXESS_UINT, EXESS_UNSUPPORTED);
726 : 1 : check_fail(EXESS_DATE, date_str, EXESS_UINT, EXESS_UNSUPPORTED);
727 : :
728 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_USHORT, EXESS_UNSUPPORTED);
729 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_USHORT, EXESS_UNSUPPORTED);
730 : 1 : check_fail(EXESS_TIME, time_str, EXESS_USHORT, EXESS_UNSUPPORTED);
731 : 1 : check_fail(EXESS_DATE, date_str, EXESS_USHORT, EXESS_UNSUPPORTED);
732 : :
733 : 1 : check_fail(EXESS_DURATION, duration_str, EXESS_UBYTE, EXESS_UNSUPPORTED);
734 : 1 : check_fail(EXESS_DATE_TIME, datetime_str, EXESS_UBYTE, EXESS_UNSUPPORTED);
735 : 1 : check_fail(EXESS_TIME, time_str, EXESS_UBYTE, EXESS_UNSUPPORTED);
736 : 1 : check_fail(EXESS_DATE, date_str, EXESS_UBYTE, EXESS_UNSUPPORTED);
737 : 1 : }
738 : :
739 : : static void
740 : 1 : test_binary(void)
741 : : {
742 : 1 : check_perf(EXESS_HEX, "666F6F", EXESS_BASE64, "Zm9v");
743 : 1 : check_perf(EXESS_BASE64, "Zm9v", EXESS_HEX, "666F6F");
744 : :
745 : 1 : check_fail(EXESS_LONG, "-2147483649", EXESS_HEX, EXESS_UNSUPPORTED);
746 : 1 : check_fail(EXESS_LONG, "-2147483649", EXESS_BASE64, EXESS_UNSUPPORTED);
747 : 1 : }
748 : :
749 : : int
750 : 1 : main(void)
751 : : {
752 : 1 : test_overflow();
753 : 1 : test_unknown();
754 : 1 : test_boolean();
755 : 1 : test_floating();
756 : 1 : test_decimal();
757 : 1 : test_round_trunc();
758 : 1 : test_long();
759 : 1 : test_ulong();
760 : 1 : test_large_integers();
761 : 1 : test_date_time();
762 : 1 : test_number_to_time();
763 : 1 : test_time_to_number();
764 : 1 : test_binary();
765 : :
766 : 1 : return 0;
767 : : }
|