mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-21 14:33:55 +00:00
* Rename test_jconf.c to test_jconf_cpp.cpp * Parse the config file on arenas read_jconf now reads the file and builds the JSON tree in a scratch arena that is released before it returns, and copies the parsed strings into one process-lifetime arena instead of a malloc per string. parse_addr and the config parser share one address splitter. Port test_jconf to C++ and cover every field copied out of the parse tree, a re-read, and the densest file the size limit accepts. * tests: rename remaining C unit tests to .cpp (no content changes) * tests: port remaining C unit tests to the C++ test harness Convert acl, acl_literal, aead2022, base64, buffer, cache (legacy reference), crypto, ipset, ipset_reference, json, netutils, ppbloom, process, ref, ssurl and utils tests to test_helpers.hpp. ctest names are unchanged; every assertion is kept. Build the ported sources with the strict C++ warning set. * Run clang-tidy on every ported test The test regex skipped file names with digits (test_aead2022_cpp.cpp, test_base64_cpp.cpp); include them, fix the two optional accesses it then reports, and build test_jconf with the strict warning set. * docs: per-connection RSS on Linux against the C relay * test_jconf: check read_jconf results before using them
159 lines
4.7 KiB
C++
159 lines
4.7 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// JSON parser (src/json.cpp): values, nesting and malformed input.
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
#include "json.h"
|
|
#include "test_helpers.hpp"
|
|
|
|
namespace {
|
|
|
|
json_value *parse(const char *text)
|
|
{
|
|
return json_parse(text, std::strlen(text));
|
|
}
|
|
|
|
void test_parse_simple_object()
|
|
{
|
|
json_value *val = parse("{\"key\": \"value\", \"num\": 42}");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_object);
|
|
SS_CHECK(val->u.object.length == 2);
|
|
|
|
// First entry.
|
|
SS_CHECK(std::strcmp(val->u.object.values[0].name, "key") == 0);
|
|
SS_CHECK(val->u.object.values[0].value->type == json_string);
|
|
SS_CHECK(std::strcmp(val->u.object.values[0].value->u.string.ptr, "value") == 0);
|
|
|
|
// Second entry.
|
|
SS_CHECK(std::strcmp(val->u.object.values[1].name, "num") == 0);
|
|
SS_CHECK(val->u.object.values[1].value->type == json_integer);
|
|
SS_CHECK(val->u.object.values[1].value->u.integer == 42);
|
|
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_array()
|
|
{
|
|
json_value *val = parse("[1, 2, 3]");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_array);
|
|
SS_CHECK(val->u.array.length == 3);
|
|
SS_CHECK(val->u.array.values[0]->type == json_integer);
|
|
SS_CHECK(val->u.array.values[0]->u.integer == 1);
|
|
SS_CHECK(val->u.array.values[1]->u.integer == 2);
|
|
SS_CHECK(val->u.array.values[2]->u.integer == 3);
|
|
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_nested()
|
|
{
|
|
json_value *val = parse("{\"outer\": {\"inner\": true}}");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_object);
|
|
SS_CHECK(val->u.object.length == 1);
|
|
|
|
json_value *outer = val->u.object.values[0].value;
|
|
SS_CHECK(outer->type == json_object);
|
|
SS_CHECK(outer->u.object.length == 1);
|
|
|
|
SS_CHECK(outer->u.object.values[0].value->type == json_boolean);
|
|
SS_CHECK(outer->u.object.values[0].value->u.boolean != 0);
|
|
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_types()
|
|
{
|
|
json_value *val = parse("{\"s\": \"hello\", \"i\": -5, \"d\": 3.14, \"b\": false, \"n\": null}");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_object);
|
|
SS_CHECK(val->u.object.length == 5);
|
|
|
|
SS_CHECK(val->u.object.values[0].value->type == json_string);
|
|
SS_CHECK(val->u.object.values[1].value->type == json_integer);
|
|
SS_CHECK(val->u.object.values[1].value->u.integer == -5);
|
|
SS_CHECK(val->u.object.values[2].value->type == json_double);
|
|
SS_CHECK(val->u.object.values[3].value->type == json_boolean);
|
|
SS_CHECK(val->u.object.values[3].value->u.boolean == 0);
|
|
SS_CHECK(val->u.object.values[4].value->type == json_null);
|
|
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_invalid()
|
|
{
|
|
// Missing closing brace.
|
|
SS_CHECK(json_parse("{\"key\": 1", 9) == nullptr);
|
|
|
|
// Empty string.
|
|
SS_CHECK(json_parse("", 0) == nullptr);
|
|
|
|
// Just garbage.
|
|
SS_CHECK(json_parse("not json", 8) == nullptr);
|
|
}
|
|
|
|
void test_parse_truncated_escape_sequences()
|
|
{
|
|
// Four bytes remain after 'u', but the fourth hex read would hit EOF.
|
|
SS_CHECK(parse("\"\\uB2D") == nullptr);
|
|
|
|
// Six bytes remain after the high surrogate, but the sixth read would hit EOF.
|
|
SS_CHECK(parse("\"\\udfff\\ufff") == nullptr);
|
|
}
|
|
|
|
void test_parse_truncated_literals()
|
|
{
|
|
SS_CHECK(json_parse("tru", 3) == nullptr);
|
|
SS_CHECK(json_parse("fals", 4) == nullptr);
|
|
SS_CHECK(json_parse("nul", 3) == nullptr);
|
|
}
|
|
|
|
void test_parse_empty_object()
|
|
{
|
|
json_value *val = parse("{}");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_object);
|
|
SS_CHECK(val->u.object.length == 0);
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_empty_array()
|
|
{
|
|
json_value *val = parse("[]");
|
|
SS_CHECK(val != nullptr);
|
|
SS_CHECK(val->type == json_array);
|
|
SS_CHECK(val->u.array.length == 0);
|
|
json_value_free(val);
|
|
}
|
|
|
|
void test_parse_wide_numbers()
|
|
{
|
|
json_value *wide = parse("[4294967296,9223372036854775807,-4294967296,0.4294967296]");
|
|
SS_CHECK(wide != nullptr && wide->type == json_array && wide->u.array.length == 4);
|
|
SS_CHECK(wide->u.array.values[0]->u.integer == INT64_C(4294967296));
|
|
SS_CHECK(wide->u.array.values[1]->u.integer == INT64_MAX);
|
|
SS_CHECK(wide->u.array.values[2]->u.integer == -INT64_C(4294967296));
|
|
SS_CHECK(wide->u.array.values[3]->u.dbl > 0.4294967295 && wide->u.array.values[3]->u.dbl < 0.4294967297);
|
|
json_value_free(wide);
|
|
SS_CHECK(json_parse("9223372036854775808", 19) == nullptr);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main()
|
|
{
|
|
SS_RUN(test_parse_wide_numbers);
|
|
SS_RUN(test_parse_simple_object);
|
|
SS_RUN(test_parse_array);
|
|
SS_RUN(test_parse_nested);
|
|
SS_RUN(test_parse_types);
|
|
SS_RUN(test_parse_invalid);
|
|
SS_RUN(test_parse_truncated_escape_sequences);
|
|
SS_RUN(test_parse_truncated_literals);
|
|
SS_RUN(test_parse_empty_object);
|
|
SS_RUN(test_parse_empty_array);
|
|
return 0;
|
|
}
|