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