1#include "tests/test_internal.h"
2#include <parse.h>
3
4TEST_GROUP_DECLARE(parse);
5
6TEST_DECLARE_UNIT(parse, data_size_units) {
7 uint64_t val = 0;
8
9 TEST_ASSERT(parse_is_data_size("1024", &val) && val == 1024);
10 TEST_ASSERT(parse_is_data_size("1K", &val) && val == 1024);
11 TEST_ASSERT(parse_is_data_size("4KiB", &val) && val == 4096);
12 TEST_ASSERT(parse_is_data_size("16M", &val) && val == 16 * 1024 * 1024);
13 TEST_ASSERT(parse_is_data_size("2G", &val) &&
14 val == 2LL * 1024 * 1024 * 1024);
15 TEST_ASSERT(parse_is_data_size("1T", &val) &&
16 val == 1024LL * 1024 * 1024 * 1024);
17
18 TEST_ASSERT(parse_is_data_size("4kib", &val) && val == 4096);
19 TEST_ASSERT(parse_is_data_size("8mb", &val) && val == 8 * 1024 * 1024);
20
21 TEST_ASSERT(!parse_is_data_size("", NULL));
22 TEST_ASSERT(!parse_is_data_size("invalid", NULL));
23 TEST_ASSERT(!parse_is_data_size("1024XYZ", NULL));
24
25 TEST_ASSERT(parse_is_data_size("64M", &val) && val == 64 * 1024 * 1024);
26 TEST_ASSERT(!parse_is_data_size("not_a_size", NULL));
27
28 return TEST_SUCCESS;
29}
30
31TEST_DECLARE_UNIT(parse, duration_units) {
32 time_ns_t dur = 0;
33
34 TEST_ASSERT(parse_is_duration("500ns", &dur) && dur == 500);
35 TEST_ASSERT(parse_is_duration("20us", &dur) && dur == 20000);
36 TEST_ASSERT(parse_is_duration("10ms", &dur) && dur == 10000000);
37 TEST_ASSERT(parse_is_duration("2s", &dur) && dur == 2000000000ULL);
38 TEST_ASSERT(parse_is_duration("5m", &dur) &&
39 dur == 5ULL * 60 * 1000000000ULL);
40 TEST_ASSERT(parse_is_duration("3min", &dur) &&
41 dur == 3ULL * 60 * 1000000000ULL);
42 TEST_ASSERT(parse_is_duration("2mins", &dur) &&
43 dur == 2ULL * 60 * 1000000000ULL);
44 TEST_ASSERT(parse_is_duration("1minute", &dur) &&
45 dur == 1ULL * 60 * 1000000000ULL);
46 TEST_ASSERT(parse_is_duration("4minutes", &dur) &&
47 dur == 4ULL * 60 * 1000000000ULL);
48 TEST_ASSERT(parse_is_duration("1h", &dur) &&
49 dur == 1ULL * 3600 * 1000000000ULL);
50 TEST_ASSERT(parse_is_duration("2hr", &dur) &&
51 dur == 2ULL * 3600 * 1000000000ULL);
52 TEST_ASSERT(parse_is_duration("6hrs", &dur) &&
53 dur == 6ULL * 3600 * 1000000000ULL);
54 TEST_ASSERT(parse_is_duration("12hour", &dur) &&
55 dur == 12ULL * 3600 * 1000000000ULL);
56 TEST_ASSERT(parse_is_duration("24hours", &dur) &&
57 dur == 24ULL * 3600 * 1000000000ULL);
58 TEST_ASSERT(parse_is_duration("1d", &dur) &&
59 dur == 1ULL * 86400 * 1000000000ULL);
60 TEST_ASSERT(parse_is_duration("3day", &dur) &&
61 dur == 3ULL * 86400 * 1000000000ULL);
62 TEST_ASSERT(parse_is_duration("7days", &dur) &&
63 dur == 7ULL * 86400 * 1000000000ULL);
64
65 TEST_ASSERT(parse_is_duration(" 10 m ", &dur) &&
66 dur == 10ULL * 60 * 1000000000ULL);
67 TEST_ASSERT(parse_is_duration(" 2 hours ", &dur) &&
68 dur == 2ULL * 3600 * 1000000000ULL);
69 TEST_ASSERT(parse_is_duration("1000", &dur) && dur == 1000);
70
71 TEST_ASSERT(!parse_is_duration("bad", NULL));
72 TEST_ASSERT(!parse_is_duration("", NULL));
73 TEST_ASSERT(!parse_is_duration("100xyz", NULL));
74
75 TEST_ASSERT(parse_is_duration("100ms", &dur) && dur == 100000000ULL);
76 TEST_ASSERT(!parse_is_duration("invalid", NULL));
77
78 return TEST_SUCCESS;
79}
80
81TEST_DECLARE_UNIT(parse, cpu_mask_ranges) {
82 size_t n_cpus = 16;
83 struct cpu_mask m1 = {0};
84
85 TEST_ASSERT(parse_is_cpu_mask("3", &m1, n_cpus));
86 TEST_ASSERT(cpu_mask_test(&m1, 3));
87 TEST_ASSERT(!cpu_mask_test(&m1, 0));
88 TEST_ASSERT_EQ(cpu_mask_popcount(&m1), 1);
89 cpu_mask_deinit(m: &m1);
90
91 struct cpu_mask m2 = {0};
92 TEST_ASSERT(parse_is_cpu_mask("0-3,7,9-11", &m2, n_cpus));
93 TEST_ASSERT(cpu_mask_test(&m2, 0) && cpu_mask_test(&m2, 1) &&
94 cpu_mask_test(&m2, 2) && cpu_mask_test(&m2, 3));
95 TEST_ASSERT(cpu_mask_test(&m2, 7));
96 TEST_ASSERT(cpu_mask_test(&m2, 9) && cpu_mask_test(&m2, 10) &&
97 cpu_mask_test(&m2, 11));
98 TEST_ASSERT(!cpu_mask_test(&m2, 4) && !cpu_mask_test(&m2, 8));
99 TEST_ASSERT_EQ(cpu_mask_popcount(&m2), 8);
100 cpu_mask_deinit(m: &m2);
101
102 TEST_ASSERT(!parse_is_cpu_mask("16", NULL, n_cpus));
103 TEST_ASSERT(!parse_is_cpu_mask("5-2", NULL, n_cpus));
104 TEST_ASSERT(parse_is_cpu_mask("0-3", NULL, n_cpus));
105 TEST_ASSERT(!parse_is_cpu_mask("0-16", NULL, n_cpus));
106 TEST_ASSERT(!parse_is_cpu_mask("abc", NULL, n_cpus));
107
108 return TEST_SUCCESS;
109}
110
111TEST_DECLARE_UNIT(parse, bool_syntax) {
112 bool val = false;
113
114 TEST_ASSERT(parse_is_bool("true", &val) && val == true);
115 TEST_ASSERT(parse_is_bool("YES", &val) && val == true);
116 TEST_ASSERT(parse_is_bool("on", &val) && val == true);
117 TEST_ASSERT(parse_is_bool("1", &val) && val == true);
118 TEST_ASSERT(parse_is_bool("enabled", &val) && val == true);
119
120 TEST_ASSERT(parse_is_bool("false", &val) && val == false);
121 TEST_ASSERT(parse_is_bool("NO", &val) && val == false);
122 TEST_ASSERT(parse_is_bool("off", &val) && val == false);
123 TEST_ASSERT(parse_is_bool("0", &val) && val == false);
124 TEST_ASSERT(parse_is_bool("disabled", &val) && val == false);
125
126 TEST_ASSERT(!parse_is_bool("maybe", NULL));
127 TEST_ASSERT(!parse_is_bool("", NULL));
128 TEST_ASSERT(!parse_is_bool("2", NULL));
129
130 return TEST_SUCCESS;
131}
132
133TEST_DECLARE_UNIT(parse, range_and_mac) {
134 uint64_t start = 0, end = 0;
135
136 TEST_ASSERT(parse_is_range("0-100", &start, &end) && start == 0 &&
137 end == 100);
138 TEST_ASSERT(parse_is_range("42-42", &start, &end) && start == 42 &&
139 end == 42);
140 TEST_ASSERT(parse_is_range("100..200", &start, &end) && start == 100 &&
141 end == 200);
142 TEST_ASSERT(parse_is_range("10ms-50ms", &start, &end) &&
143 start == 10000000ULL && end == 50000000ULL);
144 TEST_ASSERT(parse_is_range("1MiB..4MiB", &start, &end) &&
145 start == 1048576ULL && end == 4194304ULL);
146 TEST_ASSERT(!parse_is_range("50ms-10ms", NULL, NULL));
147 TEST_ASSERT(!parse_is_range("100-50", NULL, NULL));
148 TEST_ASSERT(!parse_is_range("100", NULL, NULL));
149 TEST_ASSERT(!parse_is_range("abc-def", NULL, NULL));
150
151 uint64_t mac = 0;
152 TEST_ASSERT(parse_is_mac("52:54:00:12:34:56", &mac) &&
153 mac == 0x525400123456ULL);
154 TEST_ASSERT(parse_is_mac("AA:BB:CC:DD:EE:FF", &mac) &&
155 mac == 0xAABBCCDDEEFFULL);
156 TEST_ASSERT(!parse_is_mac("52:54:00:12:34", NULL));
157 TEST_ASSERT(!parse_is_mac("52:54:00:12:34:56:78", NULL));
158 TEST_ASSERT(!parse_is_mac("52-54-00-12-34-56", NULL));
159 TEST_ASSERT(!parse_is_mac("ZZ:54:00:12:34:56", NULL));
160
161 return TEST_SUCCESS;
162}
163
164TEST_DECLARE_UNIT(parse, numbers_and_fx) {
165 fx32_32_t fx = 0;
166 TEST_ASSERT(parse_is_fx("0.5", &fx) && fx == FX(0.5));
167 TEST_ASSERT(parse_is_fx("1.25", &fx) && fx == FX(1.25));
168 TEST_ASSERT(parse_is_fx("-2.5", &fx) && fx == FX(-2.5));
169 TEST_ASSERT(!parse_is_fx("invalid", NULL));
170
171 int64_t iv = 0;
172 TEST_ASSERT(parse_is_int("-1234", &iv) && iv == -1234);
173 TEST_ASSERT(parse_is_int("0x20", &iv) && iv == 32);
174 TEST_ASSERT(!parse_is_int("abc_not_hex", NULL));
175
176 uint64_t uv = 0;
177 TEST_ASSERT(parse_is_uint("1234", &uv) && uv == 1234);
178 TEST_ASSERT(parse_is_uint("0x100", &uv) && uv == 256);
179 TEST_ASSERT(!parse_is_uint("-10", NULL));
180
181 return TEST_SUCCESS;
182}
183
184TEST_DECLARE_UNIT(parse, list_and_escaping) {
185 struct parse_list list = {0};
186
187 /* comma-separated list */
188 TEST_ASSERT(parse_is_list("apple,banana,cherry", &list));
189 TEST_ASSERT_EQ(list.count, 3);
190 TEST_ASSERT_STR_EQ(list.items[0], "apple");
191 TEST_ASSERT_STR_EQ(list.items[1], "banana");
192 TEST_ASSERT_STR_EQ(list.items[2], "cherry");
193 parse_list_free(list: &list);
194
195 /* Quoted items */
196 TEST_ASSERT(parse_is_list("first,\"second,with,comma\",third", &list));
197 TEST_ASSERT_EQ(list.count, 3);
198 TEST_ASSERT_STR_EQ(list.items[0], "first");
199 TEST_ASSERT_STR_EQ(list.items[1], "second,with,comma");
200 TEST_ASSERT_STR_EQ(list.items[2], "third");
201 parse_list_free(list: &list);
202
203 /* Escape characters */
204 TEST_ASSERT(parse_is_list("escaped\\,comma,line\\nbreak", &list));
205 TEST_ASSERT_EQ(list.count, 2);
206 TEST_ASSERT_STR_EQ(list.items[0], "escaped,comma");
207 TEST_ASSERT_STR_EQ(list.items[1], "line\nbreak");
208 parse_list_free(list: &list);
209
210 /* Whitespace */
211 TEST_ASSERT(parse_is_list(" alpha , \" beta \" , gamma ", &list));
212 TEST_ASSERT_EQ(list.count, 3);
213 TEST_ASSERT_STR_EQ(list.items[0], "alpha");
214 TEST_ASSERT_STR_EQ(list.items[1], " beta ");
215 TEST_ASSERT_STR_EQ(list.items[2], "gamma");
216
217 /* parse_list_for_each macro */
218 size_t count = 0;
219 const char *item = NULL;
220 parse_list_for_each(item, &list) {
221 TEST_ASSERT_NONNULL(item);
222 count++;
223 }
224 TEST_ASSERT_EQ(count, 3);
225 parse_list_free(list: &list);
226
227 /* Zero-allocation syntax validation */
228 TEST_ASSERT(parse_is_list("a,b,c", NULL));
229 TEST_ASSERT(!parse_is_list("", NULL));
230 TEST_ASSERT(!parse_is_list("a,,b", NULL));
231 TEST_ASSERT(!parse_is_list("unterminated \"quote", NULL));
232
233 return TEST_SUCCESS;
234}
235