]>
Commit | Line | Data |
---|---|---|
031e5cce SM |
1 | // SPDX-License-Identifier: BSD-2-Clause-Patent |
2 | /* | |
3 | * test-csv.c - test our csv parser | |
4 | */ | |
5 | ||
6 | #ifndef SHIM_UNIT_TEST | |
7 | #define SHIM_UNIT_TEST | |
8 | #endif | |
9 | #include "shim.h" | |
10 | ||
11 | #include <stdio.h> | |
12 | ||
13 | struct test_entry { | |
14 | size_t n_columns; | |
15 | char *columns[7]; | |
16 | }; | |
17 | ||
18 | int | |
19 | test_parse_csv_line_size_0(void) | |
20 | { | |
21 | char *s0 = ""; | |
22 | char *columns[] = { "a", "b", "c", "d" }; | |
23 | char *test_columns[] = { NULL, NULL, NULL, NULL }; | |
24 | size_t n_columns = 3; | |
25 | size_t i; | |
26 | ||
27 | test_columns[3] = columns[3]; | |
28 | ||
29 | parse_csv_line(s0, 0, &n_columns, (const char **)columns); | |
30 | ||
31 | assert_equal_return(s0[0], '\0', -1, "got %#hhx expected %#hhx\n"); | |
32 | assert_equal_return(n_columns, 0, -1, "got %#hhx expected %#hhx\n"); | |
33 | for (i = 0; i < 4; i++) { | |
34 | assert_equal_return(test_columns[i], columns[i], -1, | |
35 | "expected %p got %p for column %d\n", | |
36 | i); | |
37 | } | |
38 | return 0; | |
39 | } | |
40 | ||
41 | int | |
42 | test_parse_csv_line_size_1(void) | |
43 | { | |
44 | char *s0 = ""; | |
45 | char *columns[] = { "a", "b", "c", "d" }; | |
46 | char *test_columns[] = { "", NULL, NULL, NULL }; | |
47 | size_t n_columns = 3; | |
48 | size_t max = 1; | |
49 | size_t i; | |
50 | ||
51 | test_columns[3] = columns[3]; | |
52 | ||
53 | parse_csv_line(s0, max, &n_columns, (const char **)columns); | |
54 | ||
55 | assert_equal_return(s0[0], '\0', -1, "got %#hhx expected %#hhx\n"); | |
56 | assert_equal_return(n_columns, 1, -1, "got %#hhx expected %#hhx\n"); | |
57 | for (i = 0; i < 4; i++) { | |
58 | assert_equal_return(test_columns[i], columns[i], -1, | |
59 | "expected %p got %p for column %d\n", | |
60 | i); | |
61 | } | |
62 | return 0; | |
63 | } | |
64 | ||
65 | int | |
66 | test_parse_csv_line_comma_size_1(void) | |
67 | { | |
68 | char *s0; | |
69 | char *columns[] = { "a", "b", "c", "d" }; | |
70 | char *test_columns[] = { "", NULL, NULL, "d" }; | |
71 | size_t n_columns = 3; | |
72 | size_t max = 1; | |
73 | size_t i; | |
74 | ||
75 | /* | |
76 | * For reasons unknown, when I do this the normal way with: | |
77 | * char *s0 = ","; | |
78 | * gcc is putting it in .rodata, | |
79 | * *** AND combining it with the "," from delims from parse_csv_line***. | |
80 | */ | |
81 | s0 = alloca(2); | |
82 | s0[0] = ','; | |
83 | s0[1] = '\0'; | |
84 | ||
85 | parse_csv_line(s0, max, &n_columns, (const char **)columns); | |
86 | ||
87 | assert_equal_return(s0[0], '\0', -1, "got %#hhx expected %#hhx\n"); | |
88 | assert_equal_return(n_columns, 1, -1, "got %#hhx expected %#hhx\n"); | |
89 | // for (i = 0; i < 4; i++) { | |
90 | // printf("columns[%d]:%p:\"%s\"\n", i, columns[i], columns[i]); | |
91 | // } | |
92 | for (i = 0; i < 1; i++) { | |
93 | assert_equal_return(strcmp(test_columns[i], columns[i]), 0, -1, | |
94 | "expected %d got %d for column %d\n", i); | |
95 | } | |
96 | for (i = 1; i < 3; i++) { | |
97 | assert_equal_return(test_columns[i], columns[i], -1, | |
98 | "expected %p got %p for column %d\n", | |
99 | i); | |
100 | } | |
101 | for (i = 3; i < 4; i++) { | |
102 | assert_equal_return(strcmp(test_columns[i], columns[i]), 0, -1, | |
103 | "expected %d got %d for column %d\n", i); | |
104 | } | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | int | |
110 | test_parse_csv_line_comma_size_2(void) | |
111 | { | |
112 | char *s0; | |
113 | char *columns[] = { "a", "b", "c", "d" }; | |
114 | char *test_columns[] = { "", "", NULL, "d" }; | |
115 | size_t n_columns = 3; | |
116 | size_t max = 2; | |
117 | size_t i; | |
118 | ||
119 | /* | |
120 | * For reasons unknown, when I do this the normal way with: | |
121 | * char *s0 = ","; | |
122 | * gcc is putting it in .rodata, | |
123 | * *** AND combining it with the "," from delims from parse_csv_line***. | |
124 | */ | |
125 | s0 = alloca(2); | |
126 | s0[0] = ','; | |
127 | s0[1] = '\0'; | |
128 | ||
129 | parse_csv_line(s0, max, &n_columns, (const char **)columns); | |
130 | ||
131 | assert_equal_return(s0[0], '\0', -1, "got %#hhx expected %#hhx\n"); | |
132 | assert_equal_return(n_columns, 2, -1, "got %#hhx expected %#hhx\n"); | |
133 | for (i = 0; i < 2; i++) { | |
134 | assert_equal_return(strcmp(test_columns[i], columns[i]), 0, -1, | |
135 | "expected %d got %d for column %d\n", i); | |
136 | } | |
137 | for (i = 2; i < 3; i++) { | |
138 | assert_equal_return(test_columns[i], columns[i], -1, | |
139 | "expected %p got %p for column %d\n", | |
140 | i); | |
141 | } | |
142 | for (i = 3; i < 4; i++) { | |
143 | assert_equal_return(strcmp(test_columns[i], columns[i]), 0, -1, | |
144 | "expected %d got %d for column %d\n", i); | |
145 | } | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | int | |
151 | test_csv_0(void) | |
152 | { | |
153 | char csv[] = | |
154 | "\000\000\000" | |
155 | "a,b,c,d,e,f,g,h\n" | |
156 | "a,b,c\n" | |
157 | "\n" | |
158 | "\n" | |
159 | "a,b,c,d,e,f,g,h\n" | |
160 | "a,b,c"; | |
161 | struct test_entry test_entries[]= { | |
162 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
163 | { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } }, | |
164 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
165 | { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } }, | |
166 | }; | |
167 | list_t entry_list; | |
168 | size_t i; | |
169 | char *current, *end; | |
170 | list_t *pos = NULL; | |
171 | EFI_STATUS efi_status; | |
172 | ||
173 | INIT_LIST_HEAD(&entry_list); | |
174 | assert_equal_return(list_size(&entry_list), 0, -1, | |
175 | "got %d expected %d\n"); | |
176 | ||
177 | memcpy(csv, (char [])UTF8_BOM, UTF8_BOM_SIZE); | |
178 | ||
179 | current = csv; | |
180 | end = csv + sizeof(csv) - 1; | |
181 | ||
182 | efi_status = parse_csv_data(current, end, 7, &entry_list); | |
183 | assert_equal_return(efi_status, EFI_SUCCESS, -1, "got %x expected %x\n"); | |
184 | ||
185 | i = 0; | |
186 | list_for_each(pos, &entry_list) { | |
187 | struct csv_row *csv_row; | |
188 | struct test_entry *test_entry = &test_entries[i++]; | |
189 | size_t j; | |
190 | ||
191 | assert_goto(i > 0 && i <= 4, fail, "got %d expected 0 to 4\n", i); | |
192 | ||
193 | csv_row = list_entry(pos, struct csv_row, list); | |
194 | ||
195 | assert_equal_goto(csv_row->n_columns, test_entry->n_columns, | |
196 | fail, "got %d expected %d\n"); | |
197 | for (j = 0; j < csv_row->n_columns; j++) { | |
198 | assert_equal_goto(strcmp(csv_row->columns[j], | |
199 | test_entry->columns[j]), 0, | |
200 | fail, "got %d expected %d\n"); | |
201 | } | |
202 | } | |
203 | ||
204 | assert_equal_return(list_size(&entry_list), 4, -1, | |
205 | "got %d expected %d\n"); | |
206 | free_csv_list(&entry_list); | |
207 | assert_equal_return(list_size(&entry_list), 0, -1, | |
208 | "got %d expected %d\n"); | |
209 | return 0; | |
210 | fail: | |
211 | free_csv_list(&entry_list); | |
212 | return -1; | |
213 | } | |
214 | ||
215 | int | |
216 | test_csv_1(void) | |
217 | { | |
218 | char csv[] = | |
219 | "a,b,c,d,e,f,g,h\n" | |
220 | "a,b,c\n" | |
221 | "\n" | |
222 | "\n" | |
223 | "a,b,c,d,e,f,g,h\n" | |
224 | "a,b,c"; | |
225 | struct test_entry test_entries[]= { | |
226 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
227 | { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } }, | |
228 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
229 | { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } }, | |
230 | }; | |
231 | list_t entry_list; | |
232 | size_t i; | |
233 | char *current, *end; | |
234 | list_t *pos = NULL; | |
235 | EFI_STATUS efi_status; | |
236 | ||
237 | INIT_LIST_HEAD(&entry_list); | |
238 | assert_equal_return(list_size(&entry_list), 0, -1, | |
239 | "got %d expected %d\n"); | |
240 | ||
241 | current = csv; | |
242 | end = csv + sizeof(csv) - 1; | |
243 | ||
244 | efi_status = parse_csv_data(current, end, 7, &entry_list); | |
245 | assert_equal_return(efi_status, EFI_SUCCESS, -1, "got %x expected %x\n"); | |
246 | ||
247 | i = 0; | |
248 | list_for_each(pos, &entry_list) { | |
249 | struct csv_row *csv_row; | |
250 | struct test_entry *test_entry = &test_entries[i++]; | |
251 | size_t j; | |
252 | ||
253 | assert_goto(i > 0 && i <= 4, fail, "got %d expected 0 to 4\n", i); | |
254 | ||
255 | csv_row = list_entry(pos, struct csv_row, list); | |
256 | ||
257 | assert_equal_goto(csv_row->n_columns, test_entry->n_columns, | |
258 | fail, "got %d expected %d\n"); | |
259 | for (j = 0; j < csv_row->n_columns; j++) { | |
260 | assert_equal_goto(strcmp(csv_row->columns[j], | |
261 | test_entry->columns[j]), 0, | |
262 | fail, "got %d expected %d\n"); | |
263 | } | |
264 | } | |
265 | ||
266 | assert_equal_return(list_size(&entry_list), 4, -1, | |
267 | "got %d expected %d\n"); | |
268 | free_csv_list(&entry_list); | |
269 | assert_equal_return(list_size(&entry_list), 0, -1, | |
270 | "got %d expected %d\n"); | |
271 | return 0; | |
272 | fail: | |
273 | free_csv_list(&entry_list); | |
274 | return -1; | |
275 | } | |
276 | ||
277 | int | |
278 | test_csv_2(void) | |
279 | { | |
280 | char csv[] = | |
281 | "\000\000\000" | |
282 | "a,b,c,d,e,f,g,h\n" | |
283 | ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,c\n" | |
284 | "\n" | |
285 | "\n" | |
286 | "a,b,c,d,e,f,g,h\n" | |
287 | "a,b,c"; | |
288 | struct test_entry test_entries[]= { | |
289 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
290 | { 7, { "", "", "", "", "", "", "" } }, | |
291 | { 7, { "a", "b", "c", "d", "e", "f", "g" } }, | |
292 | { 3, { "a", "b", "c", NULL, NULL, NULL, NULL } }, | |
293 | }; | |
294 | list_t entry_list; | |
295 | size_t i; | |
296 | char *current, *end; | |
297 | list_t *pos = NULL; | |
298 | EFI_STATUS efi_status; | |
299 | ||
300 | INIT_LIST_HEAD(&entry_list); | |
301 | assert_equal_return(list_size(&entry_list), 0, -1, | |
302 | "got %d expected %d\n"); | |
303 | ||
304 | memcpy(csv, (char [])UTF8_BOM, UTF8_BOM_SIZE); | |
305 | ||
306 | current = csv; | |
307 | end = csv + sizeof(csv) - 1; | |
308 | ||
309 | efi_status = parse_csv_data(current, end, 7, &entry_list); | |
310 | assert_equal_return(efi_status, EFI_SUCCESS, -1, "got %x expected %x\n"); | |
311 | ||
312 | i = 0; | |
313 | list_for_each(pos, &entry_list) { | |
314 | struct csv_row *csv_row; | |
315 | struct test_entry *test_entry = &test_entries[i++]; | |
316 | size_t j; | |
317 | ||
318 | assert_goto(i > 0 && i <= 7, fail, "got %d expected 0 to 7\n", i); | |
319 | csv_row = list_entry(pos, struct csv_row, list); | |
320 | ||
321 | assert_equal_goto(csv_row->n_columns, test_entry->n_columns, | |
322 | fail, "got %d expected %d\n"); | |
323 | for (j = 0; j < csv_row->n_columns; j++) { | |
324 | assert_equal_goto(strcmp(csv_row->columns[j], | |
325 | test_entry->columns[j]), 0, | |
326 | fail, "got %d expected %d\n"); | |
327 | } | |
328 | } | |
329 | ||
330 | free_csv_list(&entry_list); | |
331 | assert_equal_return(list_size(&entry_list), 0, -1, | |
332 | "got %d expected %d\n"); | |
333 | ||
334 | return 0; | |
335 | fail: | |
336 | free_csv_list(&entry_list); | |
337 | return -1; | |
338 | } | |
339 | ||
340 | int | |
341 | test_simple_sbat_csv(void) | |
342 | { | |
343 | char csv[] = | |
344 | "test1,1,SBAT test1,acme1,1,testURL1\n" | |
345 | "test2,2,SBAT test2,acme2,2,testURL2\n"; | |
346 | struct test_entry test_entries[]= { | |
347 | { 6, { "test1", "1", "SBAT test1", "acme1", "1", "testURL1" } }, | |
348 | { 6, { "test2", "2", "SBAT test2", "acme2", "2", "testURL2" } }, | |
349 | }; | |
350 | list_t entry_list; | |
351 | size_t i; | |
352 | char *current, *end; | |
353 | list_t *pos = NULL; | |
354 | EFI_STATUS efi_status; | |
355 | ||
356 | INIT_LIST_HEAD(&entry_list); | |
357 | assert_equal_return(list_size(&entry_list), 0, -1, | |
358 | "got %d expected %d\n"); | |
359 | ||
360 | current = csv; | |
361 | end = csv + sizeof(csv) - 1; | |
362 | ||
363 | efi_status = parse_csv_data(current, end, 6, &entry_list); | |
364 | assert_equal_return(efi_status, EFI_SUCCESS, -1, | |
365 | "got %d expected %d\n"); | |
366 | ||
367 | i = 0; | |
368 | list_for_each(pos, &entry_list) { | |
369 | struct csv_row *csv_row; | |
370 | struct test_entry *test_entry = &test_entries[i++]; | |
371 | size_t j; | |
372 | ||
373 | csv_row = list_entry(pos, struct csv_row, list); | |
374 | ||
375 | assert_equal_goto(csv_row->n_columns, test_entry->n_columns, | |
376 | fail, "got %d expected %d"); | |
377 | ||
378 | for (j = 0; j < csv_row->n_columns; j++) { | |
379 | assert_equal_goto(strcmp(csv_row->columns[j], | |
380 | test_entry->columns[j]), 0, | |
381 | fail, "got %d expected %d\n"); | |
382 | } | |
383 | } | |
384 | ||
385 | assert_equal_return(list_size(&entry_list), 2, -1, | |
386 | "got %d expected %d\n"); | |
387 | free_csv_list(&entry_list); | |
388 | assert_equal_return(list_size(&entry_list), 0, -1, | |
389 | "got %d expected %d\n"); | |
390 | ||
391 | return 0; | |
392 | fail: | |
393 | free_csv_list(&entry_list); | |
394 | return -1; | |
395 | ||
396 | } | |
397 | ||
398 | int | |
399 | test_csv_simple_fuzz(char *random_bin, size_t random_bin_len, | |
400 | bool assert_entries) | |
401 | { | |
402 | list_t entry_list; | |
403 | size_t i; | |
404 | char *current, *end; | |
405 | list_t *pos = NULL; | |
406 | EFI_STATUS efi_status; | |
407 | ||
408 | INIT_LIST_HEAD(&entry_list); | |
409 | assert_equal_return(list_size(&entry_list), 0, -1, | |
410 | "got %d expected %d\n"); | |
411 | ||
412 | current = &random_bin[0]; | |
413 | current = current + 1 - 1; | |
414 | end = current + random_bin_len - 1; | |
415 | *end = '\0'; | |
416 | ||
417 | efi_status = parse_csv_data(current, end, 7, &entry_list); | |
418 | assert_equal_return(efi_status, EFI_SUCCESS, -1, "expected %#x got %#x\n"); | |
419 | printf("parsed %zd entries\n", list_size(&entry_list)); | |
420 | if (assert_entries) | |
421 | assert_goto(list_size(&entry_list) > 0, fail, | |
422 | "expected >0 entries\n"); | |
423 | ||
424 | i = 0; | |
425 | list_for_each(pos, &entry_list) { | |
426 | struct csv_row *csv_row; | |
427 | ||
428 | csv_row = list_entry(pos, struct csv_row, list); | |
429 | dprint("row[%zd]: %zd columns\n", i, csv_row->n_columns); | |
430 | i++; | |
431 | } | |
432 | ||
433 | free_csv_list(&entry_list); | |
434 | assert_equal_return(list_size(&entry_list), 0, -1, | |
435 | "got %d expected %d\n"); | |
436 | ||
437 | return 0; | |
438 | fail: | |
439 | free_csv_list(&entry_list); | |
440 | return -1; | |
441 | } | |
442 | ||
443 | #include "test-random.h" | |
444 | ||
445 | int | |
446 | main(void) | |
447 | { | |
448 | int status = 0; | |
449 | size_t i, j; | |
450 | ||
451 | setbuf(stdout, NULL); | |
452 | test(test_parse_csv_line_size_0); | |
453 | test(test_parse_csv_line_size_1); | |
454 | test(test_parse_csv_line_comma_size_1); | |
455 | test(test_parse_csv_line_comma_size_2); | |
456 | test(test_csv_0); | |
457 | test(test_csv_1); | |
458 | test(test_csv_2); | |
459 | test(test_simple_sbat_csv); | |
460 | test(test_csv_simple_fuzz, random_bin, random_bin_len, false); | |
461 | for (i = 0; i < random_bin_len; i++) { | |
462 | j = i; | |
463 | while (random_bin[i] == '\0') | |
464 | random_bin[i] = j++; | |
465 | } | |
466 | test(test_csv_simple_fuzz, random_bin, random_bin_len, true); | |
467 | ||
468 | return status; | |
469 | } | |
470 | ||
471 | // vim:fenc=utf-8:tw=75:noet |