Branch data Line data Source code
1 : : // Copyright 2011-2026 David Robillard <d@drobilla.net>
2 : : // SPDX-License-Identifier: ISC
3 : :
4 : : #undef NDEBUG
5 : :
6 : : #include "time_test_utils.h"
7 : :
8 : : #include <exess/exess.h>
9 : :
10 : : #include <assert.h>
11 : : #include <stdbool.h>
12 : : #include <stdint.h>
13 : : #include <string.h>
14 : :
15 : : static const ExessYearMonth nozone = {2001, 1, EXESS_TIMEZONE_LOCAL};
16 : : static const ExessYearMonth utc = {2002, 2, EXESS_TIMEZONE_UTC};
17 : : static const ExessYearMonth zoned = {2003, 3, INIT_ZONE(11, 30)};
18 : : static const ExessYearMonth early = {99, 3, INIT_ZONE(11, 30)};
19 : : static const ExessYearMonth future = {12345, 3, INIT_ZONE(11, 30)};
20 : : static const ExessYearMonth lowest = {INT16_MIN, 1, INIT_ZONE(-14, 0)};
21 : : static const ExessYearMonth highest = {INT16_MAX, 1, INIT_ZONE(14, 0)};
22 : : static const ExessYearMonth garbage1 = {2004, 0, INIT_ZONE(11, 30)};
23 : : static const ExessYearMonth garbage2 = {2005, 13, INIT_ZONE(11, 30)};
24 : :
25 : : static void
26 : 28 : check_read(const char* const string,
27 : : const ExessStatus expected_status,
28 : : const int64_t expected_year,
29 : : const uint8_t expected_month,
30 : : const int8_t expected_tz_hour,
31 : : const int8_t expected_tz_minute,
32 : : const bool expected_tz_is_present,
33 : : const size_t expected_count)
34 : : {
35 : 28 : ExessYearMonth value = {0, 0, EXESS_TIMEZONE_LOCAL};
36 : :
37 : 28 : const ExessResult r = exess_read_year_month(string, &value);
38 [ - + ]: 28 : assert(r.status == expected_status);
39 [ - + ]: 28 : assert(r.count == expected_count);
40 [ - + ]: 28 : assert(value.year == expected_year);
41 [ - + ]: 28 : assert(value.month == expected_month);
42 [ + + - + : 28 : assert((!expected_tz_is_present && value.zone == EXESS_TIMEZONE_LOCAL) ||
- + ]
43 : : value.zone == (4 * expected_tz_hour) + (expected_tz_minute / 15));
44 : 28 : }
45 : :
46 : : static void
47 : 1 : test_read_year_month(void)
48 : : {
49 : : // No input
50 : 1 : check_read("", EXESS_EXPECTED_DIGIT, 0, 0, 0, 0, false, 0);
51 : 1 : check_read("\t\n\r ", EXESS_EXPECTED_DIGIT, 0, 0, 0, 0, false, 4);
52 : :
53 : : // Good values
54 : 1 : check_read("2004-04", EXESS_SUCCESS, 2004, 4, 0, 0, false, 7);
55 : 1 : check_read("-0045-01", EXESS_SUCCESS, -45, 1, 0, 0, false, 8);
56 : 1 : check_read("12004-04", EXESS_SUCCESS, 12004, 4, 0, 0, false, 8);
57 : 1 : check_read("2004-04-05:00", EXESS_SUCCESS, 2004, 4, -5, 0, true, 13);
58 : 1 : check_read("2004-04Z", EXESS_SUCCESS, 2004, 4, 0, 0, true, 8);
59 : 1 : check_read("2001-10", EXESS_SUCCESS, 2001, 10, 0, 0, false, 7);
60 : 1 : check_read("2001-10+02:00", EXESS_SUCCESS, 2001, 10, 2, 0, true, 13);
61 : 1 : check_read("2001-10Z", EXESS_SUCCESS, 2001, 10, 0, 0, true, 8);
62 : 1 : check_read("2001-10+00:00", EXESS_SUCCESS, 2001, 10, 0, 0, true, 13);
63 : 1 : check_read("-2001-10", EXESS_SUCCESS, -2001, 10, 0, 0, false, 8);
64 : 1 : check_read("-20000-04", EXESS_SUCCESS, -20000, 04, 0, 0, false, 9);
65 : :
66 : : // Non-canonical
67 : 1 : check_read("02004-04", EXESS_SUCCESS, 2004, 4, 0, 0, false, 8);
68 : 1 : check_read(" 02004-04 ", EXESS_SUCCESS, 2004, 4, 0, 0, false, 9);
69 : :
70 : : // Longest possible string
71 : 1 : check_read("-32768-01-14:00",
72 : : EXESS_SUCCESS,
73 : : -32768,
74 : : 1,
75 : : -14,
76 : : 0,
77 : : true,
78 : : EXESS_MAX_YEAR_MONTH_LENGTH);
79 : :
80 : : // Limits
81 : 1 : check_read("-32768-01", EXESS_SUCCESS, -32768, 1, 0, 0, false, 9);
82 : 1 : check_read("32767-01", EXESS_SUCCESS, 32767, 1, 0, 0, false, 8);
83 : :
84 : : // Out of range years
85 : 1 : check_read("-32769-01", EXESS_OUT_OF_RANGE, 0, 0, 0, 0, false, 6);
86 : 1 : check_read("32768-01", EXESS_OUT_OF_RANGE, 0, 0, 0, 0, false, 5);
87 : :
88 : : // Out of range months
89 : 1 : check_read("2001-00", EXESS_OUT_OF_RANGE, 2001, 0, 0, 0, false, 7);
90 : 1 : check_read("2001-13", EXESS_OUT_OF_RANGE, 2001, 13, 0, 0, false, 7);
91 : :
92 : : // Trailing garbage
93 : 1 : check_read("2004-04A", EXESS_SUCCESS, 2004, 4, 0, 0, false, 7);
94 : :
95 : : // Garbage
96 : 1 : check_read("f", EXESS_EXPECTED_DIGIT, 0, 0, 0, 0, false, 0);
97 : 1 : check_read("99-04", EXESS_EXPECTED_DIGIT, 99, 0, 0, 0, false, 2);
98 : 1 : check_read("2004-4", EXESS_EXPECTED_DIGIT, 2004, 4, 0, 0, false, 6);
99 : 1 : check_read("2004/04", EXESS_EXPECTED_DASH, 2004, 0, 0, 0, false, 4);
100 : 1 : check_read("04-12", EXESS_EXPECTED_DIGIT, 4, 0, 0, 0, false, 2);
101 : 1 : }
102 : :
103 : : static void
104 : 16 : check_write(const ExessYearMonth value,
105 : : const ExessStatus expected_status,
106 : : const size_t buf_size,
107 : : const char* const expected_string)
108 : : {
109 : 16 : char buf[EXESS_MAX_YEAR_MONTH_LENGTH + 1] = {
110 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
111 : :
112 [ - + ]: 16 : assert(buf_size <= sizeof(buf));
113 : :
114 : 16 : const ExessResult r = exess_write_year_month(value, buf_size, buf);
115 [ - + ]: 16 : assert(r.status == expected_status);
116 [ + + ]: 16 : if (!r.status) {
117 [ - + ]: 7 : assert(!strcmp(buf, expected_string));
118 [ - + ]: 7 : assert(r.count == strlen(buf));
119 [ - + ]: 7 : assert(exess_write_year_month(value, 0, NULL).count == r.count);
120 : : }
121 : 16 : }
122 : :
123 : : static void
124 : 1 : test_write_year_month(void)
125 : : {
126 : 1 : check_write(nozone, EXESS_SUCCESS, 8, "2001-01");
127 : 1 : check_write(utc, EXESS_SUCCESS, 9, "2002-02Z");
128 : 1 : check_write(zoned, EXESS_SUCCESS, 14, "2003-03+11:30");
129 : 1 : check_write(early, EXESS_SUCCESS, 14, "0099-03+11:30");
130 : 1 : check_write(future, EXESS_SUCCESS, 15, "12345-03+11:30");
131 : 1 : check_write(lowest, EXESS_SUCCESS, 16, "-32768-01-14:00");
132 : 1 : check_write(highest, EXESS_SUCCESS, 15, "32767-01+14:00");
133 : :
134 : 1 : check_write(garbage1, EXESS_BAD_VALUE, 14, "");
135 : 1 : check_write(garbage2, EXESS_BAD_VALUE, 14, "");
136 : :
137 : 1 : check_write(nozone, EXESS_NO_SPACE, 7, "");
138 : 1 : check_write(utc, EXESS_NO_SPACE, 8, "");
139 : 1 : check_write(zoned, EXESS_NO_SPACE, 13, "");
140 : 1 : check_write(early, EXESS_NO_SPACE, 13, "");
141 : 1 : check_write(future, EXESS_NO_SPACE, 5, "");
142 : 1 : check_write(lowest, EXESS_NO_SPACE, 5, "");
143 : 1 : check_write(highest, EXESS_NO_SPACE, 5, "");
144 : :
145 : : // Check that nothing is written when there isn't enough space
146 : 1 : char c = 42;
147 : 1 : const ExessResult r = exess_write_year_month(nozone, 0, &c);
148 [ - + ]: 1 : assert(c == 42);
149 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
150 [ - + ]: 1 : assert(r.count == 7);
151 : 1 : }
152 : :
153 : : int
154 : 1 : main(void)
155 : : {
156 : 1 : test_read_year_month();
157 : 1 : test_write_year_month();
158 : :
159 : 1 : return 0;
160 : : }
|