diff options
-rw-r--r-- | errors.c | 3 | ||||
-rw-r--r-- | examples/conf.pom | 2 | ||||
-rw-r--r-- | meson.build | 3 | ||||
-rw-r--r-- | pom.c | 20 | ||||
-rw-r--r-- | tests/errors.c | 38 | ||||
-rw-r--r-- | tests/main.c | 13 | ||||
-rw-r--r-- | tests/parsing.c | 3 | ||||
-rw-r--r-- | tests/test.h | 1 |
8 files changed, 73 insertions, 10 deletions
@@ -21,6 +21,7 @@ enum error_id { ERROR_INVALID_LINE, ERROR_EMPTY_KEY, ERROR_REDEFINITION, + ERROR_NO_CLOSING_QUOTE, ERROR_COUNT, }; @@ -41,6 +42,7 @@ static const char *const error_messages_en[ERROR_COUNT] = { [ERROR_INVALID_LINE] = "Line should start with [ or contain =", [ERROR_EMPTY_KEY] = "Expected key name before =", [ERROR_REDEFINITION] = "Re-definition of %s (previously defined on line %" PRIu64 ")", + [ERROR_NO_CLOSING_QUOTE] = "Missing closing %c", }; @@ -61,6 +63,7 @@ static const char *const error_messages_fr[ERROR_COUNT] = { [ERROR_INVALID_LINE] = "Ligne devrait commençant par [ ou contenir =", [ERROR_EMPTY_KEY] = "Nom de clé devrait précéder =", [ERROR_REDEFINITION] = "Redéfinition de %s (définition précédente à ligne %" PRIu64 ")", + [ERROR_NO_CLOSING_QUOTE] = "Aucun %c fermant", }; static struct { diff --git a/examples/conf.pom b/examples/conf.pom index e66cde0..016179a 100644 --- a/examples/conf.pom +++ b/examples/conf.pom @@ -1,4 +1,4 @@ things = "ten, great\,things, i\\really, - love" + love diff --git a/meson.build b/meson.build index 5fafc31..766b96a 100644 --- a/meson.build +++ b/meson.build @@ -3,5 +3,6 @@ project('pom', 'c', default_options: ['c_std=c23']) library('pom', 'pom.c') static_lib = static_library('pom', 'pom.c') -tests = executable('tests', 'tests/main.c', 'tests/parsing.c', link_with: [static_lib]) +tests = executable('tests', 'tests/main.c', 'tests/parsing.c', + 'tests/errors.c', link_with: [static_lib]) test('tests', tests) @@ -690,15 +690,19 @@ parse_escape_sequence(struct parser *parser, const char **p_str) { case 'u': { if (*str++ != '{') goto invalid_sequence; uint_fast32_t value = 0; - char c; - while ((c = *str++) != '}') { + int i; + for (i = 0; i < 7; i++) { + char c = *str++; + if (c == '}') break; + if (i == 6) + goto invalid_sequence; // too long int digit = parse_hex_digit(c); if (digit < 0) goto invalid_sequence; value <<= 4; value |= digit; if (value > 0x10ffff) goto invalid_sequence; } - if (value >= 0xd800 && value <= 0xdfff) + if (value == 0 || (value >= 0xd800 && value <= 0xdfff)) goto invalid_sequence; // utf-16 surrogate if (value < 0x80) { // ASCII @@ -728,10 +732,18 @@ parse_escape_sequence(struct parser *parser, const char **p_str) { static void parse_quoted_value(struct parser *parser, const char *first_line) { + uint64_t start_line_number = parser->line_number; const char *line = first_line; char delimiter = *line++; assert(delimiter == '"' || delimiter == '`'); - while (!parser->eof && !parser->out_of_memory) { + while (!parser->out_of_memory) { + if (parser->eof) { + uint64_t prev = parser->line_number; + parser->line_number = start_line_number; + parser_error(parser, ERROR_NO_CLOSING_QUOTE, delimiter); + parser->line_number = prev; + break; + } char c; while ((c = *line++)) { if (c == delimiter) { diff --git a/tests/errors.c b/tests/errors.c new file mode 100644 index 0000000..8a255ab --- /dev/null +++ b/tests/errors.c @@ -0,0 +1,38 @@ +#include "test.h" + +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +void test_errors(const char *test_dir) { + char *errors_dir = malloc(strlen(test_dir) + 30); + sprintf(errors_dir, "%s/errors", test_dir); + DIR *dir = opendir(errors_dir); + if (!dir) { + test_fail("Couldn't open test directory %s", errors_dir); + return; + } + struct dirent *ent; + while ((ent = readdir(dir))) { + const char *name = ent->d_name; + if (strlen(name) >= strlen("x.pom") && + strcmp(name + strlen(name) - strlen(".pom"), ".pom") == 0) { + printf("Testing %s...\n",name); + char *conf_path = malloc(strlen(errors_dir) + strlen(name) + 30); + sprintf(conf_path, "%s/errors/%s", test_dir, name); + pom_error *error; + pom_conf *conf = pom_load_path(conf_path, &error); + if (error) { + free(error); + free(conf_path); + continue; + } + test_fail("Parsing %s didn't produce an error but it should have.", + conf_path); + pom_conf_free(conf); + free(conf_path); + } + } + free(errors_dir); +// pom_conf *conf = pom_load_path("../tests"); +} diff --git a/tests/main.c b/tests/main.c index 7b791cd..ff68df3 100644 --- a/tests/main.c +++ b/tests/main.c @@ -2,6 +2,8 @@ #include <stdarg.h> #include <stdio.h> +#include <string.h> +#include <stdlib.h> static bool any_failure = false; @@ -15,12 +17,19 @@ void test_fail(const char *fmt, ...) { fprintf(stderr, "\n"); } -int main(void) { - const char *test_dir = "../tests"; +int main(int argc, char **argv) { + if (argc > 2 || (argc == 2 && strcmp(argv[1], "--help") == 0)) { + printf("usage: tests [TEST DIRECTORY]\n"); + return EXIT_FAILURE; + } + const char *test_dir = argc == 2 ? argv[1] : "../tests"; test_parsing(test_dir); + test_errors(test_dir); if (any_failure) { fprintf(stderr, "\x1b[1m\x1b[91mSome tests failed.\x1b[0m\n"); + return EXIT_FAILURE; } else { printf("\x1b[1m\x1b[92mAll tests OK\x1b[0m\n"); + return 0; } } diff --git a/tests/parsing.c b/tests/parsing.c index 2b953db..3c321c6 100644 --- a/tests/parsing.c +++ b/tests/parsing.c @@ -9,7 +9,7 @@ void test_parsing(const char *test_dir) { sprintf(parsing_dir, "%s/parsing", test_dir); DIR *dir = opendir(parsing_dir); if (!dir) { - test_fail("Couldn't open test directory %s", test_dir); + test_fail("Couldn't open test directory %s", parsing_dir); return; } struct dirent *ent; @@ -64,5 +64,4 @@ void test_parsing(const char *test_dir) { } } free(parsing_dir); -// pom_conf *conf = pom_load_path("../tests"); } diff --git a/tests/test.h b/tests/test.h index 5e0b8e5..cd19482 100644 --- a/tests/test.h +++ b/tests/test.h @@ -15,3 +15,4 @@ void test_fail(PRINTF_FORMAT_STRING const char *, ...) ATTRIBUTE_PRINTF(1, 2); void test_parsing(const char *test_dir); +void test_errors(const char *test_dir); |