From e63e8b8a377fa6496297fe0113a931336466e4fc Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Sun, 24 Mar 2024 20:05:52 +0200 Subject: [PATCH] test: add "strict" JSON tests Adapt an existing JSON parsing test suite from https://github.com/nst/JSONTestSuite for SPA JSON. --- test/data/test-spa-json.txt | Bin 0 -> 39936 bytes test/pwtest.c | 1 + test/test-spa-json.c | 340 ++++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 test/data/test-spa-json.txt diff --git a/test/data/test-spa-json.txt b/test/data/test-spa-json.txt new file mode 100644 index 0000000000000000000000000000000000000000..3297d9021a7b94f5e7d51d8c11e0a2f89ed0bb0a GIT binary patch literal 39936 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 literal 0 HcmV?d00001 diff --git a/test/pwtest.c b/test/pwtest.c index 80217d999..5726fc744 100644 --- a/test/pwtest.c +++ b/test/pwtest.c @@ -787,6 +787,7 @@ static void set_test_env(struct pwtest_context *ctx, struct pwtest_test *t) replace_env(t, "ACP_PATHS_DIR", SOURCE_ROOT "/spa/plugins/alsa/mixer/paths"); replace_env(t, "ACP_PROFILES_DIR", SOURCE_ROOT "/spa/plugins/alsa/mixer/profile-sets"); replace_env(t, "PIPEWIRE_LOG_SYSTEMD", "false"); + replace_env(t, "PWTEST_DATA_DIR", SOURCE_ROOT "/test/data"); } static void close_pipes(int fds[_FD_LAST]) diff --git a/test/test-spa-json.c b/test/test-spa-json.c index 7e1624973..e06b2d3c5 100644 --- a/test/test-spa-json.c +++ b/test/test-spa-json.c @@ -3,12 +3,14 @@ /* SPDX-License-Identifier: MIT */ #include +#include #include "pwtest.h" #include #include #include +#include PWTEST(json_abi) { @@ -667,6 +669,343 @@ PWTEST(json_int) return PWTEST_PASS; } +static char *read_json_testcase(FILE *f, char **name, size_t *size, char **result, size_t *result_size) +{ + ssize_t res; + spa_autofree char *data = NULL; + spa_autofree char *resdata = NULL; + spa_autofree char *buf = NULL; + size_t alloc = 0; + size_t len = 0; + size_t resdata_len = 0; + char **dst = &data; + size_t *dst_len = &len; + + *name = NULL; + + do { + res = getline(&buf, &alloc, f); + if (res <= 0) + return NULL; + + if (spa_strstartswith(buf, "<<< ")) { + size_t k = strcspn(buf + 4, " \t\n"); + free(*name); + *name = strndup(buf + 4, k); + continue; + } else if (spa_strstartswith(buf, "==")) { + dst = &resdata; + dst_len = &resdata_len; + continue; + } else if (spa_strstartswith(buf, ">>>")) { + break; + } else if (!*name) { + continue; + } + + if (!*dst) { + *dst = spa_steal_ptr(buf); + *dst_len = res; + buf = NULL; + alloc = 0; + } else { + char *p = realloc(*dst, len + res + 1); + + pwtest_ptr_notnull(p); + + *dst = p; + memcpy(*dst + len, buf, res); + *dst_len += res; + (*dst)[len] = '\0'; + } + } while (1); + + if (!*name) + return NULL; + + *result = spa_steal_ptr(resdata); + *result_size = resdata_len; + + *size = len; + return spa_steal_ptr(data); +} + +static int validate_strict_json(struct spa_json *it, int depth, FILE *f) +{ + struct spa_json sub; + int res = 0, len; + char key[1024]; + const char *value; + + len = spa_json_next(it, &value); + if (len <= 0) + goto done; + + if (depth > 50) { + /* stop descending */ + while ((len = spa_json_next(it, &value)) > 0); + goto done; + } + + if (spa_json_is_array(value, len)) { + bool empty = true; + + fputc('[', f); + spa_json_enter(it, &sub); + while ((res = validate_strict_json(&sub, depth+1, f)) > 0) { + empty = false; + fputc(',', f); + } + if (res < 0) + return res; + if (!empty) + fseek(f, -1, SEEK_CUR); + fputc(']', f); + } else if (spa_json_is_object(value, len)) { + bool empty = true; + + spa_json_enter(it, &sub); + + fputc('{', f); + while (spa_json_get_string(&sub, key, sizeof(key)) > 0) { + fprintf(f, "\"%s\":", key); + + res = validate_strict_json(&sub, depth+1, f); + if (res < 0) + return res; + if (res == 0) + return -2; /* empty object body */ + fputc(',', f); + empty = false; + } + if (!empty) + fseek(f, -1, SEEK_CUR); + fputc('}', f); + } else if (spa_json_is_string(value, len)) { + char buf[1024]; + int i; + + spa_json_parse_stringn(value, len, buf, sizeof(buf)); + + fputc('"', f); + for (i = 0; buf[i]; ++i) { + uint8_t c = buf[i]; + switch (c) { + case '\n': fputs("\\n", f); break; + case '\b': fputs("\\b", f); break; + case '\f': fputs("\\f", f); break; + case '\t': fputs("\\t", f); break; + case '\r': fputs("\\r", f); break; + case '"': fputs("\\\"", f); break; + case '\\': fputs("\\\\", f); break; + default: + if (c < 32 || c == 0x7f) { + fprintf(f, "\\u%04x", c); + } else { + fputc(c, f); + } + break; + } + } + fputc('"', f); + } else if (spa_json_is_null(value, len)) { + fprintf(f, "null"); + } else if (spa_json_is_bool(value, len)) { + fprintf(f, spa_json_is_true(value, len) ? "true" : "false"); + } else if (spa_json_is_int(value, len)) { + int v; + spa_json_parse_int(value, len, &v); + fprintf(f, "%d", v); + } else if (spa_json_is_float(value, len)) { + float v; + spa_json_parse_float(value, len, &v); + fprintf(f, "%G", v); + } else { + /* bare value: error here, as we want to test + * int/float/etc parsing */ + return -2; + } + +done: + if (spa_json_get_error(it, NULL, NULL, NULL)) + return -1; + + return len; +} + +PWTEST(json_data) +{ + static const char * const extra_success[] = { + /* indeterminate cases that succeed */ + "i_number_double_huge_neg_exp.json", + "i_number_neg_int_huge_exp.json", + "i_number_pos_double_huge_exp.json", + "i_number_real_neg_overflow.json", + "i_number_real_pos_overflow.json", + "i_number_real_underflow.json", + "i_number_too_big_neg_int.json", + "i_number_too_big_pos_int.json", + "i_number_very_big_negative_int.json", + "i_object_key_lone_2nd_surrogate.json", + "i_string_1st_surrogate_but_2nd_missing.json", + "i_string_1st_valid_surrogate_2nd_invalid.json", + "i_string_incomplete_surrogate_and_escape_valid.json", + "i_string_incomplete_surrogate_pair.json", + "i_string_incomplete_surrogates_escape_valid.json", + "i_string_invalid_lonely_surrogate.json", + "i_string_invalid_surrogate.json", + "i_string_inverted_surrogates_U+1D11E.json", + "i_string_lone_second_surrogate.json", + "i_string_not_in_unicode_range.json", + "i_string_overlong_sequence_2_bytes.json", + "i_string_UTF8_surrogate_U+D800.json", + "i_structure_500_nested_arrays.json", + + /* relaxed JSON parsing */ + "n_array_1_true_without_comma.json", + "n_array_comma_after_close.json", + "n_array_comma_and_number.json", + "n_array_double_comma.json", + "n_array_double_extra_comma.json", + "n_array_extra_comma.json", + "n_array_just_comma.json", + "n_array_missing_value.json", + "n_array_number_and_comma.json", + "n_array_number_and_several_commas.json", + "n_object_comma_instead_of_colon.json", + "n_object_double_colon.json", + "n_object_missing_semicolon.json", + "n_object_non_string_key_but_huge_number_instead.json", + "n_object_non_string_key.json", + "n_object_repeated_null_null.json", + "n_object_several_trailing_commas.json", + "n_object_single_quote.json", + "n_object_trailing_comma.json", + "n_object_two_commas_in_a_row.json", + "n_object_unquoted_key.json", + "n_object_with_trailing_garbage.json", + "n_single_space.json", + "n_structure_double_array.json", + "n_structure_no_data.json", + "n_structure_null-byte-outside-string.json", + "n_structure_object_with_trailing_garbage.json", + "n_structure_trailing_#.json", + + /* SPA JSON accepts more number formats */ + "n_number_-01.json", + "n_number_0.e1.json", + "n_number_1_000.json", + "n_number_+1.json", + "n_number_2.e+3.json", + "n_number_2.e-3.json", + "n_number_2.e3.json", + "n_number_.2e-3.json", + "n_number_-2..json", + "n_number_hex_1_digit.json", + "n_number_hex_2_digits.json", + "n_number_neg_int_starting_with_zero.json", + "n_number_neg_real_without_int_part.json", + "n_number_real_without_fractional_part.json", + "n_number_starting_with_dot.json", + "n_number_with_leading_zero.json", + + /* \u escape not validated */ + "n_string_1_surrogate_then_escape_u1.json", + "n_string_1_surrogate_then_escape_u1x.json", + "n_string_1_surrogate_then_escape_u.json", + "n_string_incomplete_escaped_character.json", + "n_string_incomplete_surrogate.json", + "n_string_invalid_unicode_escape.json", + }; + + static const char * const ignore_result[] = { + /* Filtering duplicates is for upper layer */ + "y_object_duplicated_key_and_value.json", + "y_object_duplicated_key.json", + + /* spa_json_parse_string API doesn't do \0 */ + "y_object_escaped_null_in_key.json", + "y_string_null_escape.json", + + /* XXX: something with surrogate handling? */ + "y_string_last_surrogates_1_and_2.json", + "y_string_unicode_U+10FFFE_nonchar.json", + }; + + const char *basedir = getenv("PWTEST_DATA_DIR"); + char path[PATH_MAX]; + spa_autoptr(FILE) f = NULL; + + pwtest_ptr_notnull(basedir); + spa_scnprintf(path, sizeof(path), "%s/test-spa-json.txt", basedir); + f = fopen(path, "r"); + pwtest_ptr_notnull(f); + + while (1) { + spa_autofree char *data = NULL; + spa_autofree char *result = NULL; + spa_autofree char *name = NULL; + size_t size; + size_t result_size; + struct spa_json it; + int expect = -1; + int res; + spa_autofree char *f_ptr = NULL; + size_t f_size; + FILE *fres; + + data = read_json_testcase(f, &name, &size, &result, &result_size); + if (!data) + break; + + spa_json_init(&it, data, size); + + fres = open_memstream(&f_ptr, &f_size); + + while ((res = validate_strict_json(&it, 0, fres)) > 0); + + fclose(fres); + + SPA_FOR_EACH_ELEMENT_VAR(extra_success, suc) { + if (spa_streq(*suc, name)) { + expect = false; + break; + } + } + if (expect < 0) { + if (spa_strstartswith(name, "y_")) + expect = false; + if (spa_strstartswith(name, "t_")) + expect = false; + } + + SPA_FOR_EACH_ELEMENT_VAR(ignore_result, suc) { + if (spa_streq(*suc, name)) { + free(result); + result = NULL; + break; + } + } + + fprintf(stdout, "%s (expect %s)\n", name, expect ? "fail" : "ok"); + fflush(stdout); + pwtest_bool_eq(res == -2 || spa_json_get_error(&it, NULL, NULL, NULL), expect); + if (res == -2) + pwtest_bool_false(spa_json_get_error(&it, NULL, NULL, NULL)); + + if (result) { + while (strlen(result) > 0 && result[strlen(result) - 1] == '\n') + result[strlen(result) - 1] = '\0'; + + fprintf(stdout, "\tgot: >>%s<< expected: >>%s<<\n", f_ptr, result); + fflush(stdout); + pwtest_bool_true(spa_streq(f_ptr, result)); + } + } + + return PWTEST_PASS; +} + PWTEST_SUITE(spa_json) { pwtest_add(json_abi, PWTEST_NOARG); @@ -678,6 +1017,7 @@ PWTEST_SUITE(spa_json) pwtest_add(json_float, PWTEST_NOARG); pwtest_add(json_float_check, PWTEST_NOARG); pwtest_add(json_int, PWTEST_NOARG); + pwtest_add(json_data, PWTEST_NOARG); return PWTEST_PASS; }