diff --git a/include/validator.h b/include/validator.h new file mode 100644 index 0000000..030fbdf --- /dev/null +++ b/include/validator.h @@ -0,0 +1,26 @@ +#ifndef _BOOTSTRAP_VALIDATOR_H +#define _BOOTSTRAP_VALIDATOR_H + +#include "cJSON.h" +#include "dyn_array.h" + +enum PromptType { + PT_STRING = 1, +}; + +struct Prompt { + const char *key; + enum PromptType type; +}; + +enum SpecValidationError { + SVE_NOT_TOPLEVEL_OBJECT = 1, + // The value of a top-level key does not correspond to one of the following: + // * "$STRING" + SVE_INVALID_VALUE, +}; + +enum SpecValidationError +validate_spec_json(const cJSON *const parsed, struct DynArray **prompts); + +#endif /* _BOOTSTRAP_VALIDATOR_H */ diff --git a/main.c b/main.c index e48c21c..12c5489 100644 --- a/main.c +++ b/main.c @@ -5,6 +5,7 @@ #include "cJSON.h" #include "config.h" #include "parser.h" +#include "validator.h" const char *ENV_BOOTSTRAP_ROOT_DIR = "BOOTSTRAP_ROOT_DIR"; @@ -51,10 +52,27 @@ int main(int argc, char **argv) { goto config_cleanup; } + // `parsed` must be free'd. + + struct DynArray *prompts = 0; + switch (validate_spec_json(parsed, &prompts)) { + case SVE_NOT_TOPLEVEL_OBJECT: + fprintf(stderr, "`spec.json` top-level JSON value must be object."); + retval = EXIT_FAILURE; + goto parsed_cleanup; + case SVE_INVALID_VALUE: + fprintf(stderr, "Encountered unknown `spec.json` value type."); + retval = EXIT_FAILURE; + goto parsed_cleanup; + } + // TODO: Extract the prompts out of the `spec.json` file. // TODO: Load in the curses interface. // TODO: Run `run.sh`. +parsed_cleanup: + cJSON_Delete(parsed); + config_cleanup: config_free(config); diff --git a/specs/clang/spec.json b/specs/clang/spec.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/specs/clang/spec.json @@ -0,0 +1 @@ +[] diff --git a/src/validator.c b/src/validator.c new file mode 100644 index 0000000..8c94e65 --- /dev/null +++ b/src/validator.c @@ -0,0 +1,28 @@ +#include + +#include "validator.h" + +enum SpecValidationError +validate_spec_json(const cJSON *const parsed, struct DynArray **prompts) { + *prompts = 0; + + if (!parsed) { + // Indicates no `spec.json` file was found. + return 0; + } + + if (!cJSON_IsObject(parsed)) { + return SVE_NOT_TOPLEVEL_OBJECT; + } + + enum SpecValidationError retval = 0; + // `cJSON_GetArraySize` works because internally objects are stored as arrays. + *prompts = dyn_array_new(cJSON_GetArraySize(parsed)); + + assert(0); + +cleanup: + dyn_array_free(*prompts); + *prompts = 0; + return retval; +} diff --git a/test/runner.c b/test/runner.c index 15bb7b7..556f3d5 100644 --- a/test/runner.c +++ b/test/runner.c @@ -3,6 +3,7 @@ #include "test_dyn_array.h" #include "test_parser.h" #include "test_path.h" +#include "test_validator.h" int main(int argc, char *argv[]) { sput_start_testing(); @@ -25,6 +26,9 @@ int main(int argc, char *argv[]) { sput_run_test(test_parse_spec_json_minimal); sput_run_test(test_parse_spec_json_invalid); + sput_enter_suite("validator"); + sput_run_test(test_validate_spec_json_not_toplevel_object); + sput_finish_testing(); return sput_get_return_value(); diff --git a/test/test_parser.h b/test/test_parser.h index 5771f4f..f72d4b8 100644 --- a/test/test_parser.h +++ b/test/test_parser.h @@ -1,5 +1,5 @@ -#ifndef _BOOTSTRAP_TEST_LOADER -#define _BOOTSTRAP_TEST_LOADER +#ifndef _BOOTSTRAP_TEST_PARSER +#define _BOOTSTRAP_TEST_PARSER #include @@ -81,4 +81,4 @@ static void test_parse_spec_json_invalid() { free(root_dir); } -#endif /* _BOOTSTRAP_TEST_LOADER */ +#endif /* _BOOTSTRAP_TEST_PARSER */ diff --git a/test/test_validator.h b/test/test_validator.h new file mode 100644 index 0000000..f6fe05f --- /dev/null +++ b/test/test_validator.h @@ -0,0 +1,17 @@ +#ifndef _BOOTSTRAP_TEST_VALIDATOR +#define _BOOTSTRAP_TEST_VALIDATOR + +#include "dyn_array.h" +#include "sput.h" +#include "validator.h" + +static void test_validate_spec_json_not_toplevel_object() { + struct DynArray *prompts = 0; + cJSON *parsed = cJSON_Parse("[]"); + enum SpecValidationError retval = validate_spec_json(parsed, &prompts); + sput_fail_unless(retval == SVE_NOT_TOPLEVEL_OBJECT, "not top-level object"); + + cJSON_Delete(parsed); +} + +#endif /* _BOOTSTRAP_TEST_VALIDATOR */