/* $Id: confparse-t.c 5955 2002-12-08 09:28:32Z rra $ */ /* confparse test suite. */ #include "config.h" #include "clibrary.h" #include #include "inn/confparse.h" #include "inn/messages.h" #include "inn/vector.h" #include "libinn.h" #include "libtest.h" /* Given a FILE *, read from that file, putting the results into a newly allocated buffer, until encountering a line consisting solely of "===". Returns the buffer, NULL on end of file, dies on error. */ static char * read_section(FILE *file) { char buf[1024] = ""; char *data = NULL; char *status; status = fgets(buf, sizeof(buf), file); if (status == NULL) return false; while (1) { if (status == NULL) die("Unexpected end of file while reading tests"); if (strcmp(buf, "===\n") == 0) break; if (data == NULL) { data = xstrdup(buf); } else { char *new_data; new_data = concat(data, buf, (char *) 0); free(data); data = new_data; } status = fgets(buf, sizeof(buf), file); } return data; } /* Read from the given file a configuration file and write it out to config/tmp. Returns true on success, false on end of file, and dies on any error. */ static bool write_test_config(FILE *file) { FILE *tmp; char *config; config = read_section(file); if (config == NULL) return false; tmp = fopen("config/tmp", "w"); if (tmp == NULL) sysdie("Cannot create config/tmp"); if (fputs(config, tmp) == EOF) sysdie("Write error while writing to config/tmp"); fclose(tmp); free(config); return true; } /* Parse a given config file with errors, setting the appropriate error handler for the duration of the parse to save errors into the errors global. Returns the resulting config_group. */ static struct config_group * parse_error_config(const char *filename) { struct config_group *group; errors_capture(); group = config_parse_file(filename); errors_uncapture(); return group; } /* Read in a configuration file from the provided FILE *, write it to disk, parse the temporary config file, and return the resulting config_group in the pointer passed as the second parameter. Returns true on success, false on end of file. */ static bool parse_test_config(FILE *file, struct config_group **group) { if (!write_test_config(file)) return false; *group = parse_error_config("config/tmp"); unlink("config/tmp"); return true; } /* Test the error test cases in config/errors, ensuring that they all fail to parse and match the expected error messages. Takes the current test count and returns the new test count. */ static int test_errors(int n) { FILE *errfile; char *expected; struct config_group *group; errfile = fopen("config/errors", "r"); if (errfile == NULL) sysdie("Cannot open config/errors"); while (parse_test_config(errfile, &group)) { expected = read_section(errfile); if (expected == NULL) die("Unexpected end of file while reading error tests"); ok(n++, group == NULL); ok_string(n++, expected, errors); free(expected); } fclose(errfile); return n; } /* Test the warning test cases in config/warningss, ensuring that they all parse successfully and match the expected error messages. Takes the current test count and returns the new test count. */ static int test_warnings(int n) { FILE *warnfile; char *expected; struct config_group *group; warnfile = fopen("config/warnings", "r"); if (warnfile == NULL) sysdie("Cannot open config/warnings"); while (parse_test_config(warnfile, &group)) { expected = read_section(warnfile); if (expected == NULL) die("Unexpected end of file while reading error tests"); ok(n++, group != NULL); ok_string(n++, expected, errors); free(expected); } fclose(warnfile); return n; } /* Test the warning test cases in config/warn-bool, ensuring that they all parse successfully and produce the expected error messages when retrieved as bools. Takes the current test count and returns the new test count. */ static int test_warnings_bool(int n) { FILE *warnfile; char *expected; struct config_group *group; bool b_value = false; warnfile = fopen("config/warn-bool", "r"); if (warnfile == NULL) sysdie("Cannot open config/warn-bool"); while (parse_test_config(warnfile, &group)) { expected = read_section(warnfile); if (expected == NULL) die("Unexpected end of file while reading error tests"); ok(n++, group != NULL); ok(n++, errors == NULL); errors_capture(); ok(n++, !config_param_boolean(group, "parameter", &b_value)); ok_string(n++, expected, errors); errors_uncapture(); free(expected); } fclose(warnfile); return n; } /* Test the warning test cases in config/warn-int, ensuring that they all parse successfully and produce the expected error messages when retrieved as bools. Takes the current test count and returns the new test count. */ static int test_warnings_int(int n) { FILE *warnfile; char *expected; struct config_group *group; long l_value = 1; warnfile = fopen("config/warn-int", "r"); if (warnfile == NULL) sysdie("Cannot open config/warn-int"); while (parse_test_config(warnfile, &group)) { expected = read_section(warnfile); if (expected == NULL) die("Unexpected end of file while reading error tests"); ok(n++, group != NULL); ok(n++, errors == NULL); errors_capture(); ok(n++, !config_param_integer(group, "parameter", &l_value)); ok_string(n++, expected, errors); errors_uncapture(); free(expected); } fclose(warnfile); return n; } int main(void) { struct config_group *group; bool b_value = false; long l_value = 1; const char *s_value; struct vector *v_value; char *long_param, *long_value; size_t length; int n; FILE *tmpconfig; puts("125"); if (access("config/valid", F_OK) < 0) if (access("lib/config/valid", F_OK) == 0) chdir("lib"); group = config_parse_file("config/valid"); ok(1, group != NULL); if (group == NULL) exit(1); /* Booleans. */ ok(2, config_param_boolean(group, "param1", &b_value)); ok(3, b_value); b_value = false; ok(4, config_param_boolean(group, "param2", &b_value)); ok(5, b_value); b_value = false; ok(6, config_param_boolean(group, "param3", &b_value)); ok(7, b_value); ok(8, config_param_boolean(group, "param4", &b_value)); ok(9, !b_value); b_value = true; ok(10, config_param_boolean(group, "param5", &b_value)); ok(11, !b_value); b_value = true; ok(12, config_param_boolean(group, "param6", &b_value)); ok(13, !b_value); /* Integers. */ ok(14, config_param_integer(group, "int1", &l_value)); ok(15, l_value == 0); ok(16, config_param_integer(group, "int2", &l_value)); ok(17, l_value == -3); ok(18, !config_param_integer(group, "int3", &l_value)); ok(19, l_value == -3); ok(20, config_param_integer(group, "int4", &l_value)); ok(21, l_value == 5000); ok(22, config_param_integer(group, "int5", &l_value)); ok(23, l_value == 2147483647L); ok(24, config_param_integer(group, "int6", &l_value)); ok(25, l_value == (-2147483647L - 1)); /* Strings. */ ok(26, config_param_string(group, "string1", &s_value)); ok_string(27, "foo", s_value); ok(28, config_param_string(group, "string2", &s_value)); ok_string(29, "bar", s_value); ok(30, config_param_string(group, "string3", &s_value)); ok_string(31, "this is a test", s_value); ok(32, config_param_string(group, "string4", &s_value)); ok_string(33, "this is a test", s_value); ok(34, config_param_string(group, "string5", &s_value)); ok_string(35, "this is \a\b\f\n\r\t\v a test \' of \" escapes \?\\", s_value); ok(36, config_param_string(group, "string6", &s_value)); ok_string(37, "# this is not a comment", s_value); ok(38, config_param_string(group, "string7", &s_value)); ok_string(39, "lost \nyet?", s_value); config_free(group); /* Missing newline. */ group = config_parse_file("config/no-newline"); ok(40, group != NULL); if (group == NULL) { ok(41, false); ok(42, false); } else { ok(41, config_param_string(group, "parameter", &s_value)); ok_string(42, "value", s_value); config_free(group); } /* Extremely long parameter and value. */ tmpconfig = fopen("config/tmp", "w"); if (tmpconfig == NULL) sysdie("cannot create config/tmp"); long_param = xcalloc(20001, 1); memset(long_param, 'a', 20000); long_value = xcalloc(64 * 1024 + 1, 1); memset(long_value, 'b', 64 * 1024); fprintf(tmpconfig, "%s: \"%s\"; two: %s", long_param, long_value, long_value); fclose(tmpconfig); group = config_parse_file("config/tmp"); ok(43, group != NULL); if (group == NULL) { ok(44, false); ok(45, false); ok(46, false); ok(47, false); } else { ok(44, config_param_string(group, long_param, &s_value)); ok_string(45, long_value, s_value); ok(46, config_param_string(group, "two", &s_value)); ok_string(47, long_value, s_value); config_free(group); } unlink("config/tmp"); free(long_param); free(long_value); /* Parsing problems exactly on the boundary of a buffer. This test catches a bug in the parser that caused it to miss the colon at the end of a parameter because the colon was the first character read in a new read of the file buffer. */ tmpconfig = fopen("config/tmp", "w"); if (tmpconfig == NULL) sysdie("cannot create config/tmp"); length = 16 * 1024 - strlen(": baz\nfoo:"); long_param = xcalloc(length + 1, 1); memset(long_param, 'c', length); fprintf(tmpconfig, "%s: baz\nfoo: bar\n", long_param); fclose(tmpconfig); group = config_parse_file("config/tmp"); ok(48, group != NULL); if (group == NULL) { ok(49, false); ok(50, false); ok(51, false); ok(52, false); } else { ok(49, config_param_string(group, long_param, &s_value)); ok_string(50, "baz", s_value); ok(51, config_param_string(group, "foo", &s_value)); ok_string(52, "bar", s_value); config_free(group); } unlink("config/tmp"); free(long_param); /* Alternate line endings. */ group = config_parse_file("config/line-endings"); ok(53, group != NULL); if (group == NULL) exit(1); ok(54, config_param_boolean(group, "param1", &b_value)); ok(55, b_value); b_value = false; ok(56, config_param_boolean(group, "param2", &b_value)); ok(57, b_value); b_value = false; ok(58, config_param_boolean(group, "param3", &b_value)); ok(59, b_value); ok(60, config_param_boolean(group, "param4", &b_value)); ok(61, !b_value); ok(62, config_param_integer(group, "int1", &l_value)); ok(63, l_value == 0); ok(64, config_param_integer(group, "int2", &l_value)); ok(65, l_value == -3); config_free(group); /* Listing parameters. */ group = config_parse_file("config/simple"); ok(66, group != NULL); if (group == NULL) exit(1); v_value = config_params(group); ok_int(67, 2, v_value->count); ok_int(68, 2, v_value->allocated); if (strcmp(v_value->strings[0], "foo") == 0) ok_string(69, "bar", v_value->strings[1]); else if (strcmp(v_value->strings[0], "bar") == 0) ok_string(69, "foo", v_value->strings[1]); else ok(69, false); vector_free(v_value); config_free(group); /* Errors. */ group = parse_error_config("config/null"); ok(70, group == NULL); ok_string(71, "config/null: invalid NUL character found in file\n", errors); n = test_errors(72); n = test_warnings(n); n = test_warnings_bool(n); n = test_warnings_int(n); return 0; }