1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
|
/*
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 "config.h"
#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"
#include "ini_config_priv.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;
}
|