From df65c8bcac2ea2ce084b498cc6437980679f28bc Mon Sep 17 00:00:00 2001 From: Joshua Potter Date: Sat, 25 Nov 2023 15:58:13 -0700 Subject: [PATCH] Ensure keys are alphanumeric, underscores, and do not begin with digits. --- README.md | 4 ++-- include/error.h | 3 +++ src/validator.c | 18 ++++++++++++++++++ test/test.c | 2 ++ test/test_validator.h | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6dd62e9..d948083 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ CLI utility for defining custom project initialization scripts. TODO: - [ ] Add evaluator tests. - [ ] Color output to console. -- [ ] Ensure keys are alphanumeric, underscore ## Overview @@ -120,7 +119,8 @@ a string (submitted with a newline). If the user were to enter, say `fieldvalue`, in response to the prompt, the `runner` script would then have access to an environment variable -`FIELDNAME` set to `fieldvalue` on launch. +`FIELDNAME` set to `fieldvalue` on launch. Field names should consist of +alphanumeric characters or underscores, and may not start with a digit. #### Types diff --git a/include/error.h b/include/error.h index 3108cda..61b2111 100644 --- a/include/error.h +++ b/include/error.h @@ -37,6 +37,9 @@ enum ErrorCode { ERROR_VALIDATOR_TOP_LEVEL_NOT_OBJECT, /// A field in `spec.json` is not an object. ERROR_VALIDATOR_FIELD_NOT_OBJECT, + /// A field name in `spec.json` is not alphanumeric and beginning with a + /// non-digit. + ERROR_VALIDATOR_FIELD_NAME_INVALID, /// The `type` of a `spec.json` field is not a string. ERROR_VALIDATOR_FIELD_TYPE_INVALID, /// The `type` of a `spec.json` field does not correspond to a known prompt diff --git a/src/validator.c b/src/validator.c index 477bfb4..5d8f65a 100644 --- a/src/validator.c +++ b/src/validator.c @@ -1,5 +1,7 @@ #include "validator.h" +#include + #include "string_utils.h" static struct Error *read_field(const cJSON *const field, struct Field **out) { @@ -12,6 +14,22 @@ static struct Error *read_field(const cJSON *const field, struct Field **out) { ); } + if (isdigit(field->string[0])) { + return ERROR_NEW( + ERROR_VALIDATOR_FIELD_NAME_INVALID, + "Field names may not begin with a digit." + ); + } else { + for (const char *c = field->string; *c; ++c) { + if (*c != '_' && !isalnum(*c)) { + return ERROR_NEW( + ERROR_VALIDATOR_FIELD_NAME_INVALID, + "Field names must consist of alphanumeric characters or underscores." + ); + } + } + } + struct Error *error = 0; *out = malloc(sizeof(struct Field)); (*out)->key = field->string; diff --git a/test/test.c b/test/test.c index 55abe74..95dce04 100644 --- a/test/test.c +++ b/test/test.c @@ -36,6 +36,8 @@ int main(int argc, char *argv[]) { sput_enter_suite("validator"); sput_run_test(test_validator_toplevel_not_object); sput_run_test(test_validator_field_not_object); + sput_run_test(test_validator_field_name_leading_digit); + sput_run_test(test_validator_field_name_non_alnum); sput_run_test(test_validator_field_type_invalid); sput_run_test(test_validator_field_type_unknown); sput_run_test(test_validator_valid_type_ci); diff --git a/test/test_validator.h b/test/test_validator.h index 9aaf0f2..02e21ac 100644 --- a/test/test_validator.h +++ b/test/test_validator.h @@ -52,6 +52,43 @@ static void test_validator_field_not_object() { test_validator_teardown(fixture); } +static void test_validator_field_name_leading_digit() { + struct TestValidatorFixture *fixture = test_validator_setup( + "{" + " \"1abc\": {" + " \"type\": \"text\"" + " }" + "}" + ); + + struct Error *error = validate_spec_json(fixture->parsed, &fixture->prompts); + sput_fail_unless( + error->code == ERROR_VALIDATOR_FIELD_NAME_INVALID, + "field name leading digit" + ); + error_free(error); + + test_validator_teardown(fixture); +} + +static void test_validator_field_name_non_alnum() { + struct TestValidatorFixture *fixture = test_validator_setup( + "{" + " \"a~bc\": {" + " \"type\": \"text\"" + " }" + "}" + ); + + struct Error *error = validate_spec_json(fixture->parsed, &fixture->prompts); + sput_fail_unless( + error->code == ERROR_VALIDATOR_FIELD_NAME_INVALID, "field name non alnum" + ); + error_free(error); + + test_validator_teardown(fixture); +} + static void test_validator_field_type_invalid() { struct TestValidatorFixture *fixture = test_validator_setup( "{"