diff --git a/include/rfl/cbor/read.hpp b/include/rfl/cbor/read.hpp index 9e8247ad..1939b1f9 100644 --- a/include/rfl/cbor/read.hpp +++ b/include/rfl/cbor/read.hpp @@ -21,30 +21,24 @@ using InputVarType = typename Reader::InputVarType; template Result> read( const concepts::ContiguousByteContainer auto& _bytes) { - try { - auto val = jsoncons::cbor::decode_cbor(_bytes); + auto result = jsoncons::cbor::try_decode_cbor(_bytes); + if (result.has_value()) { auto r = Reader(); - return Parser>::read(r, InputVarType{&val}); - } catch (const jsoncons::ser_error& e) { - std::string error("Could not parse CBOR: "); - error.append(e.what()); - return rfl::error(error); + return Parser>::read(r, InputVarType{&result.value()}); + } else { + return rfl::error("Could not parse CBOR: " + result.error().message()); } } /// Parses an object from a stream. template Result> read(std::istream& _stream) { - // TODO: Use a non-throwing decode_cbor(), pending - // https://github.com/danielaparker/jsoncons/issues/615 - try { - auto val = jsoncons::cbor::decode_cbor(_stream); + auto result = jsoncons::cbor::try_decode_cbor(_stream); + if (result.has_value()) { auto r = Reader(); - return Parser>::read(r, InputVarType{&val}); - } catch (const jsoncons::ser_error& e) { - std::string error("Could not parse CBOR: "); - error.append(e.what()); - return rfl::error(error); + return Parser>::read(r, InputVarType{&result.value()}); + } else { + return rfl::error("Could not parse CBOR: " + result.error().message()); } } diff --git a/include/rfl/ubjson/read.hpp b/include/rfl/ubjson/read.hpp index 7374906e..3f257693 100644 --- a/include/rfl/ubjson/read.hpp +++ b/include/rfl/ubjson/read.hpp @@ -22,32 +22,24 @@ using InputVarType = typename Reader::InputVarType; template Result> read( const concepts::ContiguousByteContainer auto& _bytes) { - // TODO: Use a non-throwing decode_ubjson(), pending - // https://github.com/danielaparker/jsoncons/issues/615 - try { - auto val = jsoncons::ubjson::decode_ubjson(_bytes); + auto result = jsoncons::ubjson::try_decode_ubjson(_bytes); + if (result.has_value()) { auto r = Reader(); - return Parser>::read(r, InputVarType{&val}); - } catch (const jsoncons::ser_error& e) { - std::string error("Could not parse UBJSON: "); - error.append(e.what()); - return rfl::error(error); + return Parser>::read(r, InputVarType{&result.value()}); + } else { + return rfl::error("Could not parse UBJSON: " + result.error().message()); } } /// Parses an object from a stream. template Result> read(std::istream& _stream) { - // TODO: Use a non-throwing decode_ubjson(), pending - // https://github.com/danielaparker/jsoncons/issues/615 - try { - auto val = jsoncons::ubjson::decode_ubjson(_stream); + auto result = jsoncons::ubjson::try_decode_ubjson(_stream); + if (result.has_value()) { auto r = Reader(); - return Parser>::read(r, InputVarType{&val}); - } catch (const jsoncons::ser_error& e) { - std::string error("Could not parse UBJSON: "); - error.append(e.what()); - return rfl::error(error); + return Parser>::read(r, InputVarType{&result.value()}); + } else { + return rfl::error("Could not parse UBJSON: " + result.error().message()); } } diff --git a/tests/README.md b/tests/README.md index 8a2af281..c4eaee6c 100644 --- a/tests/README.md +++ b/tests/README.md @@ -45,7 +45,7 @@ ctest --test-dir build --output-on-failure Or you can run tests individually, as in: -``` +```shell ./build/tests/avro/reflect-cpp-avro-tests ./build/tests/bson/reflect-cpp-bson-tests ./build/tests/capnproto/reflect-cpp-capnproto-tests diff --git a/tests/cbor/test_error_messages.cpp b/tests/cbor/test_error_messages.cpp index b8155fcb..8fb063a1 100644 --- a/tests/cbor/test_error_messages.cpp +++ b/tests/cbor/test_error_messages.cpp @@ -15,12 +15,39 @@ struct Person { std::vector children; }; -TEST(cbor, test_field_error_messages) { +TEST(cbor, test_empty_field_error_messages) { + // Use JSON input to generic parser for convenient flexible test input + const std::string faulty_string = + R"({})"; + const auto faulty_generic = rfl::json::read(faulty_string); + const auto faulty_cbor = rfl::cbor::write(faulty_generic); + + rfl::Result result = rfl::error("result didn't get set"); + EXPECT_NO_THROW({ + result = rfl::cbor::read(faulty_cbor); + }); + + const std::string expected = R"(Found 4 errors: +1) Field named 'firstName' not found. +2) Field named 'lastName' not found. +3) Field named 'birthday' not found. +4) Field named 'children' not found.)"; + EXPECT_EQ(result.error().what(), expected); + + EXPECT_FALSE(result.has_value()); +} + +TEST(cbor, test_field_type_error_messages) { + // Use JSON input to generic parser for convenient flexible test input const std::string faulty_string = R"({"firstName":"Homer","lastName":12345,"birthday":"04/19/1987"})"; const auto faulty_generic = rfl::json::read(faulty_string); const auto faulty_cbor = rfl::cbor::write(faulty_generic); - const auto result = rfl::cbor::read(faulty_cbor); + + rfl::Result result = rfl::error("result didn't get set"); + EXPECT_NO_THROW({ + result = rfl::cbor::read(faulty_cbor); + }); // Order of errors is different than input JSON because rfl::Generic doesn't preserve order const std::string expected = R"(Found 3 errors: @@ -28,17 +55,15 @@ TEST(cbor, test_field_error_messages) { 2) Failed to parse field 'lastName': Could not cast to string. 3) Field named 'children' not found.)"; - EXPECT_TRUE(!result.has_value() && true); + EXPECT_FALSE(result.has_value()); EXPECT_EQ(result.error().what(), expected); } TEST(cbor, test_decode_error_without_exception) { - const std::string good_string = - R"({"firstName":"Homer","lastName":"Simpson","birthday":"1987-04-19"})"; - const auto good_generic = rfl::json::read(good_string); - auto faulty_cbor = rfl::cbor::write(good_generic); - faulty_cbor[1] = '\xff'; // Corrupt structure of CBOR encoding + const Person homer{"Homer", "Simpson", "1987-04-19"}; + auto faulty_cbor = rfl::cbor::write(homer); + faulty_cbor[1] = '\xfe'; // Corrupt structure of CBOR encoding rfl::Result result = rfl::error("result didn't get set"); EXPECT_NO_THROW({ @@ -46,14 +71,10 @@ TEST(cbor, test_decode_error_without_exception) { }); // A proposal: A generic prefix, followed by the underlying library's error output - const std::string expected = R"(Found 4 errors: -1) Field named 'firstName' not found. -2) Field named 'lastName' not found. -3) Field named 'birthday' not found. -4) Field named 'children' not found.)"; + const std::string expected = R"(Could not parse CBOR: An unknown type was found in the stream at position 1)"; EXPECT_EQ(result.error().what(), expected); - EXPECT_TRUE(!result.has_value() && true); + EXPECT_FALSE(result.has_value()); } } // namespace test_error_messages diff --git a/tests/ubjson/test_error_messages.cpp b/tests/ubjson/test_error_messages.cpp index 41fd1210..6d19f256 100644 --- a/tests/ubjson/test_error_messages.cpp +++ b/tests/ubjson/test_error_messages.cpp @@ -15,12 +15,39 @@ struct Person { std::vector children; }; -TEST(ubjson, test_field_error_messages) { +TEST(ubjson, test_empty_field_error_messages) { + // Use JSON input to generic parser for convenient flexible test input + const std::string faulty_string = + R"({})"; + const auto faulty_generic = rfl::json::read(faulty_string); + const auto faulty_ubjson = rfl::ubjson::write(faulty_generic); + + rfl::Result result = rfl::error("result didn't get set"); + EXPECT_NO_THROW({ + result = rfl::ubjson::read(faulty_ubjson); + }); + + const std::string expected = R"(Found 4 errors: +1) Field named 'firstName' not found. +2) Field named 'lastName' not found. +3) Field named 'birthday' not found. +4) Field named 'children' not found.)"; + EXPECT_EQ(result.error().what(), expected); + + EXPECT_FALSE(result.has_value()); +} + +TEST(ubjson, test_field_type_error_messages) { + // Use JSON input to generic parser for convenient flexible test input const std::string faulty_string = R"({"firstName":"Homer","lastName":12345,"birthday":"04/19/1987"})"; const auto faulty_generic = rfl::json::read(faulty_string); const auto faulty_ubjson = rfl::ubjson::write(faulty_generic); - const auto result = rfl::ubjson::read(faulty_ubjson); + + rfl::Result result = rfl::error("result didn't get set"); + EXPECT_NO_THROW({ + result = rfl::ubjson::read(faulty_ubjson); + }); // Order of errors is different than input JSON because rfl::Generic doesn't preserve order const std::string expected = R"(Found 3 errors: @@ -28,16 +55,14 @@ TEST(ubjson, test_field_error_messages) { 2) Failed to parse field 'lastName': Could not cast to string. 3) Field named 'children' not found.)"; - EXPECT_TRUE(!result.has_value() && true); + EXPECT_FALSE(result.has_value()); EXPECT_EQ(result.error().what(), expected); } TEST(ubjson, test_decode_error_without_exception) { - const std::string good_string = - R"({"firstName":"Homer","lastName":"Simpson","birthday":"1987-04-19"})"; - const auto good_generic = rfl::json::read(good_string); - auto faulty_ubjson = rfl::ubjson::write(good_generic); + const Person homer{"Homer", "Simpson", "1987-04-19"}; + auto faulty_ubjson = rfl::ubjson::write(homer); faulty_ubjson[0] = '\xff'; // Corrupt structure of ubjson encoding rfl::Result result = rfl::error("result didn't get set"); @@ -49,7 +74,7 @@ TEST(ubjson, test_decode_error_without_exception) { const std::string expected = R"(Could not parse UBJSON: Unknown type at position 1)"; EXPECT_EQ(result.error().what(), expected); - EXPECT_TRUE(!result.has_value() && true); + EXPECT_FALSE(result.has_value()); } } // namespace test_error_messages