|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include "cx/test.h" |
|
30 |
|
31 #include "cx/properties.h" |
|
32 |
|
33 CX_TEST(test_cx_properties_init) { |
|
34 CxProperties prop; |
|
35 CX_TEST_DO { |
|
36 cxPropertiesInitDefault(&prop); |
|
37 |
|
38 CX_TEST_ASSERT(prop.config.delimiter == '='); |
|
39 CX_TEST_ASSERT(prop.config.comment1 == '#'); |
|
40 CX_TEST_ASSERT(prop.config.comment2 == 0); |
|
41 CX_TEST_ASSERT(prop.config.comment3 == 0); |
|
42 CX_TEST_ASSERT(prop.flags == 0); |
|
43 CX_TEST_ASSERT(prop.text == NULL); |
|
44 CX_TEST_ASSERT(prop.buf == NULL); |
|
45 |
|
46 cxPropertiesDestroy(&prop); |
|
47 } |
|
48 } |
|
49 |
|
50 CX_TEST(test_cx_properties_next) { |
|
51 const char *tests[] = { |
|
52 "name = value\n", |
|
53 "name=value\n", |
|
54 "n=value\n", |
|
55 "name=v\n", |
|
56 "n=v\n", |
|
57 "name = value # comment\n", |
|
58 "#comment\nn=v\n", |
|
59 "# comment1\n# comment2\n\n \n\nname = value\n", |
|
60 " name = value\n", |
|
61 "name = value\n\n" |
|
62 }; |
|
63 |
|
64 const char *keys[] = { |
|
65 "name", |
|
66 "name", |
|
67 "n", |
|
68 "name", |
|
69 "n", |
|
70 "name", |
|
71 "n", |
|
72 "name", |
|
73 "name", |
|
74 "name" |
|
75 }; |
|
76 |
|
77 const char *values[] = { |
|
78 "value", |
|
79 "value", |
|
80 "value", |
|
81 "v", |
|
82 "v", |
|
83 "value", |
|
84 "v", |
|
85 "value", |
|
86 "value", |
|
87 "value" |
|
88 }; |
|
89 |
|
90 CxProperties prop; |
|
91 cxPropertiesInitDefault(&prop); |
|
92 enum cx_properties_status result; |
|
93 cxstring key; |
|
94 cxstring value; |
|
95 CX_TEST_DO { |
|
96 for (int i = 0; i < 10; i++) { |
|
97 cxPropertiesInput(&prop, tests[i], strlen(tests[i])); |
|
98 CX_TEST_ASSERT(prop.text == tests[i]); |
|
99 CX_TEST_ASSERT(prop.text_size == strlen(tests[i])); |
|
100 CX_TEST_ASSERT(prop.text_pos == 0); |
|
101 |
|
102 result = cxPropertiesNext(&prop, &key, &value); |
|
103 cxstring k = cx_str(keys[i]); |
|
104 cxstring v = cx_str(values[i]); |
|
105 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
106 CX_TEST_ASSERT(0 == cx_strcmp(key, k)); |
|
107 CX_TEST_ASSERT(0 == cx_strcmp(value, v)); |
|
108 |
|
109 result = cxPropertiesNext(&prop, &key, &value); |
|
110 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
111 } |
|
112 } |
|
113 cxPropertiesDestroy(&prop); |
|
114 } |
|
115 |
|
116 CX_TEST(test_cx_properties_next_multi) { |
|
117 const char *keys[] = { |
|
118 "a", |
|
119 "b", |
|
120 "c", |
|
121 "uap", |
|
122 "name", |
|
123 "key1", |
|
124 "key2", |
|
125 "key3" |
|
126 }; |
|
127 |
|
128 const char *values[] = { |
|
129 "a value", |
|
130 "b value", |
|
131 "core", |
|
132 "core", |
|
133 "ucx", |
|
134 "value1", |
|
135 "value2", |
|
136 "value3" |
|
137 }; |
|
138 |
|
139 const char *str = "#\n" |
|
140 "# properties\n" |
|
141 "# contains key/value pairs\n" |
|
142 "#\n" |
|
143 "a = a value\n" |
|
144 "b = b value\n" |
|
145 "c = core\n" |
|
146 "\n# test\n" |
|
147 "uap = core\n" |
|
148 "name = ucx\n" |
|
149 "# no = property\n" |
|
150 "key1 = value1\n" |
|
151 "#key1 = wrong value\n" |
|
152 "#key2 = not value 2\n" |
|
153 "key2 = value2\n" |
|
154 "\n\n\n \n key3=value3\n"; |
|
155 |
|
156 CxProperties prop; |
|
157 cxPropertiesInitDefault(&prop); |
|
158 enum cx_properties_status result; |
|
159 cxstring key; |
|
160 cxstring value; |
|
161 |
|
162 CX_TEST_DO { |
|
163 result = cxPropertiesNext(&prop, &key, &value); |
|
164 CX_TEST_ASSERT(result == CX_PROPERTIES_NULL_INPUT); |
|
165 cxPropertiesInput(&prop, str, strlen(str)); |
|
166 for (int i = 0; i < 8; i++) { |
|
167 result = cxPropertiesNext(&prop, &key, &value); |
|
168 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
169 CX_TEST_ASSERT(!cx_strcmp(key, cx_str(keys[i]))); |
|
170 CX_TEST_ASSERT(!cx_strcmp(value, cx_str(values[i]))); |
|
171 } |
|
172 result = cxPropertiesNext(&prop, &key, &value); |
|
173 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
174 } |
|
175 cxPropertiesDestroy(&prop); |
|
176 } |
|
177 |
|
178 CX_TEST(test_cx_properties_next_part) { |
|
179 CxProperties prop; |
|
180 cxPropertiesInitDefault(&prop); |
|
181 enum cx_properties_status result; |
|
182 cxstring key; |
|
183 cxstring value; |
|
184 const char *str; |
|
185 |
|
186 CX_TEST_DO { |
|
187 str = ""; |
|
188 cxPropertiesFill(&prop, str, strlen(str)); |
|
189 result = cxPropertiesNext(&prop, &key, &value); |
|
190 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
191 |
|
192 str = " \n"; |
|
193 cxPropertiesFill(&prop, str, strlen(str)); |
|
194 result = cxPropertiesNext(&prop, &key, &value); |
|
195 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
196 |
|
197 str = "name"; |
|
198 cxPropertiesFill(&prop, str, strlen(str)); |
|
199 result = cxPropertiesNext(&prop, &key, &value); |
|
200 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
201 |
|
202 str = " "; |
|
203 cxPropertiesFill(&prop, str, strlen(str)); |
|
204 result = cxPropertiesNext(&prop, &key, &value); |
|
205 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
206 |
|
207 // call fill twice in a row |
|
208 str = "= "; |
|
209 cxPropertiesFill(&prop, str, strlen(str)); |
|
210 str = "value"; |
|
211 cxPropertiesFill(&prop, str, strlen(str)); |
|
212 result = cxPropertiesNext(&prop, &key, &value); |
|
213 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
214 |
|
215 str = "\n"; |
|
216 cxPropertiesFill(&prop, str, strlen(str)); |
|
217 result = cxPropertiesNext(&prop, &key, &value); |
|
218 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
219 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name"))); |
|
220 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value"))); |
|
221 |
|
222 // second round |
|
223 str = "#comment\n"; |
|
224 cxPropertiesFill(&prop, str, strlen(str)); |
|
225 result = cxPropertiesNext(&prop, &key, &value); |
|
226 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
227 |
|
228 str = "#comment\nname2 = "; |
|
229 cxPropertiesFill(&prop, str, strlen(str)); |
|
230 result = cxPropertiesNext(&prop, &key, &value); |
|
231 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
232 |
|
233 str = "value2\na = b\n"; |
|
234 cxPropertiesFill(&prop, str, strlen(str)); |
|
235 result = cxPropertiesNext(&prop, &key, &value); |
|
236 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
237 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("name2"))); |
|
238 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value2"))); |
|
239 |
|
240 result = cxPropertiesNext(&prop, &key, &value); |
|
241 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
242 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("a"))); |
|
243 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("b"))); |
|
244 |
|
245 str = "# comment\n#\n#\ntests = "; |
|
246 cxPropertiesFill(&prop, str, strlen(str)); |
|
247 result = cxPropertiesNext(&prop, &key, &value); |
|
248 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
249 |
|
250 str = "test1 "; |
|
251 cxPropertiesFill(&prop, str, strlen(str)); |
|
252 result = cxPropertiesNext(&prop, &key, &value); |
|
253 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
254 |
|
255 str = "test2 test3 test4\n"; |
|
256 cxPropertiesFill(&prop, str, strlen(str)); |
|
257 result = cxPropertiesNext(&prop, &key, &value); |
|
258 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
259 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("tests"))); |
|
260 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("test1 test2 test3 test4"))); |
|
261 |
|
262 // test if cxPropertiesNext finds a name/value after a comment |
|
263 str = "# just a comment"; |
|
264 cxPropertiesFill(&prop, str, strlen(str)); |
|
265 result = cxPropertiesNext(&prop, &key, &value); |
|
266 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
267 |
|
268 str = " in 3"; |
|
269 cxPropertiesFill(&prop, str, strlen(str)); |
|
270 result = cxPropertiesNext(&prop, &key, &value); |
|
271 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
272 |
|
273 str = " parts\nx = 1\n"; |
|
274 cxPropertiesFill(&prop, str, strlen(str)); |
|
275 result = cxPropertiesNext(&prop, &key, &value); |
|
276 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
277 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("x"))); |
|
278 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("1"))); |
|
279 |
|
280 // finally we are done |
|
281 result = cxPropertiesNext(&prop, &key, &value); |
|
282 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
283 } |
|
284 cxPropertiesDestroy(&prop); |
|
285 } |
|
286 |
|
287 CX_TEST(test_ucx_properties_next_long_lines) { |
|
288 CxProperties prop; |
|
289 cxPropertiesInitDefault(&prop); |
|
290 enum cx_properties_status result; |
|
291 cxstring key; |
|
292 cxstring value; |
|
293 |
|
294 size_t key_len = 512; |
|
295 char *long_key = (char*)malloc(key_len); |
|
296 memset(long_key, 'a', 70); |
|
297 memset(long_key + 70, 'b', 242); |
|
298 memset(long_key + 312, 'c', 200); |
|
299 |
|
300 size_t value_len = 2048; |
|
301 char *long_value = (char*)malloc(value_len); |
|
302 memset(long_value, 'x', 1024); |
|
303 memset(long_value+1024, 'y', 1024); |
|
304 |
|
305 CX_TEST_DO { |
|
306 cxPropertiesFill(&prop, long_key, 10); |
|
307 result = cxPropertiesNext(&prop, &key, &value); |
|
308 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
309 |
|
310 cxPropertiesFill(&prop, long_key + 10, 202); |
|
311 result = cxPropertiesNext(&prop, &key, &value); |
|
312 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
313 |
|
314 cxPropertiesFill(&prop, long_key + 212, 200); |
|
315 result = cxPropertiesNext(&prop, &key, &value); |
|
316 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
317 |
|
318 cxPropertiesFill(&prop, long_key + 412, 100); |
|
319 result = cxPropertiesNext(&prop, &key, &value); |
|
320 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
321 |
|
322 const char *str = " = "; |
|
323 cxPropertiesFill(&prop, str, strlen(str)); |
|
324 result = cxPropertiesNext(&prop, &key, &value); |
|
325 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
326 |
|
327 cxPropertiesFill(&prop, long_value, 512); |
|
328 result = cxPropertiesNext(&prop, &key, &value); |
|
329 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
330 |
|
331 cxPropertiesFill(&prop, long_value + 512, 1024); |
|
332 result = cxPropertiesNext(&prop, &key, &value); |
|
333 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
334 |
|
335 cxPropertiesFill(&prop, long_value + 1536, 512); |
|
336 result = cxPropertiesNext(&prop, &key, &value); |
|
337 CX_TEST_ASSERT(result == CX_PROPERTIES_INCOMPLETE_DATA); |
|
338 |
|
339 str = "\n#comment\nkey = value\n"; |
|
340 cxPropertiesFill(&prop, str, strlen(str)); |
|
341 result = cxPropertiesNext(&prop, &key, &value); |
|
342 cxstring k = cx_strn(long_key, key_len); |
|
343 cxstring v = cx_strn(long_value, value_len); |
|
344 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
345 CX_TEST_ASSERT(0 == cx_strcmp(key, k)); |
|
346 CX_TEST_ASSERT(0 == cx_strcmp(value, v)); |
|
347 |
|
348 result = cxPropertiesNext(&prop, &key, &value); |
|
349 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_ERROR); |
|
350 CX_TEST_ASSERT(0 == cx_strcmp(key, cx_str("key"))); |
|
351 CX_TEST_ASSERT(0 == cx_strcmp(value, cx_str("value"))); |
|
352 |
|
353 result = cxPropertiesNext(&prop, &key, &value); |
|
354 CX_TEST_ASSERT(result == CX_PROPERTIES_NO_DATA); |
|
355 |
|
356 CX_TEST_ASSERT(prop.buf != NULL); |
|
357 CX_TEST_ASSERT(prop.buf_capacity > 0); |
|
358 CX_TEST_ASSERT(prop.buf_size == 0); |
|
359 cxPropertiesDestroy(&prop); |
|
360 |
|
361 CX_TEST_ASSERT(prop.buf == NULL); |
|
362 CX_TEST_ASSERT(prop.buf_capacity == 0); |
|
363 CX_TEST_ASSERT(prop.buf_size == 0); |
|
364 } |
|
365 |
|
366 free(long_key); |
|
367 free(long_value); |
|
368 } |
|
369 |
|
370 CxTestSuite *cx_test_suite_properties(void) { |
|
371 CxTestSuite *suite = cx_test_suite_new("properties"); |
|
372 |
|
373 cx_test_register(suite, test_cx_properties_init); |
|
374 cx_test_register(suite, test_cx_properties_next); |
|
375 cx_test_register(suite, test_cx_properties_next_multi); |
|
376 cx_test_register(suite, test_cx_properties_next_part); |
|
377 cx_test_register(suite, test_ucx_properties_next_long_lines); |
|
378 |
|
379 return suite; |
|
380 } |