From fc8c9a6c7bec176299915c6adab120e1bf2ea4e9 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 1 May 2021 17:28:44 +0100 Subject: Lots of test cases, few minor fixes --- lib/jsonParse.impl.cpp | 5 ++- lib/jsonParse.ll | 8 ++-- lib/persistence.cpp | 2 + test/Jamfile.jam | 2 +- test/fixtures/json/bad/bad.json | 1 + test/fixtures/json/bad/empty_abs.json | 6 +++ test/fixtures/json/bad/implicit_abs.json | 8 ++++ test/fixtures/json/bad/late_type.json | 4 ++ test/fixtures/json/bad/missing_member.json | 3 ++ test/fixtures/json/bad/not.json | 1 + test/fixtures/json/bad/unexp_array.json | 3 ++ test/fixtures/json/bad/unexp_bool.json | 3 ++ test/fixtures/json/bad/unexp_float.json | 3 ++ test/fixtures/json/bad/unexp_null.json | 3 ++ test/fixtures/json/bad/unexp_obj.json | 3 ++ test/fixtures/json/bad/unexp_str.json | 3 ++ test/fixtures/json/empty_abs.json | 6 --- test/fixtures/json/implicit.json | 3 +- test/fixtures/json/implicit_abs.json | 8 ---- test/fixtures/json/shared_ptr_null.json | 8 ++++ test/test-persistence.cpp | 62 +++++++++++++++++++++++++++--- 21 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 test/fixtures/json/bad/bad.json create mode 100644 test/fixtures/json/bad/empty_abs.json create mode 100644 test/fixtures/json/bad/implicit_abs.json create mode 100644 test/fixtures/json/bad/late_type.json create mode 100644 test/fixtures/json/bad/missing_member.json create mode 100644 test/fixtures/json/bad/not.json create mode 100644 test/fixtures/json/bad/unexp_array.json create mode 100644 test/fixtures/json/bad/unexp_bool.json create mode 100644 test/fixtures/json/bad/unexp_float.json create mode 100644 test/fixtures/json/bad/unexp_null.json create mode 100644 test/fixtures/json/bad/unexp_obj.json create mode 100644 test/fixtures/json/bad/unexp_str.json delete mode 100644 test/fixtures/json/empty_abs.json delete mode 100644 test/fixtures/json/implicit_abs.json create mode 100644 test/fixtures/json/shared_ptr_null.json diff --git a/lib/jsonParse.impl.cpp b/lib/jsonParse.impl.cpp index 3ed8e62..4d13eae 100644 --- a/lib/jsonParse.impl.cpp +++ b/lib/jsonParse.impl.cpp @@ -12,7 +12,7 @@ json::jsonParser::LexerError(const char * msg) void json::jsonParser::appendEscape(const char * cphs, std::string & str) { - appendEscape(std::strtoul(cphs, nullptr, 16), str); + appendEscape(std::strtoul(cphs + 1, nullptr, 16), str); } void @@ -39,4 +39,7 @@ json::jsonParser::appendEscape(unsigned long cp, std::string & str) str += char(((cp >> 6) & 63) + 128); str += char((cp & 63) + 128); } + else { + throw std::range_error("Invalid UTF-8 sequence"); + } } diff --git a/lib/jsonParse.ll b/lib/jsonParse.ll index 52ad89f..c9c708c 100644 --- a/lib/jsonParse.ll +++ b/lib/jsonParse.ll @@ -17,6 +17,7 @@ class jsonBaseFlexLexer; #ifdef __clang__ #pragma clang diagnostic ignored "-Wnull-conversion" #endif +[[maybe_unused]]static constexpr auto x=getpid; %} beginobj "{" @@ -152,7 +153,6 @@ text [^\\\"]* <*>[ \t\r\n\f] { } -%% - -// Make iwyu think unistd.h is required -[[maybe_unused]]static auto x=getpid; +<*>. { + LexerError("Unexpected input"); +} diff --git a/lib/persistence.cpp b/lib/persistence.cpp index 5744cd7..15391ad 100644 --- a/lib/persistence.cpp +++ b/lib/persistence.cpp @@ -62,6 +62,7 @@ namespace Persistence { throw std::runtime_error("Unexpected object"); } + /// LCOV_EXCL_START Don't think we can trigger these from something lexer will parse void Selection::beforeValue(Stack &) { @@ -78,4 +79,5 @@ namespace Persistence { Selection::endObject(Stack &) { } + /// LCOV_EXCL_STOP } diff --git a/test/Jamfile.jam b/test/Jamfile.jam index 2c09b8a..8a9843c 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -19,4 +19,4 @@ run test-collection.cpp ; run test-obj.cpp ; run test-maths.cpp ; run test-network.cpp ; -run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob fixtures/json/*.json ] ] ; +run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob fixtures/json/*.json fixtures/json/bad/*.json ] ] ; diff --git a/test/fixtures/json/bad/bad.json b/test/fixtures/json/bad/bad.json new file mode 100644 index 0000000..8c611b1 --- /dev/null +++ b/test/fixtures/json/bad/bad.json @@ -0,0 +1 @@ +{ bad } diff --git a/test/fixtures/json/bad/empty_abs.json b/test/fixtures/json/bad/empty_abs.json new file mode 100644 index 0000000..7d22001 --- /dev/null +++ b/test/fixtures/json/bad/empty_abs.json @@ -0,0 +1,6 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "aptr": {}, + "str": "after" +} diff --git a/test/fixtures/json/bad/implicit_abs.json b/test/fixtures/json/bad/implicit_abs.json new file mode 100644 index 0000000..573b323 --- /dev/null +++ b/test/fixtures/json/bad/implicit_abs.json @@ -0,0 +1,8 @@ +{ + "@typeid": "TestObject", + "flt": 1, + "aptr": { + "str": "trigger" + }, + "str": "after" +} diff --git a/test/fixtures/json/bad/late_type.json b/test/fixtures/json/bad/late_type.json new file mode 100644 index 0000000..171575a --- /dev/null +++ b/test/fixtures/json/bad/late_type.json @@ -0,0 +1,4 @@ +{ + "str": "trigger", + "@typeid": "doesn't matter" +} diff --git a/test/fixtures/json/bad/missing_member.json b/test/fixtures/json/bad/missing_member.json new file mode 100644 index 0000000..0c8a1fd --- /dev/null +++ b/test/fixtures/json/bad/missing_member.json @@ -0,0 +1,3 @@ +{ + "missing": true +} diff --git a/test/fixtures/json/bad/not.json b/test/fixtures/json/bad/not.json new file mode 100644 index 0000000..6b7a9f4 --- /dev/null +++ b/test/fixtures/json/bad/not.json @@ -0,0 +1 @@ +not json diff --git a/test/fixtures/json/bad/unexp_array.json b/test/fixtures/json/bad/unexp_array.json new file mode 100644 index 0000000..399a2bd --- /dev/null +++ b/test/fixtures/json/bad/unexp_array.json @@ -0,0 +1,3 @@ +{ + "bl": [] +} diff --git a/test/fixtures/json/bad/unexp_bool.json b/test/fixtures/json/bad/unexp_bool.json new file mode 100644 index 0000000..85a4bd1 --- /dev/null +++ b/test/fixtures/json/bad/unexp_bool.json @@ -0,0 +1,3 @@ +{ + "str": true +} diff --git a/test/fixtures/json/bad/unexp_float.json b/test/fixtures/json/bad/unexp_float.json new file mode 100644 index 0000000..bd824b6 --- /dev/null +++ b/test/fixtures/json/bad/unexp_float.json @@ -0,0 +1,3 @@ +{ + "bl": 3.14 +} diff --git a/test/fixtures/json/bad/unexp_null.json b/test/fixtures/json/bad/unexp_null.json new file mode 100644 index 0000000..2edc363 --- /dev/null +++ b/test/fixtures/json/bad/unexp_null.json @@ -0,0 +1,3 @@ +{ + "str": null +} diff --git a/test/fixtures/json/bad/unexp_obj.json b/test/fixtures/json/bad/unexp_obj.json new file mode 100644 index 0000000..6331897 --- /dev/null +++ b/test/fixtures/json/bad/unexp_obj.json @@ -0,0 +1,3 @@ +{ + "str": {} +} diff --git a/test/fixtures/json/bad/unexp_str.json b/test/fixtures/json/bad/unexp_str.json new file mode 100644 index 0000000..45ac749 --- /dev/null +++ b/test/fixtures/json/bad/unexp_str.json @@ -0,0 +1,3 @@ +{ + "bl": "3.14" +} diff --git a/test/fixtures/json/empty_abs.json b/test/fixtures/json/empty_abs.json deleted file mode 100644 index 7d22001..0000000 --- a/test/fixtures/json/empty_abs.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "@typeid": "TestObject", - "flt": 1, - "aptr": {}, - "str": "after" -} diff --git a/test/fixtures/json/implicit.json b/test/fixtures/json/implicit.json index 03dec4b..478cec6 100644 --- a/test/fixtures/json/implicit.json +++ b/test/fixtures/json/implicit.json @@ -2,7 +2,8 @@ "@typeid": "TestObject", "flt": 1, "ptr": { - "str": "trigger" + "str": "trigger", + "bl": false }, "str": "after" } diff --git a/test/fixtures/json/implicit_abs.json b/test/fixtures/json/implicit_abs.json deleted file mode 100644 index 573b323..0000000 --- a/test/fixtures/json/implicit_abs.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "@typeid": "TestObject", - "flt": 1, - "aptr": { - "str": "trigger" - }, - "str": "after" -} diff --git a/test/fixtures/json/shared_ptr_null.json b/test/fixtures/json/shared_ptr_null.json new file mode 100644 index 0000000..c2461e8 --- /dev/null +++ b/test/fixtures/json/shared_ptr_null.json @@ -0,0 +1,8 @@ +{ + "@typeid": "SharedTestObject", + "sptr": { + "@typeid": "SubObject", + "@id": "someid" + }, + "ssptr": null +} diff --git a/test/test-persistence.cpp b/test/test-persistence.cpp index d5910e9..6dcb94d 100644 --- a/test/test-persistence.cpp +++ b/test/test-persistence.cpp @@ -1,5 +1,6 @@ #define BOOST_TEST_MODULE test_persistence +#include #include #include @@ -63,7 +64,7 @@ struct TestObject : public Persistence::Persistable { struct JPP : public Persistence::JsonParsePersistence { template T - load_json(const char * path) + load_json(const std::filesystem::path & path) { BOOST_TEST_CONTEXT(path) { std::ifstream ss {path}; @@ -147,14 +148,16 @@ BOOST_FIXTURE_TEST_CASE(load_empty_object, JPP) BOOST_CHECK_EQUAL(to->str, "after"); } -BOOST_FIXTURE_TEST_CASE(fail_implicit_abs_object, JPP) +static std::vector +fixtures_in(const std::filesystem::path & root) { - BOOST_CHECK_THROW(load_json>(FIXTURESDIR "json/implicit_abs.json"), std::runtime_error); + return {std::filesystem::directory_iterator {root}, {}}; } -BOOST_FIXTURE_TEST_CASE(fail_empty_abs_object, JPP) +BOOST_DATA_TEST_CASE_F(JPP, various_parse_failures, fixtures_in(FIXTURESDIR "json/bad"), path) { - BOOST_CHECK_THROW(load_json>(FIXTURESDIR "json/empty_abs.json"), std::runtime_error); + std::ifstream ss {path}; + BOOST_CHECK_THROW(loadState>(ss), std::runtime_error); } BOOST_FIXTURE_TEST_CASE(load_abs_object, JPP) @@ -211,3 +214,52 @@ BOOST_FIXTURE_TEST_CASE(load_shared_object2, JPP) BOOST_CHECK_EQUAL(to->sptr.use_count(), 2); BOOST_CHECK_EQUAL(to->ssptr.use_count(), 2); } + +BOOST_FIXTURE_TEST_CASE(load_shared_object_null, JPP) +{ + auto to = load_json>(FIXTURESDIR "json/shared_ptr_null.json"); + BOOST_CHECK(to->sptr); + BOOST_CHECK(!to->ssptr); +} + +using svs = std::tuple; +BOOST_DATA_TEST_CASE_F(JPP, load_strings, + boost::unit_test::data::make({ + {R"J("")J", ""}, + {R"J("non empty")J", "non empty"}, + {R"J("new\nline")J", "new\nline"}, + {R"J("quote\"mark")J", "quote\"mark"}, + {R"J("tab\t")J", "tab\t"}, + {R"J("back\bspace?")J", "back\bspace?"}, + {R"J("form\ffeed?")J", "form\ffeed?"}, + {R"J("forward\/slash")J", "forward/slash"}, + {R"J("\u00a5 yen")J", "¥ yen"}, + {R"J("gbp \u00a3")J", "gbp £"}, + {R"J("\u007E tilde")J", "~ tilde"}, + {R"J("\u056b ARMENIAN SMALL LETTER INI")J", "ի ARMENIAN SMALL LETTER INI"}, + {R"J("\u0833 SAMARITAN PUNCTUATION BAU")J", "࠳ SAMARITAN PUNCTUATION BAU"}, + }), + in, exp) +{ + std::stringstream str {in}; + BOOST_CHECK_EQUAL(loadState(str), exp); +} + +using cpstr = std::tuple; +BOOST_DATA_TEST_CASE(utf8_decode, + boost::unit_test::data::make({ + {9, "\t"}, + {0x00010000, "𐀀"}, + }), + cp, str) +{ + std::string out; + BOOST_CHECK_NO_THROW(json::jsonParser::appendEscape(cp, out)); + BOOST_CHECK_EQUAL(out, str); +} + +BOOST_DATA_TEST_CASE(utf8_decode_bad, boost::unit_test::data::make({0xd800, 0xdfff, 0x110000}), cp) +{ + std::string out; + BOOST_CHECK_THROW(json::jsonParser::appendEscape(cp, out), std::runtime_error); +} -- cgit v1.2.3