f8513f5719
Resolves: rhbz#1962772 sssd-team is added as a recipient
307 lines
10 KiB
C
307 lines
10 KiB
C
/*
|
|
INI LIBRARY
|
|
|
|
Check based unit test for ini parser.
|
|
|
|
Copyright (C) Michal Zidek <mzidek@redhat.com> 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <check.h>
|
|
|
|
/* #define TRACE_LEVEL 7 */
|
|
#define TRACE_HOME
|
|
#include "trace.h"
|
|
#include "ini_configobj.h"
|
|
|
|
#define TEST_DIR_PATH ""
|
|
|
|
START_TEST(test_ini_parse_non_kvp)
|
|
{
|
|
int ret;
|
|
struct ini_cfgobj *ini_cfg;
|
|
int value;
|
|
struct ini_cfgfile *file_ctx;
|
|
struct value_obj *vo;
|
|
char non_kvp_cfg[] =
|
|
"[section_before]\n"
|
|
"one = 1\n"
|
|
|
|
"[section_non_kvp]\n"
|
|
"two = 2\n"
|
|
"non_kvp\n"
|
|
"three = 3\n"
|
|
"=nonkvp\n"
|
|
|
|
"[section_after]\n"
|
|
"four = 4\n";
|
|
|
|
ret = ini_config_file_from_mem(non_kvp_cfg, strlen(non_kvp_cfg),
|
|
&file_ctx);
|
|
fail_unless(ret == EOK, "Failed to load config. Error %d.\n", ret);
|
|
|
|
/* First try without the INI_PARSE_IGNORE_NON_KVP. This should fail
|
|
* with error. */
|
|
ret = ini_config_create(&ini_cfg);
|
|
fail_unless(ret == EOK, "Failed to create config. Error %d.\n", ret);
|
|
ret = ini_config_parse(file_ctx, INI_STOP_ON_ERROR, INI_MV1S_ALLOW, 0,
|
|
ini_cfg);
|
|
fail_if(ret != 5, "Expected error was not found.\n");
|
|
|
|
ini_config_destroy(ini_cfg);
|
|
ini_config_file_destroy(file_ctx);
|
|
|
|
/* Now try with INI_PARSE_IGNORE_NON_KVP. We should have no errors
|
|
* and all the surounding configuration should be valid */
|
|
ret = ini_config_file_from_mem(non_kvp_cfg, strlen(non_kvp_cfg),
|
|
&file_ctx);
|
|
fail_unless(ret == EOK, "Failed to load config. Error %d.\n", ret);
|
|
ret = ini_config_create(&ini_cfg);
|
|
fail_unless(ret == EOK, "Failed to create config. Error %d.\n", ret);
|
|
ret = ini_config_parse(file_ctx, INI_STOP_ON_ERROR, INI_MV1S_ALLOW,
|
|
INI_PARSE_IGNORE_NON_KVP,
|
|
ini_cfg);
|
|
fail_unless(ret == EOK, "ini_config_parse returned %d\n", ret);
|
|
|
|
/* Now check if the surrounding configuration is OK */
|
|
/* section_before */
|
|
ret = ini_get_config_valueobj("section_before", "one", ini_cfg,
|
|
INI_GET_FIRST_VALUE, &vo);
|
|
fail_unless(ret == EOK, "ini_get_config_valueobj returned %d\n: %s", ret,
|
|
strerror(ret));
|
|
|
|
value = ini_get_int_config_value(vo, 1, -1, &ret);
|
|
fail_unless(ret == EOK, "ini_get_int_config_value returned %d\n: %s", ret,
|
|
strerror(ret));
|
|
|
|
fail_unless(ret == EOK);
|
|
fail_if(value != 1, "Expected value 1 got %d\n", value);
|
|
|
|
/* section_non_kvp */
|
|
ret = ini_get_config_valueobj("section_non_kvp", "two", ini_cfg,
|
|
INI_GET_FIRST_VALUE, &vo);
|
|
fail_unless(ret == EOK);
|
|
|
|
value = ini_get_int_config_value(vo, 1, -1, &ret);
|
|
fail_unless(ret == EOK);
|
|
fail_if(value != 2, "Expected value 2 got %d\n", value);
|
|
|
|
ret = ini_get_config_valueobj("section_non_kvp", "three", ini_cfg,
|
|
INI_GET_FIRST_VALUE, &vo);
|
|
fail_unless(ret == EOK);
|
|
|
|
value = ini_get_int_config_value(vo, 1, -1, &ret);
|
|
fail_unless(ret == EOK);
|
|
fail_if(value != 3, "Expected value 3 got %d\n", value);
|
|
|
|
/* section_after */
|
|
ret = ini_get_config_valueobj("section_after", "four", ini_cfg,
|
|
INI_GET_FIRST_VALUE, &vo);
|
|
fail_unless(ret == EOK);
|
|
|
|
value = ini_get_int_config_value(vo, 1, -1, &ret);
|
|
fail_unless(ret == EOK);
|
|
fail_if(value != 4, "Expected value 4 got %d\n", value);
|
|
|
|
ini_config_destroy(ini_cfg);
|
|
ini_config_file_destroy(file_ctx);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_ini_parse_section_key_conflict)
|
|
{
|
|
/*
|
|
* This tests the behavior of ini_config_parse to ensure correct handling
|
|
* of conflicts between sections and keys of the same name. There are
|
|
* three possibilities for conflict:
|
|
*
|
|
* 1. Inside a section, between the section name and a key name
|
|
* 2. Between a default-section key name and a section name
|
|
* 3. Between a key name in a different section and a section name
|
|
*
|
|
* In case (1), parsing finished without an error. However, when
|
|
* trying to select a value object inside a section, the returned
|
|
* object was an unchecked cast from the section's data, and not the
|
|
* attribute's data. In cases (2) and (3), the parser segfaulted while
|
|
* trying to merge a section with an attribute.
|
|
*/
|
|
|
|
char config1[] =
|
|
"[a]\n"
|
|
"a=a\n";
|
|
|
|
char config2[] =
|
|
"a=b\n"
|
|
"[a]\n"
|
|
"c=d\n";
|
|
|
|
char config3[] =
|
|
"[a]\n"
|
|
"b=c\n"
|
|
"[b]\n"
|
|
"a=d\n";
|
|
|
|
char *file_contents[] = {config1, config2, config3, NULL};
|
|
|
|
size_t iter;
|
|
|
|
struct ini_cfgobj *ini_config = NULL;
|
|
struct ini_cfgfile *file_ctx = NULL;
|
|
|
|
int ret;
|
|
int i;
|
|
int j;
|
|
|
|
char **sections = NULL;
|
|
int sections_count = 0;
|
|
int sections_error = 0;
|
|
|
|
char **attributes = NULL;
|
|
int attributes_count = 0;
|
|
int attributes_error = 0;
|
|
|
|
struct value_obj *val = NULL;
|
|
char *val_str = NULL;
|
|
|
|
for (iter = 0; file_contents[iter] != NULL; iter++) {
|
|
ret = ini_config_create(&ini_config);
|
|
fail_unless(ret == EOK, "Failed to create config. Error %d.\n", ret);
|
|
|
|
ret = ini_config_file_from_mem(file_contents[iter],
|
|
strlen(file_contents[iter]),
|
|
&file_ctx);
|
|
fail_unless(ret == EOK, "Failed to load file. Error %d.\n", ret);
|
|
|
|
ret = ini_config_parse(file_ctx, 1, 0, 0, ini_config);
|
|
fail_unless(ret == EOK, "Failed to parse file. Error %d.\n", ret);
|
|
|
|
sections = ini_get_section_list(ini_config, §ions_count,
|
|
§ions_error);
|
|
fail_unless(sections_error == EOK,
|
|
"Failed to get sections. Error %d.\n",
|
|
sections_error);
|
|
|
|
for (i = 0; i < sections_count; i++) {
|
|
attributes = ini_get_attribute_list(ini_config,
|
|
sections[i],
|
|
&attributes_count,
|
|
&attributes_error);
|
|
fail_unless(attributes_error == EOK,
|
|
"Failed to get attributes. Error %d.\n",
|
|
attributes_error);
|
|
|
|
for (j = 0; j < attributes_count; j++) {
|
|
ret = ini_get_config_valueobj(sections[i], attributes[j],
|
|
ini_config, 0, &val);
|
|
fail_unless(ret == EOK,
|
|
"Failed to get attribute. Error %d.\n",
|
|
ret);
|
|
|
|
val_str = ini_get_string_config_value(val, &ret);
|
|
fail_unless(ret == EOK,
|
|
"Failed to get attribute as string. Error %d.\n",
|
|
ret);
|
|
fail_unless(val_str != NULL,
|
|
"Failed to get attribute as string: was NULL.\n");
|
|
|
|
free(val_str);
|
|
}
|
|
|
|
ini_free_attribute_list(attributes);
|
|
}
|
|
|
|
ini_free_section_list(sections);
|
|
ini_config_file_destroy(file_ctx);
|
|
ini_config_destroy(ini_config);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
/* Maybe we should test even bigger values? */
|
|
#define VALUE_LEN 10000
|
|
/* The +100 is space for section name and key name. */
|
|
#define CFGBUF_LEN (VALUE_LEN + 100)
|
|
START_TEST(test_ini_long_value)
|
|
{
|
|
int ret;
|
|
struct ini_cfgobj *ini_cfg;
|
|
struct ini_cfgfile *file_ctx;
|
|
struct value_obj *vo;
|
|
char big_val_cfg[CFGBUF_LEN] = {0};
|
|
char value[VALUE_LEN] = {0};
|
|
char *value_got;
|
|
|
|
/* The value is just a lot of As ending with '\0'*/
|
|
memset(value, 'A', VALUE_LEN - 1);
|
|
|
|
/* Create config file */
|
|
ret = snprintf(big_val_cfg, CFGBUF_LEN, "[section]\nkey=%s", value);
|
|
|
|
ret = ini_config_file_from_mem(big_val_cfg, strlen(big_val_cfg),
|
|
&file_ctx);
|
|
fail_unless(ret == EOK, "Failed to load config. Error %d.\n", ret);
|
|
|
|
ret = ini_config_create(&ini_cfg);
|
|
fail_unless(ret == EOK, "Failed to create config. Error %d.\n", ret);
|
|
ret = ini_config_parse(file_ctx, INI_STOP_ON_ERROR, INI_MV1S_ALLOW, 0,
|
|
ini_cfg);
|
|
fail_if(ret != 0, "Failed to parse config. Error %d.\n", ret);
|
|
|
|
ret = ini_get_config_valueobj("section", "key", ini_cfg,
|
|
INI_GET_FIRST_VALUE, &vo);
|
|
fail_unless(ret == EOK, "ini_get_config_valueobj returned %d\n: %s", ret,
|
|
strerror(ret));
|
|
|
|
value_got = ini_get_string_config_value(vo, &ret);
|
|
fail_unless(ret == EOK, "ini_get_int_config_value returned %d\n: %s", ret,
|
|
strerror(ret));
|
|
|
|
fail_unless(strcmp(value, value_got) == 0, "Expected and found values differ!\n");
|
|
free(value_got);
|
|
ini_config_destroy(ini_cfg);
|
|
ini_config_file_destroy(file_ctx);
|
|
}
|
|
END_TEST
|
|
|
|
static Suite *ini_parse_suite(void)
|
|
{
|
|
Suite *s = suite_create("ini_parse_suite");
|
|
|
|
TCase *tc_parse = tcase_create("ini_parse");
|
|
tcase_add_test(tc_parse, test_ini_parse_non_kvp);
|
|
tcase_add_test(tc_parse, test_ini_parse_section_key_conflict);
|
|
tcase_add_test(tc_parse, test_ini_long_value);
|
|
|
|
suite_add_tcase(s, tc_parse);
|
|
|
|
return s;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int number_failed;
|
|
|
|
Suite *s = ini_parse_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;
|
|
}
|