From 9eeb858a9a1a65c27cb6fb131ffcad82328dc19b Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Fri, 24 Nov 2023 12:23:52 -0700 Subject: [PATCH] Add first prompt type. --- main.c | 10 ++++++-- specs/clang/spec.json | 4 +++- src/dyn_array.c | 3 +++ src/validator.c | 39 +++++++++++++++++++++++++++---- test/runner.c | 1 + test/test_dyn_array.h | 27 +++++++++++----------- test/test_validator.h | 53 +++++++++++++++++++++++++++++++++++++++---- 7 files changed, 112 insertions(+), 25 deletions(-) diff --git a/main.c b/main.c index fa1b610..1146a9d 100644 --- a/main.c +++ b/main.c @@ -58,14 +58,20 @@ static int run(const char *root_dir, const char *target) { goto cleanup_parsed; } - // TODO: Extract the prompts out of the `spec.json` file. // TODO: Load in the curses interface. // TODO: Run `run.sh`. retval = EXIT_SUCCESS; +cleanup_prompts: + if (prompts) { + dyn_array_free(prompts); + } + cleanup_parsed: - cJSON_Delete(parsed); + if (parsed) { + cJSON_Delete(parsed); + } cleanup_config: config_free(config); diff --git a/specs/clang/spec.json b/specs/clang/spec.json index fe51488..bde20d8 100644 --- a/specs/clang/spec.json +++ b/specs/clang/spec.json @@ -1 +1,3 @@ -[] +{ + "test": "$STRING" +} diff --git a/src/dyn_array.c b/src/dyn_array.c index 5c1f45a..72560e9 100644 --- a/src/dyn_array.c +++ b/src/dyn_array.c @@ -30,6 +30,9 @@ void dyn_array_free(struct DynArray *a) { if (!a) { return; } + for (int i = 0; i < a->size; ++i) { + free(a->buf[i]); + } free(a->buf); free(a); } diff --git a/src/validator.c b/src/validator.c index 8c94e65..87914f7 100644 --- a/src/validator.c +++ b/src/validator.c @@ -1,7 +1,22 @@ -#include +#include #include "validator.h" +static struct Prompt *create_prompt(const cJSON *const kv) { + if (!kv->string) { + return 0; + } + + if (cJSON_IsString(kv) && strcmp(kv->valuestring, "$STRING") == 0) { + struct Prompt *prompt = malloc(sizeof(struct Prompt)); + prompt->key = kv->string; + prompt->type = PT_STRING; + return prompt; + } + + return 0; +} + enum SpecValidationError validate_spec_json(const cJSON *const parsed, struct DynArray **prompts) { *prompts = 0; @@ -16,13 +31,27 @@ validate_spec_json(const cJSON *const parsed, struct DynArray **prompts) { } enum SpecValidationError retval = 0; - // `cJSON_GetArraySize` works because internally objects are stored as arrays. + // `cJSON_GetArraySize` works because internally JSON objects are stored as + // arrays. *prompts = dyn_array_new(cJSON_GetArraySize(parsed)); - assert(0); + cJSON *child = parsed->child; + while (child) { + struct Prompt *prompt = create_prompt(child); + if (!prompt) { + retval = SVE_INVALID_VALUE; + goto cleanup; + } + dyn_array_push(*prompts, prompt); + child = child->next; + } + + return 0; cleanup: - dyn_array_free(*prompts); - *prompts = 0; + if (*prompts) { + dyn_array_free(*prompts); + *prompts = 0; + } return retval; } diff --git a/test/runner.c b/test/runner.c index d0f0aa6..9488cae 100644 --- a/test/runner.c +++ b/test/runner.c @@ -29,6 +29,7 @@ int main(int argc, char *argv[]) { sput_enter_suite("validator"); sput_run_test(test_validate_spec_json_not_toplevel_object); + sput_run_test(test_validate_spec_json_invalid_value_type); sput_finish_testing(); diff --git a/test/test_dyn_array.h b/test/test_dyn_array.h index 61bb4de..1540a90 100644 --- a/test/test_dyn_array.h +++ b/test/test_dyn_array.h @@ -12,13 +12,13 @@ static void test_dyn_array_zero_capacity() { sput_fail_unless(a->size == 0, "a->size == 0"); sput_fail_unless(a->_capacity == 1, "a->_capacity == 1"); - int x; - dyn_array_push(a, &x); + int *x = malloc(sizeof(int)); + dyn_array_push(a, x); sput_fail_unless(a->size == 1, "a->size == 1"); sput_fail_unless(a->_capacity == 1, "a->_capacity == 1"); - int y; - dyn_array_push(a, &y); + int *y = malloc(sizeof(int)); + dyn_array_push(a, y); sput_fail_unless(a->size == 2, "a->size == 2"); sput_fail_unless(a->_capacity == 2, "a->_capacity == 2"); @@ -26,24 +26,25 @@ static void test_dyn_array_zero_capacity() { } /* -A @DynArray with nonzero capacity can be instantiated and have entries pushed onto. +A @DynArray with nonzero capacity can be instantiated and have entries pushed +onto. */ static void test_dyn_array_nonzero_capacity() { struct DynArray *a = dyn_array_new(3); sput_fail_unless(a->size == 0, "a->size == 0"); sput_fail_unless(a->_capacity == 3, "a->_capacity == 3"); - int x; - int y; - int z; - dyn_array_push(a, &x); - dyn_array_push(a, &y); - dyn_array_push(a, &z); + int *x = malloc(sizeof(int)); + int *y = malloc(sizeof(int)); + int *z = malloc(sizeof(int)); + dyn_array_push(a, x); + dyn_array_push(a, y); + dyn_array_push(a, z); sput_fail_unless(a->size == 3, "a->size == 3"); sput_fail_unless(a->_capacity == 3, "a->_capacity == 3"); - int w; - dyn_array_push(a, &w); + int *w = malloc(sizeof(int)); + dyn_array_push(a, w); sput_fail_unless(a->size == 4, "a->size == 4"); sput_fail_unless(a->_capacity == 6, "a->_capacity == 6"); diff --git a/test/test_validator.h b/test/test_validator.h index f6fe05f..a9a04a7 100644 --- a/test/test_validator.h +++ b/test/test_validator.h @@ -5,13 +5,58 @@ #include "sput.h" #include "validator.h" +struct TestValidatorFixture { + const char *json; + struct DynArray *prompts; + cJSON *parsed; +}; + +static struct TestValidatorFixture *test_validator_setup(const char *json) { + struct TestValidatorFixture *fixture = + malloc(sizeof(struct TestValidatorFixture)); + fixture->json = json; + fixture->prompts = 0; + fixture->parsed = cJSON_Parse(json); + return fixture; +} + +static void test_validator_teardown(struct TestValidatorFixture *fixture) { + if (fixture->parsed) { + cJSON_Delete(fixture->parsed); + } + free(fixture); +} + 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); + struct TestValidatorFixture *fixture = test_validator_setup("[]"); + + enum SpecValidationError retval = + validate_spec_json(fixture->parsed, &fixture->prompts); sput_fail_unless(retval == SVE_NOT_TOPLEVEL_OBJECT, "not top-level object"); - cJSON_Delete(parsed); + test_validator_teardown(fixture); +} + +static void test_validate_spec_json_invalid_value_type() { + struct TestValidatorFixture *fixture = + test_validator_setup("{\"key\": \"$UNKNOWN\"}"); + + enum SpecValidationError retval = + validate_spec_json(fixture->parsed, &fixture->prompts); + sput_fail_unless(retval == SVE_INVALID_VALUE, "invalid value"); + + test_validator_teardown(fixture); +} + +static void test_validate_spec_json_valid() { + struct TestValidatorFixture *fixture = + test_validator_setup("{\"key\": \"$STRING\"}"); + + enum SpecValidationError retval = + validate_spec_json(fixture->parsed, &fixture->prompts); + sput_fail_unless(retval == 0, "valid"); + + test_validator_teardown(fixture); } #endif /* _BOOTSTRAP_TEST_VALIDATOR */