summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--Makefile7
-rw-r--r--examples/conf.pom5
-rw-r--r--examples/read_conf.c2
-rw-r--r--pom.c24
-rw-r--r--tests/interpretation.c163
-rw-r--r--tests/main.c1
-rw-r--r--tests/test.h1
8 files changed, 192 insertions, 16 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f14c696..0972a9b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,10 @@ endif()
add_library(pom-static STATIC pom.c)
add_library(pom SHARED pom.c)
-add_executable(tests tests/errors.c tests/location.c tests/parsing.c tests/main.c)
+add_executable(tests tests/errors.c tests/location.c tests/parsing.c tests/interpretation.c tests/main.c)
target_include_directories(tests PRIVATE .)
target_link_libraries(tests pom-static)
+add_executable(read_conf examples/read_conf.c)
+target_include_directories(read_conf PRIVATE .)
+target_link_libraries(read_conf pom-static)
diff --git a/Makefile b/Makefile
index 8d8474b..65a7055 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,9 @@ BUILD_DIR ?= $(PROFILE)
__build:
mkdir -p $(BUILD_DIR)
P=`pwd` && cd $(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE=$(PROFILE) -DCMAKE_EXPORT_COMPILE_COMMANDS=1 $$P
- make -j16 -C $(BUILD_DIR)
+ $(MAKE) -C $(BUILD_DIR)
-.PHONY: __build
+test: __build
+ valgrind --exit-on-first-error=yes --error-exitcode=1 $(BUILD_DIR)/tests
+
+.PHONY: __build test
diff --git a/examples/conf.pom b/examples/conf.pom
index 016179a..6011308 100644
--- a/examples/conf.pom
+++ b/examples/conf.pom
@@ -1,4 +1 @@
-things = "ten,
- great\,things,
- i\\really,
- love
+things = \,,,76
diff --git a/examples/read_conf.c b/examples/read_conf.c
index acc3eba..d96e190 100644
--- a/examples/read_conf.c
+++ b/examples/read_conf.c
@@ -2,7 +2,7 @@
#include <string.h>
#include <inttypes.h>
-#include "pom.h"
+#include <pom.h>
int main(int argc, char **argv) {
pom_error *error;
diff --git a/pom.c b/pom.c
index 2ca3ffa..772df4a 100644
--- a/pom.c
+++ b/pom.c
@@ -632,7 +632,7 @@ check_if_key_is_valid(struct parser *parser, const char *key) {
bad = (0xfc001bffffffffffU >> c) & 1;
} else if (c < 128) {
// bitmask of disallowed ASCII characters 64-127
- bad = (0xfc0000017c000001U >> c) & 1;
+ bad = (0xf800000178000001 >> (c - 64)) & 1;
}
if (bad) {
parser_error(parser, ERROR_KEY_INVALID_CHAR, c, c);
@@ -1113,6 +1113,13 @@ static void libc_free(void *udata, void *ptr) {
free(ptr);
}
+static void fix_settings(const pom_settings *in, pom_settings *out) {
+ *out = in ? *in : (pom_settings){0};
+ if (!out->calloc) out->calloc = libc_calloc;
+ if (!out->realloc) out->realloc = libc_realloc;
+ if (!out->free) out->free = libc_free;
+}
+
// make single pom_error out of all of parser's errors.
static pom_error *parser_make_error(struct parser *parser) {
// shouldn't realistically overflow given that we cut off at 1000 errors
@@ -1160,10 +1167,7 @@ pom_load(const pom_settings *psettings, const char *filename,
if (!read_func)
fatal_error("%s called with NULL read function", __func__);
pom_settings settings_data = {0}, *settings = &settings_data;
- if (psettings) settings_data = *psettings;
- if (!settings->calloc) settings->calloc = libc_calloc;
- if (!settings->realloc) settings->realloc = libc_realloc;
- if (!settings->free) settings->free = libc_free;
+ fix_settings(psettings, &settings_data);
if (error) *error = NULL;
// Start by allocating out-of-memory error, so we can just return
// it if we run out of memory.
@@ -1239,11 +1243,13 @@ read_file(void *file, char *buf, size_t len) {
}
pom_conf *
-pom_load_file(const pom_settings *settings, const char *filename, FILE *file, pom_error **error) {
+pom_load_file(const pom_settings *psettings, const char *filename, FILE *file, pom_error **error) {
if (!filename)
fatal_error("%s called with NULL file name", __func__);
if (!file)
fatal_error("%s called with NULL file", __func__);
+ pom_settings settings_data = {0}, *settings = &settings_data;
+ fix_settings(psettings, &settings_data);
pom_conf *conf = pom_load(settings, filename, read_file, file, error);
if (ferror(file)) {
if (error) {
@@ -1257,9 +1263,11 @@ pom_load_file(const pom_settings *settings, const char *filename, FILE *file, po
}
pom_conf *
-pom_load_path(const pom_settings *settings, const char *path, pom_error **error) {
+pom_load_path(const pom_settings *psettings, const char *path, pom_error **error) {
if (!path)
fatal_error("%s called with NULL file name", __func__);
+ pom_settings settings_data = {0}, *settings = &settings_data;
+ fix_settings(psettings, &settings_data);
FILE *fp = fopen(path, "rb");
if (!fp) {
if (error) {
@@ -1869,7 +1877,7 @@ pom_conf_get_list(const pom_conf *conf, const char *key) {
char *strings = (char *)(list + max_entries+1);
const char *p = value_str;
while (true) {
- while (strchr(" \t\n", *p)) p++;
+ while (*p == ' ' || *p == '\t' || *p == '\n') p++;
const char *end = p;
char *out = *entry++ = strings;
for (; *end; end++) {
diff --git a/tests/interpretation.c b/tests/interpretation.c
new file mode 100644
index 0000000..bdae290
--- /dev/null
+++ b/tests/interpretation.c
@@ -0,0 +1,163 @@
+#include "test.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+void test_interpretation(void) {
+ char **listing = list_dir("interpretation", ".pom");
+ if (!listing)
+ return;
+ for (size_t l = 0; listing[l]; l++) {
+ const char *conf_path = listing[l];
+ printf("Testing %s...\n",conf_path);
+ pom_error *error;
+ pom_conf *conf = pom_load_path(NULL, conf_path, &error);
+ if (error) {
+ test_fail("Error parsing %s: %s.", conf_path,
+ pom_error_to_string(error));
+ free(error);
+ continue;
+ }
+ const pom_conf *bad = pom_conf_section(conf, "bad");
+ const pom_conf *good = pom_conf_section(conf, "good");
+ const char *key = NULL;
+ pom_key_iter *iter = NULL;
+ if (strstr(conf_path, "uint.pom")) {
+ uint64_t val, val2;
+ while ((key = pom_conf_next_key(bad, &iter))) {
+ if (!pom_conf_get_uint(bad, key, &val)) {
+ test_fail("Key %s should be rejected as a uint", key);
+ }
+ }
+ while ((key = pom_conf_next_key(good, &iter))) {
+ const pom_conf *section = pom_conf_section(good, key);
+ if (pom_conf_get_uint(section, "a", &val)) {
+ test_fail("Key %s.a should be parsed as a uint", key);
+ continue;
+ }
+ if (pom_conf_get_uint(section, "b", &val2)) {
+ test_fail("Key %s.a should be parsed as a uint", key);
+ continue;
+ }
+ if (val != val2) {
+ test_fail("Keys %s.a and %s.b disagree:\n"
+ "a: %" PRIu64 "\n"
+ "b: %" PRIu64, key, key, val, val2);
+ }
+ }
+ } else if (strstr(conf_path, "int.pom")) {
+ int64_t val, val2;
+ while ((key = pom_conf_next_key(bad, &iter))) {
+ if (!pom_conf_get_int(bad, key, &val)) {
+ test_fail("Key %s should be rejected as an int", key);
+ }
+ }
+ while ((key = pom_conf_next_key(good, &iter))) {
+ const pom_conf *section = pom_conf_section(good, key);
+ if (pom_conf_get_int(section, "a", &val)) {
+ test_fail("Key %s.a should be parsed as an int", key);
+ continue;
+ }
+ if (pom_conf_get_int(section, "b", &val2)) {
+ test_fail("Key %s.a should be parsed as an int", key);
+ continue;
+ }
+ if (val != val2) {
+ test_fail("Keys %s.a and %s.b disagree:\n"
+ "a: %" PRId64 "\n"
+ "b: %" PRId64, key, key, val, val2);
+ }
+ }
+ } else if (strstr(conf_path, "float.pom")) {
+ double val, val2;
+ while ((key = pom_conf_next_key(bad, &iter))) {
+ if (!pom_conf_get_float(bad, key, &val)) {
+ test_fail("Key %s should be rejected as a float", key);
+ }
+ }
+ while ((key = pom_conf_next_key(good, &iter))) {
+ const pom_conf *section = pom_conf_section(good, key);
+ if (pom_conf_get_float(section, "a", &val)) {
+ test_fail("Key %s.a should be parsed as a float", key);
+ continue;
+ }
+ if (pom_conf_get_float(section, "b", &val2)) {
+ test_fail("Key %s.a should be parsed as a float", key);
+ continue;
+ }
+ if (val != val2) {
+ test_fail("Keys %s.a and %s.b disagree:\n"
+ "a: %f\n"
+ "b: %f", key, key, val, val2);
+ }
+ }
+ } else if (strstr(conf_path, "bool.pom")) {
+ bool val, val2;
+ while ((key = pom_conf_next_key(bad, &iter))) {
+ if (!pom_conf_get_bool(bad, key, &val)) {
+ test_fail("Key %s should be rejected as a bool", key);
+ }
+ }
+ while ((key = pom_conf_next_key(good, &iter))) {
+ const pom_conf *section = pom_conf_section(good, key);
+ if (pom_conf_get_bool(section, "a", &val)) {
+ test_fail("Key %s.a should be parsed as a bool", key);
+ continue;
+ }
+ if (pom_conf_get_bool(section, "b", &val2)) {
+ test_fail("Key %s.a should be parsed as a bool", key);
+ continue;
+ }
+ if (val != val2) {
+ test_fail("Keys %s.a and %s.b disagree:\n"
+ "a: %d\n"
+ "b: %d", key, key, val, val2);
+ }
+ }
+ } else if (strstr(conf_path, "list.pom")) {
+ // TODO
+ while ((key = pom_conf_next_key(conf, &iter))) {
+ const pom_conf *section = pom_conf_section(conf, key);
+ char **list = pom_conf_get_list(section, "list");
+ if (!list) {
+ test_fail("%s should have a subkey 'list'", key);
+ continue;
+ }
+ const char *sep = pom_conf_get(section, "sep");
+ if (!sep) {
+ test_fail("%s should have a subkey 'sep'", key);
+ free(list);
+ continue;
+ }
+ size_t list_count, sep_count = 0;
+ for (list_count = 0; list[list_count]; list_count++);
+ for (size_t i = 0; sep[i]; i++)
+ sep_count += sep[i] == ';';
+ if (list_count != sep_count) {
+ test_fail("List %s should have %zu elements (got %zu)", key, sep_count, list_count);
+ free(list);
+ continue;
+ }
+ for (size_t i = 0; list[i]; i++) {
+ const char *item = list[i];
+ size_t sep_len = strcspn(sep, ";");
+ if (strlen(item) != sep_len
+ || memcmp(item, sep, sep_len) != 0) {
+ test_fail("List %s element %zu is wrong:\n"
+ "expected: %.*s\n"
+ " got: %s\n",
+ key, i, (int)sep_len, sep, item);
+ }
+ sep += sep_len + 1;
+ }
+ free(list);
+ }
+ } else {
+ test_fail("Unrecognized test: %s",conf_path);
+ }
+ pom_conf_free(conf);
+ }
+ free_listing(listing);
+// pom_conf *conf = pom_load_path("../tests");
+}
diff --git a/tests/main.c b/tests/main.c
index c34a79d..791fdc7 100644
--- a/tests/main.c
+++ b/tests/main.c
@@ -65,6 +65,7 @@ int main(int argc, char **argv) {
test_parsing();
test_errors();
test_location();
+ test_interpretation();
if (any_failure) {
fprintf(stderr, "\x1b[1m\x1b[91mSome tests failed.\x1b[0m\n");
return EXIT_FAILURE;
diff --git a/tests/test.h b/tests/test.h
index 59807d1..c6109fb 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -16,5 +16,6 @@ void test_fail(PRINTF_FORMAT_STRING const char *, ...) ATTRIBUTE_PRINTF(1, 2);
void test_parsing(void);
void test_errors(void);
void test_location(void);
+void test_interpretation(void);
char **list_dir(const char *dir, const char *suffix);
void free_listing(char **listing);