#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utime.h>
#include "profile.h"
static void
check(long code)
{
assert(code == 0);
}
static void
check_fail(long code, long expected)
{
assert(code == expected);
}
static void
write_file(const char *name, int nlines, ...)
{
FILE *f;
va_list ap;
int i;
(void)unlink(name);
f = fopen(name, "w");
assert(f != NULL);
va_start(ap, nlines);
for (i = 0; i < nlines; i++)
fprintf(f, "%s\n", va_arg(ap, char *));
va_end(ap);
fclose(f);
}
static void
test_iterate(void)
{
profile_t p;
void *iter;
const char *names[] = { "test section 1", "child_section", "child", NULL };
const char *values[] = { "slick", "harry", "john", NULL };
char *name, *value;
int i;
check(profile_init_path("test2.ini", &p));
check(profile_iterator_create(p, names, 0, &iter));
for (i = 0;; i++) {
check(profile_iterator(&iter, &name, &value));
if (name == NULL && value == NULL)
break;
assert(strcmp(name, names[2]) == 0);
assert(values[i] != NULL);
assert(strcmp(value, values[i]) == 0);
profile_release_string(name);
profile_release_string(value);
}
assert(values[i] == NULL);
profile_iterator_free(&iter);
check(profile_iterator_create(p, names, 0, &iter));
for (;;) {
check(profile_iterator(&iter, NULL, &value));
if (value == NULL)
break;
check(profile_update_relation(p, names, value, NULL));
profile_release_string(value);
}
profile_iterator_free(&iter);
(void)unlink("test3.ini");
profile_flush_to_file(p, "test3.ini");
profile_abandon(p);
check(profile_init_path("test3.ini", &p));
check(profile_iterator_create(p, names, 0, &iter));
check(profile_iterator(&iter, &name, &value));
assert(name == NULL && value == NULL);
profile_iterator_free(&iter);
profile_abandon(p);
}
static void
test_shared(void)
{
profile_t a, b;
struct utimbuf times;
system("cp test2.ini test3.ini");
check(profile_init_path("test3.ini", &a));
times.actime = time(NULL) + 2;
times.modtime = times.actime;
utime("test3.ini", ×);
check(profile_init_path("test3.ini", &b));
profile_release(b);
profile_release(a);
check(profile_init_path("test3.ini", &a));
profile_release(a);
}
static void
test_clear(void)
{
profile_t p;
const char *names[] = { "test section 1", "quux", NULL };
char **values, **dummy;
check(profile_init_path("test2.ini", &p));
check(profile_get_values(p, names, &values));
check(profile_clear_relation(p, names));
check_fail(profile_get_values(p, names, &dummy), PROF_NO_RELATION);
check(profile_add_relation(p, names, values[0]));
profile_free_list(values);
check(profile_get_values(p, names, &values));
assert(values[0] != NULL && values[1] == NULL);
profile_free_list(values);
profile_abandon(p);
}
static void
test_include(void)
{
profile_t p;
const char *names[] = { "test section 1", "bar", NULL };
char **values;
write_file("testinc.ini", 1, "include does-not-exist");
check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_FILE);
write_file("testinc.ini", 1, "includedir does-not-exist");
check_fail(profile_init_path("testinc.ini", &p), PROF_FAIL_INCLUDE_DIR);
write_file("testinc.ini", 1, "include test2.ini");
check(profile_init_path("testinc.ini", &p));
check(profile_get_values(p, names, &values));
assert(strcmp(values[0], "foo") == 0 && values[1] == NULL);
profile_free_list(values);
profile_release(p);
system("rm -rf test_include_dir");
system("mkdir test_include_dir");
system("cp test2.ini test_include_dir/a");
system("cp test2.ini test_include_dir/a~");
system("cp test2.ini test_include_dir/b.conf");
system("cp test2.ini test_include_dir/b.conf.rpmsave");
write_file("testinc.ini", 1, "includedir test_include_dir");
check(profile_init_path("testinc.ini", &p));
check(profile_get_values(p, names, &values));
assert(strcmp(values[0], "foo") == 0);
assert(strcmp(values[1], "foo") == 0);
assert(values[2] == NULL);
profile_free_list(values);
profile_release(p);
check(profile_init_path("test_include_dir", &p));
check(profile_get_values(p, names, &values));
assert(strcmp(values[0], "foo") == 0);
assert(strcmp(values[1], "foo") == 0);
assert(values[2] == NULL);
profile_free_list(values);
profile_release(p);
}
static void
test_independence(void)
{
profile_t p;
const char *names1[] = { "sec1", "var", "a", NULL };
const char *names2[] = { "sec2", "b", NULL };
const char *names3[] = { "sec1", "var", "c", NULL };
char **values;
write_file("testinc.ini", 6, "[sec1]", "var = {", "a = 1",
"include testinc2.ini", "c = 3", "}");
write_file("testinc2.ini", 2, "[sec2]", "b = 2");
check(profile_init_path("testinc.ini", &p));
check(profile_get_values(p, names1, &values));
assert(strcmp(values[0], "1") == 0 && values[1] == NULL);
profile_free_list(values);
check(profile_get_values(p, names2, &values));
assert(strcmp(values[0], "2") == 0 && values[1] == NULL);
profile_free_list(values);
check(profile_get_values(p, names3, &values));
assert(strcmp(values[0], "3") == 0 && values[1] == NULL);
profile_free_list(values);
profile_release(p);
}
static void
test_delete_section(void)
{
profile_t p;
const char *sect[] = { "test section 1", NULL };
const char *newrel[] = { "test section 1", "testkey", NULL };
const char *oldrel[] = { "test section 1", "child", NULL };
char **values;
check(profile_init_path("test2.ini", &p));
check(profile_rename_section(p, sect, NULL));
check(profile_add_relation(p, sect, NULL));
check(profile_add_relation(p, newrel, "6"));
check(profile_get_values(p, newrel, &values));
assert(strcmp(values[0], "6") == 0 && values[1] == NULL);
profile_free_list(values);
check_fail(profile_get_values(p, oldrel, &values), PROF_NO_RELATION);
profile_abandon(p);
}
static void
test_delete_clear_relation(void)
{
profile_t p;
const char *names[] = { "test section 1", "testkey", NULL };
check(profile_init_path("test2.ini", &p));
check(profile_add_relation(p, names, "1"));
check(profile_add_relation(p, names, "2"));
check(profile_update_relation(p, names, "2", NULL));
check(profile_clear_relation(p, names));
profile_abandon(p);
}
static void
test_delete_ordering(void)
{
profile_t p;
const char *names[] = { "test section 1", "testkey", NULL };
char **values;
check(profile_init_path("test2.ini", &p));
check(profile_add_relation(p, names, "1"));
check(profile_add_relation(p, names, "2"));
check(profile_add_relation(p, names, "3"));
check(profile_update_relation(p, names, "2", NULL));
check(profile_add_relation(p, names, "4"));
check(profile_get_values(p, names, &values));
assert(strcmp(values[0], "1") == 0);
assert(strcmp(values[1], "3") == 0);
assert(strcmp(values[2], "4") == 0);
assert(values[3] == NULL);
profile_free_list(values);
profile_abandon(p);
}
static void
test_flush_to_file(void)
{
profile_t p;
check(profile_init_path("test2.ini", &p));
unlink("test3.ini");
check(profile_flush_to_file(p, "test3.ini"));
profile_release(p);
profile_init_path("test2.ini", &p);
profile_release(p);
}
static void
test_merge_subsections(void)
{
profile_t p;
const char *n1[] = { "test section 2", "child_section2", "child", NULL };
const char *n2[] = { "test section 2", "child_section2", "chores", NULL };
char **values;
check(profile_init_path("test2.ini", &p));
check(profile_get_values(p, n1, &values));
assert(strcmp(values[0], "slick") == 0);
assert(strcmp(values[1], "harry") == 0);
assert(strcmp(values[2], "john\tb ") == 0);
assert(strcmp(values[3], "ron") == 0);
assert(values[4] == NULL);
profile_free_list(values);
check(profile_get_values(p, n2, &values));
assert(strcmp(values[0], "cleaning") == 0 && values[1] == NULL);
profile_free_list(values);
profile_release(p);
}
static void
test_empty(void)
{
profile_t p, p2;
const char *n1[] = { "section", NULL };
const char *n2[] = { "section", "var", NULL };
char **values;
check(profile_init(NULL, &p));
check(profile_add_relation(p, n1, NULL));
check(profile_add_relation(p, n2, "value"));
check(profile_flush(p));
check(profile_get_values(p, n2, &values));
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
profile_free_list(values);
check(profile_copy(p, &p2));
check(profile_get_values(p2, n2, &values));
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
profile_free_list(values);
profile_release(p2);
profile_flush_to_file(p, "test3.ini");
profile_release(p);
profile_init_path("test3.ini", &p);
check(profile_get_values(p, n2, &values));
assert(strcmp(values[0], "value") == 0 && values[1] == NULL);
profile_free_list(values);
profile_release(p);
}
int
main(void)
{
test_iterate();
test_shared();
test_clear();
test_include();
test_independence();
test_delete_section();
test_delete_clear_relation();
test_delete_ordering();
test_flush_to_file();
test_merge_subsections();
test_empty();
}