1 /*
2 * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20 * \file
21 * Tests for user option processing
22 */
23
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <check.h>
31
32 #include "utils/errors.h"
33 #include "utils/log.h"
34 #include "utils/nsoption.h"
35
36 #ifndef TESTROOT
37 #define TESTROOT "/tmp"
38 #endif
39
40 const char *test_choices_path = "test/data/Choices";
41 const char *test_choices_short_path = "test/data/Choices-short";
42 const char *test_choices_all_path = "test/data/Choices-all";
43 const char *test_choices_full_path = "test/data/Choices-full";
44 const char *test_choices_missing_path = "test/data/Choices-missing";
45
46 /* Stubs */
nslog_set_filter_by_options()47 nserror nslog_set_filter_by_options() { return NSERROR_OK; }
48
49 /**
50 * generate test output filenames
51 */
testnam(char * out)52 static char *testnam(char *out)
53 {
54 static int count = 0;
55 static char name[64];
56 int pid;
57 pid=getpid();
58 snprintf(name, 64, TESTROOT"/nsoptiontest%d%d", pid, count);
59 count++;
60 return name;
61 }
62
gui_options_init_defaults(struct nsoption_s * defaults)63 static nserror gui_options_init_defaults(struct nsoption_s *defaults)
64 {
65 /* Set defaults for absent option strings */
66 nsoption_setnull_charp(ca_bundle, strdup("NetSurf:Resources.ca-bundle"));
67 nsoption_setnull_charp(cookie_file, strdup("NetSurf:Cookies"));
68 nsoption_setnull_charp(cookie_jar, strdup("Cookies"));
69
70 if (nsoption_charp(ca_bundle) == NULL ||
71 nsoption_charp(cookie_file) == NULL ||
72 nsoption_charp(cookie_jar) == NULL) {
73 return NSERROR_BAD_PARAMETER;
74 }
75 return NSERROR_OK;
76 }
77
78
79 /**
80 * compare two files contents
81 */
cmp(const char * f1,const char * f2)82 static int cmp(const char *f1, const char *f2)
83 {
84 int res = 0;
85 FILE *fp1;
86 FILE *fp2;
87 int ch1;
88 int ch2;
89
90 fp1 = fopen(f1, "r");
91 if (fp1 == NULL) {
92 return -1;
93 }
94 fp2 = fopen(f2, "r");
95 if (fp2 == NULL) {
96 fclose(fp1);
97 return -1;
98 }
99
100 while (res == 0) {
101 ch1 = fgetc(fp1);
102 ch2 = fgetc(fp2);
103
104 if (ch1 != ch2) {
105 res = 1;
106 }
107
108 if (ch1 == EOF) {
109 break;
110 }
111 }
112
113 fclose(fp1);
114 fclose(fp2);
115 return res;
116 }
117
118 /** option create fixture */
nsoption_create(void)119 static void nsoption_create(void)
120 {
121 nserror res;
122
123 res = nsoption_init(NULL, NULL, NULL);
124 ck_assert_int_eq(res, NSERROR_OK);
125 }
126
127 /** option create fixture for format case */
nsoption_format_create(void)128 static void nsoption_format_create(void)
129 {
130 nserror res;
131
132 res = nsoption_init(NULL, NULL, NULL);
133 ck_assert_int_eq(res, NSERROR_OK);
134
135 /* read from file */
136 res = nsoption_read(test_choices_path, NULL);
137 ck_assert_int_eq(res, NSERROR_OK);
138 }
139
140 /** option teardown fixture */
nsoption_teardown(void)141 static void nsoption_teardown(void)
142 {
143 nserror res;
144
145 res = nsoption_finalise(NULL, NULL);
146 ck_assert_int_eq(res, NSERROR_OK);
147 }
148
149
150 /**
151 * Test full options session from start to finish
152 */
START_TEST(nsoption_session_test)153 START_TEST(nsoption_session_test)
154 {
155 nserror res;
156 int argc = 2;
157 char arg1[] = "nsoption";
158 char arg2[] = "--http_proxy_host=fooo";
159 char *argv[] = { arg1, arg2, NULL};
160 char *outnam;
161
162 res = nsoption_init(gui_options_init_defaults, NULL, NULL);
163 ck_assert_int_eq(res, NSERROR_OK);
164
165 /* read from file */
166 res = nsoption_read(test_choices_path, NULL);
167 ck_assert_int_eq(res, NSERROR_OK);
168
169 /* overlay commandline */
170 res = nsoption_commandline(&argc, &argv[0], NULL);
171 ck_assert_int_eq(res, NSERROR_OK);
172
173 /* change a string option */
174 nsoption_set_charp(http_proxy_host, strdup("bar"));
175
176 /* change an uint option */
177 nsoption_set_uint(disc_cache_size, 42);
178
179 /* change a colour */
180 nsoption_set_colour(sys_colour_ActiveBorder, 0x00d0000d);
181
182 /* write options out */
183 outnam = testnam(NULL);
184 res = nsoption_write(outnam, NULL, NULL);
185 ck_assert_int_eq(res, NSERROR_OK);
186
187 /* check for the correct answer */
188 ck_assert_int_eq(cmp(outnam, test_choices_full_path), 0);
189
190 /* remove test output */
191 unlink(outnam);
192
193 res = nsoption_finalise(NULL, NULL);
194 ck_assert_int_eq(res, NSERROR_OK);
195
196 }
197 END_TEST
198
nsoption_session_case_create(void)199 static TCase *nsoption_session_case_create(void)
200 {
201 TCase *tc;
202 tc = tcase_create("Full session");
203
204 tcase_add_test(tc, nsoption_session_test);
205
206 return tc;
207 }
208
209
210
211 struct format_test_vec_s {
212 int opt_idx;
213 const char *res_html;
214 const char *res_text;
215 };
216
217 struct format_test_vec_s format_test_vec[] = {
218 {
219 NSOPTION_http_proxy,
220 "<tr><th>http_proxy</th><td>boolean</td><td>default</td><td>false</td></tr>",
221 "http_proxy:0"
222 },
223 {
224 NSOPTION_enable_javascript,
225 "<tr><th>enable_javascript</th><td>boolean</td><td>user</td><td>true</td></tr>",
226 "enable_javascript:1"
227 },
228 {
229 NSOPTION_http_proxy_port,
230 "<tr><th>http_proxy_port</th><td>integer</td><td>default</td><td>8080</td></tr>",
231 "http_proxy_port:8080"
232 },
233 {
234 NSOPTION_http_proxy_host,
235 "<tr><th>http_proxy_host</th><td>string</td><td>default</td><td><span class=\"null-content\">NULL</span></td></tr>",
236 "http_proxy_host:"
237 },
238 {
239 NSOPTION_cookie_file,
240 "<tr><th>cookie_file</th><td>string</td><td>user</td><td>/home/vince/.netsurf/Cookies</td></tr>",
241 "cookie_file:/home/vince/.netsurf/Cookies"
242 },
243 {
244 NSOPTION_disc_cache_size,
245 "<tr><th>disc_cache_size</th><td>unsigned integer</td><td>default</td><td>1073741824</td></tr>",
246 "disc_cache_size:1073741824"
247 },
248 {
249 NSOPTION_sys_colour_ActiveBorder,
250 "<tr><th>sys_colour_ActiveBorder</th><td>colour</td><td>default</td><td><span style=\"font-family:Monospace;\">#D3D3D3</span> <span style=\"background-color: #d3d3d3; border: 1px solid #000000; display: inline-block; width: 1em; height: 1em;\"></span></td></tr>",
251 "sys_colour_ActiveBorder:d3d3d3"
252 },
253 };
254
255 /**
256 * Test formatting of html output
257 */
START_TEST(nsoption_format_html_test)258 START_TEST(nsoption_format_html_test)
259 {
260 int ret;
261 char buffer[1024];
262 struct format_test_vec_s *tst = &format_test_vec[_i];
263
264 ret = nsoption_snoptionf(buffer, sizeof buffer, tst->opt_idx,
265 "<tr><th>%k</th><td>%t</td><td>%p</td><td>%V</td></tr>");
266 ck_assert_int_gt(ret, 0);
267 ck_assert_str_eq(buffer, tst->res_html);
268 }
269 END_TEST
270
271 /**
272 * Test formatting of text output
273 */
START_TEST(nsoption_format_text_test)274 START_TEST(nsoption_format_text_test)
275 {
276 int ret;
277 char buffer[1024];
278 struct format_test_vec_s *tst = &format_test_vec[_i];
279
280 ret = nsoption_snoptionf(buffer, sizeof buffer, tst->opt_idx,
281 "%k:%v");
282 ck_assert_int_gt(ret, 0);
283 ck_assert_str_eq(buffer, tst->res_text);
284 }
285 END_TEST
286
287 #define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
288
nsoption_format_case_create(void)289 static TCase *nsoption_format_case_create(void)
290 {
291 TCase *tc;
292 tc = tcase_create("Formatted output");
293
294 /* ensure options are initialised and finalised for every test */
295 tcase_add_unchecked_fixture(tc,
296 nsoption_format_create,
297 nsoption_teardown);
298
299 tcase_add_loop_test(tc,
300 nsoption_format_html_test,
301 0, NELEMS(format_test_vec));
302
303 tcase_add_loop_test(tc,
304 nsoption_format_text_test,
305 0, NELEMS(format_test_vec));
306
307 return tc;
308 }
309
310
311 /**
312 * Test dumping option file
313 */
START_TEST(nsoption_dump_test)314 START_TEST(nsoption_dump_test)
315 {
316 nserror res;
317 char *outnam;
318 FILE *fp;
319
320 res = nsoption_read(test_choices_path, NULL);
321 ck_assert_int_eq(res, NSERROR_OK);
322
323 outnam = testnam(NULL);
324
325 fp = fopen(outnam, "w");
326 res = nsoption_dump(fp, NULL);
327 fclose(fp);
328
329 ck_assert_int_eq(res, NSERROR_OK);
330
331 ck_assert_int_eq(cmp(outnam, test_choices_all_path), 0);
332
333 unlink(outnam);
334 }
335 END_TEST
336
337 /**
338 * Test writing option file
339 */
START_TEST(nsoption_write_test)340 START_TEST(nsoption_write_test)
341 {
342 nserror res;
343 char *outnam;
344
345 res = nsoption_read(test_choices_path, NULL);
346 ck_assert_int_eq(res, NSERROR_OK);
347
348 outnam = testnam(NULL);
349
350 res = nsoption_write(outnam, NULL, NULL);
351 ck_assert_int_eq(res, NSERROR_OK);
352
353 ck_assert_int_eq(cmp(outnam, test_choices_short_path), 0);
354
355 unlink(outnam);
356 }
357 END_TEST
358
359 /**
360 * Test reading option file
361 */
START_TEST(nsoption_read_test)362 START_TEST(nsoption_read_test)
363 {
364 nserror res;
365 res = nsoption_read(test_choices_path, NULL);
366 ck_assert_int_eq(res, NSERROR_OK);
367
368 ck_assert(nsoption_charp(homepage_url) != NULL);
369 ck_assert_str_eq(nsoption_charp(homepage_url), "about:welcome");
370 }
371 END_TEST
372
373
374 /**
375 * Test reading missing option file
376 */
START_TEST(nsoption_read_missing_test)377 START_TEST(nsoption_read_missing_test)
378 {
379 nserror res;
380 res = nsoption_read(test_choices_missing_path, NULL);
381 ck_assert_int_eq(res, NSERROR_NOT_FOUND);
382 }
383 END_TEST
384
385 /**
386 * Test commandline string value setting
387 */
START_TEST(nsoption_commandline_test)388 START_TEST(nsoption_commandline_test)
389 {
390 nserror res;
391 int argc = 4;
392 char arg1[] = "nsoption";
393 char arg2[] = "--http_proxy_host=fooo";
394 char arg3[] = "--http_proxy_port";
395 char arg4[] = "not-option";
396 char *argv[] = { arg1, arg2, arg3, arg4, NULL};
397
398 /* commandline */
399 res = nsoption_commandline(&argc, &argv[0], NULL);
400 ck_assert_int_eq(res, NSERROR_OK);
401
402 ck_assert(nsoption_charp(http_proxy_host) != NULL);
403 ck_assert_str_eq(nsoption_charp(http_proxy_host), "fooo");
404 }
405 END_TEST
406
nsoption_case_create(void)407 static TCase *nsoption_case_create(void)
408 {
409 TCase *tc;
410 tc = tcase_create("File operations");
411
412 /* ensure options are initialised and finalised for every test */
413 tcase_add_unchecked_fixture(tc,
414 nsoption_create,
415 nsoption_teardown);
416
417 tcase_add_test(tc, nsoption_commandline_test);
418 tcase_add_test(tc, nsoption_read_test);
419 tcase_add_test(tc, nsoption_read_missing_test);
420 tcase_add_test(tc, nsoption_write_test);
421 tcase_add_test(tc, nsoption_dump_test);
422
423 return tc;
424 }
425
426
427 /**
428 * Test finalisation without init
429 */
START_TEST(nsoption_api_fini_no_init_test)430 START_TEST(nsoption_api_fini_no_init_test)
431 {
432 nserror res;
433
434 /* attempt to finalise without init */
435 res = nsoption_finalise(NULL, NULL);
436 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
437 }
438 END_TEST
439
440 /**
441 * Test read without path
442 */
START_TEST(nsoption_api_read_no_path_test)443 START_TEST(nsoption_api_read_no_path_test)
444 {
445 nserror res;
446
447 /* read with no path or init */
448 res = nsoption_read(NULL, NULL);
449 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
450 }
451 END_TEST
452
453 /**
454 * Test read without init
455 */
START_TEST(nsoption_api_read_no_init_test)456 START_TEST(nsoption_api_read_no_init_test)
457 {
458 nserror res;
459
460 /* read with path but no init */
461 res = nsoption_read(test_choices_path, NULL);
462 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
463 }
464 END_TEST
465
466 /**
467 * Test write without path
468 */
START_TEST(nsoption_api_write_no_path_test)469 START_TEST(nsoption_api_write_no_path_test)
470 {
471 nserror res;
472
473 /* write with no path or init */
474 res = nsoption_write(NULL, NULL, NULL);
475 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
476 }
477 END_TEST
478
479 /**
480 * Test write without init
481 */
START_TEST(nsoption_api_write_no_init_test)482 START_TEST(nsoption_api_write_no_init_test)
483 {
484 nserror res;
485
486 /* write with path but no init */
487 res = nsoption_write(test_choices_path, NULL, NULL);
488 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
489
490 }
491 END_TEST
492
493 /**
494 * Test dump without path
495 */
START_TEST(nsoption_api_dump_no_path_test)496 START_TEST(nsoption_api_dump_no_path_test)
497 {
498 nserror res;
499
500 /* write with no path or init */
501 res = nsoption_dump(NULL, NULL);
502 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
503 }
504 END_TEST
505
506 /**
507 * Test dump without init
508 */
START_TEST(nsoption_api_dump_no_init_test)509 START_TEST(nsoption_api_dump_no_init_test)
510 {
511 nserror res;
512 FILE *outf;
513
514 outf = tmpfile();
515 ck_assert(outf != NULL);
516
517 /* write with path but no init */
518 res = nsoption_dump(outf, NULL);
519 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
520
521 fclose(outf);
522 }
523 END_TEST
524
525 /**
526 * Test commandline without args
527 */
START_TEST(nsoption_api_commandline_no_args_test)528 START_TEST(nsoption_api_commandline_no_args_test)
529 {
530 nserror res;
531 int argc = 2;
532 char arg1[] = "nsoption";
533 char arg2[] = "--http_proxy_host=fooo";
534 char *argv[] = { arg1, arg2, NULL};
535
536 /* commandline with no argument count or init */
537 res = nsoption_commandline(NULL, &argv[0], NULL);
538 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
539
540 /* commandline with no argument vector or init */
541 res = nsoption_commandline(&argc, NULL, NULL);
542 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
543 }
544 END_TEST
545
546 /**
547 * Test commandline without init
548 */
START_TEST(nsoption_api_commandline_no_init_test)549 START_TEST(nsoption_api_commandline_no_init_test)
550 {
551 nserror res;
552 int argc = 2;
553 char arg1[] = "nsoption";
554 char arg2[] = "--http_proxy_host=fooo";
555 char *argv[] = { arg1, arg2, NULL};
556
557 /* write with path but no init */
558 res = nsoption_commandline(&argc, &argv[0], NULL);
559 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
560 }
561 END_TEST
562
563
564 /**
565 * Test default initialisation and repeated finalisation
566 */
START_TEST(nsoption_api_fini_twice_test)567 START_TEST(nsoption_api_fini_twice_test)
568 {
569 nserror res;
570 res = nsoption_init(NULL, NULL, NULL);
571 ck_assert_int_eq(res, NSERROR_OK);
572
573 res = nsoption_finalise(NULL, NULL);
574 ck_assert_int_eq(res, NSERROR_OK);
575
576 res = nsoption_finalise(NULL, NULL);
577 ck_assert_int_eq(res, NSERROR_BAD_PARAMETER);
578 }
579 END_TEST
580
581
582 /**
583 * Test default initialisation and finalisation
584 */
START_TEST(nsoption_api_init_def_test)585 START_TEST(nsoption_api_init_def_test)
586 {
587 nserror res;
588 res = nsoption_init(NULL, NULL, NULL);
589 ck_assert_int_eq(res, NSERROR_OK);
590
591 res = nsoption_finalise(NULL, NULL);
592 ck_assert_int_eq(res, NSERROR_OK);
593 }
594 END_TEST
595
596 /**
597 * Test default initialisation and finalisation with parameters
598 */
START_TEST(nsoption_api_init_param_test)599 START_TEST(nsoption_api_init_param_test)
600 {
601 nserror res;
602 res = nsoption_init(NULL, &nsoptions, &nsoptions_default);
603 ck_assert_int_eq(res, NSERROR_OK);
604
605 res = nsoption_finalise(nsoptions, nsoptions_default);
606 ck_assert_int_eq(res, NSERROR_OK);
607 }
608 END_TEST
609
failing_init_cb(struct nsoption_s * defaults)610 static nserror failing_init_cb(struct nsoption_s *defaults)
611 {
612 return NSERROR_INIT_FAILED;
613 }
614
615 /**
616 * Test default initialisation with failing callback
617 */
START_TEST(nsoption_api_init_failcb_test)618 START_TEST(nsoption_api_init_failcb_test)
619 {
620 nserror res;
621 res = nsoption_init(failing_init_cb, NULL, NULL);
622 ck_assert_int_eq(res, NSERROR_INIT_FAILED);
623 }
624 END_TEST
625
626 /**
627 * Test snoptionf format
628 */
START_TEST(nsoption_api_snoptionf_badfmt_test)629 START_TEST(nsoption_api_snoptionf_badfmt_test)
630 {
631 int ret;
632 ret = nsoption_snoptionf(NULL, 0, -1, NULL);
633 ck_assert_int_eq(ret, -1);
634 }
635 END_TEST
636
637 /**
638 * Test snoptionf range
639 */
START_TEST(nsoption_api_snoptionf_param_test)640 START_TEST(nsoption_api_snoptionf_param_test)
641 {
642 int ret;
643
644 ret = nsoption_snoptionf(NULL, 0, NSOPTION_LISTEND, "");
645 ck_assert_int_eq(ret, -1);
646 }
647 END_TEST
648
649 /**
650 * Test snoptionf with no initialisation
651 */
START_TEST(nsoption_api_snoptionf_no_init_test)652 START_TEST(nsoption_api_snoptionf_no_init_test)
653 {
654 int ret;
655 ret = nsoption_snoptionf(NULL, 0, 0, "");
656 ck_assert_int_eq(ret, -1);
657 }
658 END_TEST
659
660
nsoption_api_case_create(void)661 static TCase *nsoption_api_case_create(void)
662 {
663 TCase *tc;
664 tc = tcase_create("API checks");
665
666 tcase_add_test(tc, nsoption_api_fini_no_init_test);
667 tcase_add_test(tc, nsoption_api_read_no_path_test);
668 tcase_add_test(tc, nsoption_api_read_no_init_test);
669 tcase_add_test(tc, nsoption_api_write_no_path_test);
670 tcase_add_test(tc, nsoption_api_write_no_init_test);
671 tcase_add_test(tc, nsoption_api_dump_no_path_test);
672 tcase_add_test(tc, nsoption_api_dump_no_init_test);
673 tcase_add_test(tc, nsoption_api_commandline_no_args_test);
674 tcase_add_test(tc, nsoption_api_commandline_no_init_test);
675 tcase_add_test(tc, nsoption_api_init_def_test);
676 tcase_add_test(tc, nsoption_api_fini_twice_test);
677 tcase_add_test(tc, nsoption_api_init_param_test);
678 tcase_add_test(tc, nsoption_api_init_failcb_test);
679 tcase_add_test(tc, nsoption_api_snoptionf_no_init_test);
680 tcase_add_test(tc, nsoption_api_snoptionf_badfmt_test);
681 tcase_add_test(tc, nsoption_api_snoptionf_param_test);
682
683 return tc;
684 }
685
686
nsoption_suite_create(void)687 static Suite *nsoption_suite_create(void)
688 {
689 Suite *s;
690 s = suite_create("User options");
691
692 suite_add_tcase(s, nsoption_api_case_create());
693 suite_add_tcase(s, nsoption_case_create());
694 suite_add_tcase(s, nsoption_format_case_create());
695 suite_add_tcase(s, nsoption_session_case_create());
696
697 return s;
698 }
699
main(int argc,char ** argv)700 int main(int argc, char **argv)
701 {
702 int number_failed;
703 SRunner *sr;
704
705 sr = srunner_create(nsoption_suite_create());
706
707 srunner_run_all(sr, CK_ENV);
708
709 number_failed = srunner_ntests_failed(sr);
710 srunner_free(sr);
711
712 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
713 }
714