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 ExessMonthDay nozone = {1, 2, EXESS_TIMEZONE_LOCAL};
16 : : static const ExessMonthDay utc = {2, 3, EXESS_TIMEZONE_UTC};
17 : : static const ExessMonthDay zoned = {3, 4, INIT_ZONE(11, 30)};
18 : : static const ExessMonthDay lowest = {1, 1, INIT_ZONE(-14, 0)};
19 : : static const ExessMonthDay highest = {12, 31, INIT_ZONE(14, 0)};
20 : : static const ExessMonthDay garbage1 = {0, 1, INIT_ZONE(11, 30)};
21 : : static const ExessMonthDay garbage2 = {13, 1, INIT_ZONE(11, 30)};
22 : : static const ExessMonthDay garbage3 = {1, 0, INIT_ZONE(11, 30)};
23 : : static const ExessMonthDay garbage4 = {1, 32, INIT_ZONE(11, 30)};
24 : :
25 : : static void
26 : 22 : check_read(const char* const string,
27 : : const ExessStatus expected_status,
28 : : const uint8_t expected_month,
29 : : const uint8_t expected_day,
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 : 22 : ExessMonthDay value = {0, 0, EXESS_TIMEZONE_LOCAL};
36 : :
37 : 22 : const ExessResult r = exess_read_month_day(string, &value);
38 [ - + ]: 22 : assert(r.status == expected_status);
39 [ - + ]: 22 : assert(r.count == expected_count);
40 [ - + ]: 22 : assert(value.month == expected_month);
41 [ - + ]: 22 : assert(value.day == expected_day);
42 [ + + + + : 22 : assert((!expected_tz_is_present && value.zone == EXESS_TIMEZONE_LOCAL) ||
- + ]
43 : : value.zone == (4 * expected_tz_hour) + (expected_tz_minute / 15));
44 : 22 : }
45 : :
46 : : static void
47 : 1 : test_read_month_day(void)
48 : : {
49 : : // No input
50 : 1 : check_read("", EXESS_EXPECTED_DASH, 0, 0, 0, 0, false, 0);
51 : 1 : check_read("\t\n\r ", EXESS_EXPECTED_DASH, 0, 0, 0, 0, false, 4);
52 : :
53 : : // Good values
54 : 1 : check_read("--04-12", EXESS_SUCCESS, 4, 12, 0, 0, false, 7);
55 : 1 : check_read("--04-12-05:00", EXESS_SUCCESS, 4, 12, -5, 0, true, 13);
56 : 1 : check_read("--04-12Z", EXESS_SUCCESS, 4, 12, 0, 0, true, 8);
57 : 1 : check_read("--10-26", EXESS_SUCCESS, 10, 26, 0, 0, false, 7);
58 : 1 : check_read("--10-26+02:00", EXESS_SUCCESS, 10, 26, 2, 0, true, 13);
59 : 1 : check_read("--10-26Z", EXESS_SUCCESS, 10, 26, 0, 0, true, 8);
60 : 1 : check_read("--10-26+00:00", EXESS_SUCCESS, 10, 26, 0, 0, true, 13);
61 : :
62 : : // Non-canonical
63 : 1 : check_read(" --04-12 ", EXESS_SUCCESS, 4, 12, 0, 0, false, 8);
64 : :
65 : : // Longest possible string
66 : 1 : check_read("--01-01-14:00",
67 : : EXESS_SUCCESS,
68 : : 1,
69 : : 1,
70 : : -14,
71 : : 0,
72 : : true,
73 : : EXESS_MAX_MONTH_DAY_LENGTH);
74 : :
75 : : // Limits
76 : 1 : check_read("--01-01", EXESS_SUCCESS, 1, 1, 0, 0, false, 7);
77 : 1 : check_read("--12-31", EXESS_SUCCESS, 12, 31, 0, 0, false, 7);
78 : :
79 : : // Out of range months
80 : 1 : check_read("--00-26", EXESS_OUT_OF_RANGE, 0, 0, 0, 0, false, 7);
81 : 1 : check_read("--13-26", EXESS_OUT_OF_RANGE, 13, 0, 0, 0, false, 7);
82 : :
83 : : // Out of range days (only roughly since the year is unknown)
84 : 1 : check_read("--02-00", EXESS_OUT_OF_RANGE, 2, 00, 0, 0, false, 7);
85 : 1 : check_read("--01-32", EXESS_OUT_OF_RANGE, 1, 32, 0, 0, false, 7);
86 : :
87 : : // Trailing garbage
88 : 1 : check_read("--04-12A", EXESS_SUCCESS, 4, 12, 0, 0, false, 7);
89 : :
90 : : // Garbage
91 : 1 : check_read("f", EXESS_EXPECTED_DASH, 0, 0, 0, 0, false, 0);
92 : 1 : check_read("--4-2", EXESS_EXPECTED_DIGIT, 4, 0, 0, 0, false, 5);
93 : 1 : check_read("/04/02", EXESS_EXPECTED_DASH, 0, 0, 0, 0, false, 0);
94 : 1 : check_read("-/04/02", EXESS_EXPECTED_DASH, 0, 0, 0, 0, false, 1);
95 : 1 : }
96 : :
97 : : static void
98 : 14 : check_write(const ExessMonthDay value,
99 : : const ExessStatus expected_status,
100 : : const size_t buf_size,
101 : : const char* const expected_string)
102 : : {
103 : 14 : char buf[EXESS_MAX_MONTH_DAY_LENGTH + 1] = {
104 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
105 : :
106 [ - + ]: 14 : assert(buf_size <= sizeof(buf));
107 : :
108 : 14 : const ExessResult r = exess_write_month_day(value, buf_size, buf);
109 [ - + ]: 14 : assert(r.status == expected_status);
110 [ + + ]: 14 : if (!r.status) {
111 [ - + ]: 5 : assert(!strcmp(buf, expected_string));
112 [ - + ]: 5 : assert(r.count == strlen(buf));
113 [ - + ]: 5 : assert(exess_write_month_day(value, 0, NULL).count == r.count);
114 : : }
115 : 14 : }
116 : :
117 : : static void
118 : 1 : test_write_month_day(void)
119 : : {
120 : 1 : check_write(nozone, EXESS_SUCCESS, 8, "--01-02");
121 : 1 : check_write(utc, EXESS_SUCCESS, 9, "--02-03Z");
122 : 1 : check_write(zoned, EXESS_SUCCESS, 14, "--03-04+11:30");
123 : 1 : check_write(lowest, EXESS_SUCCESS, 14, "--01-01-14:00");
124 : 1 : check_write(highest, EXESS_SUCCESS, 14, "--12-31+14:00");
125 : :
126 : 1 : check_write(garbage1, EXESS_BAD_VALUE, 14, "");
127 : 1 : check_write(garbage2, EXESS_BAD_VALUE, 14, "");
128 : 1 : check_write(garbage3, EXESS_BAD_VALUE, 14, "");
129 : 1 : check_write(garbage4, EXESS_BAD_VALUE, 14, "");
130 : :
131 : 1 : check_write(nozone, EXESS_NO_SPACE, 7, "");
132 : 1 : check_write(utc, EXESS_NO_SPACE, 8, "");
133 : 1 : check_write(zoned, EXESS_NO_SPACE, 13, "");
134 : 1 : check_write(lowest, EXESS_NO_SPACE, 3, "");
135 : 1 : check_write(highest, EXESS_NO_SPACE, 3, "");
136 : :
137 : : // Check that nothing is written when there isn't enough space
138 : 1 : char c = 42;
139 : 1 : const ExessResult r = exess_write_month_day(nozone, 0, &c);
140 [ - + ]: 1 : assert(c == 42);
141 [ - + ]: 1 : assert(r.status == EXESS_NO_SPACE);
142 [ - + ]: 1 : assert(r.count == 7);
143 : 1 : }
144 : :
145 : : int
146 : 1 : main(void)
147 : : {
148 : 1 : test_read_month_day();
149 : 1 : test_write_month_day();
150 : :
151 : 1 : return 0;
152 : : }
|