/* INI LIBRARY Unit test for the configuration file validators API. Copyright (C) Michal Zidek 2016 INI Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. INI Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with INI Library. If not, see . */ #include #include #include #include #include #include #include #include /* #define TRACE_LEVEL 7 */ #define TRACE_HOME #include "trace.h" #include "ini_configobj.h" #define TEST_DIR_PATH "" #define TEST_RULES_FILE TEST_DIR_PATH"test_rules.ini" static void create_rules_from_str(const char *rules, struct ini_cfgobj **_rules_obj) { FILE *file; size_t written; int ret; /* We want to test actual reading from file using * ini_rules_read_from_file, so we create the file here */ file = fopen(TEST_RULES_FILE, "w"); fail_if(file == NULL, "fopen() failed: %s", strerror(errno)); written = fwrite(rules, 1, strlen(rules), file); fail_unless(written == strlen(rules)); /* allow reading */ ret = chmod(TEST_RULES_FILE, 0664); fail_unless(ret == 0, "chmod() failed: %s", strerror(errno)); fclose(file); ret = ini_rules_read_from_file(TEST_RULES_FILE, _rules_obj); fail_unless(ret == 0, "read_rules_from_file() failed: %s", strerror(ret)); } static struct ini_cfgobj *get_ini_config_from_str(char input_data[], size_t input_data_len) { struct ini_cfgobj *in_cfg; struct ini_cfgfile *file_ctx; int ret; ret = ini_config_create(&in_cfg); fail_unless(ret == EOK, "Failed to create config. Error %d.\n", ret); ret = ini_config_file_from_mem(input_data, input_data_len, &file_ctx); fail_unless(ret == EOK, "Failed to load config. Error %d.\n", ret); ret = ini_config_parse(file_ctx, INI_STOP_ON_NONE, INI_MV1S_ALLOW, 0, in_cfg); fail_unless(ret == EOK, "Failed to parse config. Error %d.\n", ret); ini_config_file_destroy(file_ctx); return in_cfg; } START_TEST(test_ini_errobj) { struct ini_errobj *errobj; int ret; const char TEST_MSG1[] = "Test message one."; const char TEST_MSG2[] = "Test message two."; const char TEST_MSG3[] = "Test message three."; ret = ini_errobj_create(NULL); fail_unless(ret == EINVAL, "ini_errobj_create(NULL) failed with wrong error [%s]", strerror(ret)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); /* We just created the errobj, it should be empty */ fail_unless(ini_errobj_no_more_msgs(errobj)); /* Now add three messages, after adding each message, * check if the errobj has correct content. */ ret = ini_errobj_add_msg(errobj, TEST_MSG1); fail_if(ret != 0, "ini_errobj_add_msg() failed: %s", strerror(ret)); fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG1, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG1 was not found."); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ret = ini_errobj_add_msg(errobj, TEST_MSG2); fail_if(ret != 0, "ini_errobj_add_msg() failed: %s", strerror(ret)); ini_errobj_reset(errobj); /* strart from first message */ fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG1, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG1 was not found."); ini_errobj_next(errobj); fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG2, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG2 was not found."); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ret = ini_errobj_add_msg(errobj, TEST_MSG3); fail_if(ret != 0, "ini_errobj_add_msg() failed: %s", strerror(ret)); ini_errobj_reset(errobj); /* strart from first message */ fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG1, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG1 was not found."); ini_errobj_next(errobj); fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG2, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG2 was not found."); ini_errobj_next(errobj); fail_if(ini_errobj_no_more_msgs(errobj)); ret = strcmp(TEST_MSG3, ini_errobj_get_msg(errobj)); fail_if(ret != 0, "TEST_MSG3 was not found."); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); } END_TEST START_TEST(test_ini_noerror) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; char input_rules[] = "[rule/always_succeed]\n" "validator = ini_dummy_noerror\n"; char input_cfg[] = "[section]\n" "# Content of this file should not matter\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_error) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; const char *errmsg; char input_rules[] = "[rule/generate_error]\n" "validator = ini_dummy_error\n"; char input_wrong_rule[] = "[rule/generate_error]\n" "valid = ini_dummy_error\n"; char input_cfg[] = "[section]\n" "# Content of this file should not matter\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate exactly one error */ fail_if(ini_errobj_no_more_msgs(errobj)); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/generate_error]: Error"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); /* test rule with missing validator */ create_rules_from_str(input_wrong_rule, &rules_obj); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate exactly one error */ fail_if(ini_errobj_no_more_msgs(errobj)); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/generate_error' has no validator."); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); ini_config_destroy(cfg_obj); } END_TEST START_TEST(test_unknown_validator) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; char input_rules[] = "[rule/always_succeed]\n" "validator = nonexistent_validator\n"; char input_cfg[] = "[section]\n" "# Content of this file should not matter\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate exactly one error */ fail_if(ini_errobj_no_more_msgs(errobj)); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST static int custom_noerror(const char *rule_name, struct ini_cfgobj *rules_obj, struct ini_cfgobj *config_obj, struct ini_errobj *errobj, void **data) { return 0; } static int custom_error(const char *rule_name, struct ini_cfgobj *rules_obj, struct ini_cfgobj *config_obj, struct ini_errobj *errobj, void **data) { return ini_errobj_add_msg(errobj, "Error"); } START_TEST(test_custom_noerror) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; struct ini_validator *noerror[] = { &(struct ini_validator){ "custom_noerror", custom_noerror, NULL }, NULL }; struct ini_validator *missing_name[] = { &(struct ini_validator){ NULL, custom_noerror, NULL }, &(struct ini_validator){ "custom_noerror", custom_noerror, NULL }, NULL }; char input_rules[] = "[rule/custom_succeed]\n" "validator = custom_noerror\n"; char input_cfg[] = "[section]\n" "# Content of this file should not matter\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); /* Pass the custom validator to ini_rules_check() */ ret = ini_rules_check(rules_obj, cfg_obj, noerror, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate no errors */ fail_unless(ini_errobj_no_more_msgs(errobj)); /* Pass wrong external validator to ini_rules_check() */ /* It should be skipped */ ret = ini_rules_check(rules_obj, cfg_obj, missing_name, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate no errors */ fail_unless(ini_errobj_no_more_msgs(errobj), "%s", ini_errobj_get_msg(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_custom_error) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; struct ini_validator *error[] = { &(struct ini_validator){ "custom_error", custom_error, NULL }, NULL }; struct ini_validator *missing_function[] = { &(struct ini_validator){ "custom_noerror", NULL, NULL }, NULL }; const char *errmsg; char input_rules[] = "[rule/custom_error]\n" "validator = custom_error\n"; char input_cfg[] = "[section]\n" "# Content of this file should not matter\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); /* Pass the custom validator to ini_rules_check() */ ret = ini_rules_check(rules_obj, cfg_obj, error, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate one error */ fail_if(ini_errobj_no_more_msgs(errobj)); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/custom_error]: Error"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); /* Pass the custom validator to ini_rules_check() */ ret = ini_rules_check(rules_obj, cfg_obj, missing_function, errobj); /* Should generate one error for missing validator */ fail_if(ini_errobj_no_more_msgs(errobj)); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/custom_error' uses unknown validator " "'custom_error'."); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); ini_config_destroy(cfg_obj); } END_TEST START_TEST(test_ini_allowed_options_ok) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/options_for_foo]\n" "validator = ini_allowed_options\n" "section_re = ^foo$\n" "option = bar\n" "option = baz\n"; /* Should check only foo section, other sections are * irrelevant and can contain any option */ char input_cfg[] = "[foo]\n" "bar = 0\n" "baz = 0\n" "[oof]\n" "opt1 = 1\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate no errors */ fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_options_no_section) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; size_t num_err; const char *errmsg; /* Ommit section_re to generate error */ char input_rules[] = "[rule/options_for_foo]\n" "validator = ini_allowed_options\n" /* "section_re = ^foo$\n" */ "option = bar\n" "option = baz\n"; /* section_re without value */ char input_rules2[] = "[rule/options_for_foo]\n" "validator = ini_allowed_options\n" "section_re = \n" "option = bar\n" "option = baz\n"; /* Make 4 typos */ char input_cfg[] = "[foo]\n" "bar = 0\n" "baz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors (one from rules_check and one * from the validator itself) */ fail_if(ini_errobj_no_more_msgs(errobj)); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/options_for_foo' returned error code '22'"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/options_for_foo]: Validator misses 'section_re' " "parameter"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); /* the second test with missing value for section_re */ create_rules_from_str(input_rules2, &rules_obj); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors (one from rules_check and one * from the validator itself) */ fail_if(ini_errobj_no_more_msgs(errobj)); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/options_for_foo' returned error code '22'"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/options_for_foo]: Validator misses 'section_re' " "parameter"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); ini_config_destroy(cfg_obj); } END_TEST START_TEST(test_ini_allowed_options_wrong_regex) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; size_t num_err; const char *errmsg; /* Ommit section_re to generate error */ char input_rules[] = "[rule/options_for_foo]\n" "validator = ini_allowed_options\n" "section_re = ^foo[$\n" "option = bar\n" "option = baz\n"; /* Make 4 typos */ char input_cfg[] = "[foo]\n" "bar = 0\n" "baz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors (one from rules_check and one * from the validator itself) */ fail_if(ini_errobj_no_more_msgs(errobj)); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/options_for_foo' returned error code '22'"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); /* Different versions of libc produce slightly different error strings * in this case. For simplicity compare against all of them. */ errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/options_for_foo]: Cannot compile regular expression " "from option 'section_re'. " "Error: 'Unmatched [ or [^'"); if (ret != 0) { ret = strcmp(errmsg, "[rule/options_for_foo]: Cannot compile regular " "expression from option 'section_re'. " "Error: 'brackets ([ ]) not balanced'"); } if (ret != 0) { ret = strcmp(errmsg, "[rule/options_for_foo]: Cannot compile regular " "expression from option 'section_re'. " "Error: 'Unmatched [, [^, [:, [., or [='"); } fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_options_typos) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; size_t num_err; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/options_for_foo]\n" "validator = ini_allowed_options\n" "section_re = ^foo$\n" "option = bar\n" "option = baz\n"; /* Make 4 typos */ char input_cfg[] = "[foo]\n" "br = 0\n" "bra = 0\n" "abr = 0\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 4 errors */ fail_if(ini_errobj_no_more_msgs(errobj)); num_err = ini_errobj_count(errobj); fail_unless(num_err == 4, "Expected 4 errors, got %d", num_err); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_str_ok) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "section = foo\n" "section = bar\n"; /* Make 4 typos */ char input_cfg[] = "[foo]\n" "br = 0\n" "bra = 0\n" "[bar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 0 errors */ fail_unless(ini_errobj_no_more_msgs(errobj), "Unexpected errors found: [%s]", ini_errobj_get_msg(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_str_typos) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int num_err; int ret; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "section = foo\n" "section = bar\n"; /* Make 4 typos */ char input_cfg[] = "[fooo]\n" "br = 0\n" "bra = 0\n" "[baar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors */ fail_if(ini_errobj_no_more_msgs(errobj), "Expected 2 errors but none found"); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_str_insensitive) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; int i; /* Only bar and baz are allowed for foo section */ char input_rules_template[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "case_insensitive = %s\n" "section = foo\n" "section = bar\n"; char input_rules[sizeof(input_rules_template) + 10]; const char *case_insensitive_values[] = { "yes", "Yes", "true", "True", "1", NULL }; /* Make 4 typos */ char input_cfg[] = "[FOo]\n" "br = 0\n" "bra = 0\n" "[baR]\n" "abz = 0\n"; cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); for (i = 0; case_insensitive_values[i] != NULL; i++) { sprintf(input_rules, input_rules_template, case_insensitive_values[i]); create_rules_from_str(input_rules, &rules_obj); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed for case_insensitive = %s: %s", case_insensitive_values[i], strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed for case_insensitive = %s: %s", case_insensitive_values[i], strerror(ret)); /* Should generate 0 errors */ fail_unless(ini_errobj_no_more_msgs(errobj), "Unexpected errors found for case_insensitive = %s: [%s]", case_insensitive_values[i], ini_errobj_get_msg(errobj)); ini_errobj_destroy(&errobj); ini_rules_destroy(rules_obj); } ini_config_destroy(cfg_obj); } END_TEST START_TEST(test_ini_allowed_sections_re_ok) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "section_re = ^foo*$\n" "section_re = bar\n"; char input_cfg[] = "[foooooooooooo]\n" "br = 0\n" "bra = 0\n" "[my_bar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 0 errors */ fail_unless(ini_errobj_no_more_msgs(errobj), "Unexpected errors found"); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_re_typos) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int num_err; int ret; char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "section_re = ^foo*$\n" "section_re = bar\n"; /* Make 4 typos */ char input_cfg[] = "[fooooooOooooo]\n" "br = 0\n" "bra = 0\n" "[my_bra]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors */ fail_if(ini_errobj_no_more_msgs(errobj), "Expected 2 errors but none found"); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_re_insensitive) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int ret; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "case_insensitive = yes\n" "section_re = ^foo*$\n" "section_re = bar\n"; /* Make 4 typos */ char input_cfg[] = "[FOoOoOoOoOOOOooo]\n" "br = 0\n" "bra = 0\n" "[my_Bar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 0 errors */ fail_unless(ini_errobj_no_more_msgs(errobj), "Unexpected errors found"); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_missing_section) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int num_err; int ret; const char *errmsg; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n"; /* Make 4 typos */ char input_cfg[] = "[fooo]\n" "br = 0\n" "bra = 0\n" "[baar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 1 errors */ fail_if(ini_errobj_no_more_msgs(errobj), "Expected 1 errors but none found"); num_err = ini_errobj_count(errobj); fail_unless(num_err == 1, "Expected 1 errors, got %d", num_err); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/section_list]: No allowed sections specified. " "Use 'section = default' to allow only default section"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST START_TEST(test_ini_allowed_sections_wrong_regex) { struct ini_cfgobj *rules_obj; struct ini_cfgobj *cfg_obj; struct ini_errobj *errobj; int num_err; int ret; const char *errmsg; /* Only bar and baz are allowed for foo section */ char input_rules[] = "[rule/section_list]\n" "validator = ini_allowed_sections\n" "section_re = ^foo\\(*$\n"; /* Make 4 typos */ char input_cfg[] = "[fooo]\n" "br = 0\n" "bra = 0\n" "[baar]\n" "abz = 0\n"; create_rules_from_str(input_rules, &rules_obj); cfg_obj = get_ini_config_from_str(input_cfg, sizeof(input_cfg)); ret = ini_errobj_create(&errobj); fail_unless(ret == 0, "ini_errobj_create() failed: %s", strerror(ret)); ret = ini_rules_check(rules_obj, cfg_obj, NULL, errobj); fail_unless(ret == 0, "ini_rules_check() failed: %s", strerror(ret)); /* Should generate 2 errors */ fail_if(ini_errobj_no_more_msgs(errobj), "Expected 2 errors but none found"); num_err = ini_errobj_count(errobj); fail_unless(num_err == 2, "Expected 2 errors, got %d", num_err); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "Rule 'rule/section_list' returned error code '22'"); fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); errmsg = ini_errobj_get_msg(errobj); ret = strcmp(errmsg, "[rule/section_list]: Validator failed to use regex " "[^foo\\(*$]:[Unmatched ( or \\(]"); if (ret !=0) { ret = strcmp(errmsg, "[rule/section_list]: Validator failed to use regex " "[^foo\\(*$]:[parentheses not balanced]"); } fail_unless(ret == 0, "Got msg: [%s]", errmsg); ini_errobj_next(errobj); fail_unless(ini_errobj_no_more_msgs(errobj)); ini_errobj_destroy(&errobj); ini_config_destroy(cfg_obj); ini_rules_destroy(rules_obj); } END_TEST static Suite *ini_validators_utils_suite(void) { Suite *s = suite_create("ini_validators"); TCase *tc_infrastructure = tcase_create("infrastructure"); tcase_add_test(tc_infrastructure, test_ini_errobj); tcase_add_test(tc_infrastructure, test_ini_noerror); tcase_add_test(tc_infrastructure, test_ini_error); tcase_add_test(tc_infrastructure, test_unknown_validator); tcase_add_test(tc_infrastructure, test_custom_noerror); tcase_add_test(tc_infrastructure, test_custom_error); TCase *tc_allowed_options = tcase_create("ini_allowed_options"); tcase_add_test(tc_allowed_options, test_ini_allowed_options_ok); tcase_add_test(tc_allowed_options, test_ini_allowed_options_no_section); tcase_add_test(tc_allowed_options, test_ini_allowed_options_wrong_regex); tcase_add_test(tc_allowed_options, test_ini_allowed_options_typos); TCase *tc_allowed_sections = tcase_create("ini_allowed_sections"); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_str_ok); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_str_typos); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_str_insensitive); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_re_ok); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_re_typos); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_re_insensitive); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_missing_section); tcase_add_test(tc_allowed_sections, test_ini_allowed_sections_wrong_regex); suite_add_tcase(s, tc_infrastructure); suite_add_tcase(s, tc_allowed_options); suite_add_tcase(s, tc_allowed_sections); return s; } int main(void) { int number_failed; Suite *s = ini_validators_utils_suite(); SRunner *sr = srunner_create(s); /* If CK_VERBOSITY is set, use that, otherwise it defaults to CK_NORMAL */ srunner_run_all(sr, CK_ENV); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }