#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "matchers.h" using namespace jvalidate::detail; using JsonCppAdapter = jvalidate::adapter::JsonCppAdapter; using jvalidate::adapter::Type; using testing::Eq; using testing::Test; using testing::ThrowsMessage; using testing::Types; using testing::VariantWith; TEST(AnchorTest, PermitsEmpty) { EXPECT_NO_THROW(Anchor("")); } TEST(AnchorTest, PermitsFirstCharWord) { EXPECT_NO_THROW(Anchor("here")); } TEST(AnchorTest, PermitsFirstCharUnderscore) { EXPECT_NO_THROW(Anchor("_here")); } TEST(AnchorTest, ForbidsFirstCharNumber) { EXPECT_THROW(Anchor("0here"), std::runtime_error); } TEST(AnchorTest, AllowsDotDashAlnum) { EXPECT_NO_THROW(Anchor("here.0-_")); } TEST(AnchorTest, ForbidsSpecial) { EXPECT_THROW(Anchor("h$"), std::runtime_error); } TEST(AnchorTest, CanViewString) { EXPECT_THAT(static_cast(Anchor("here")), "here"); } TEST(AnchorTest, Print) { EXPECT_THAT(testing::PrintToString(Anchor("here")), "here"); } TEST(PointerTest, BackCoercesIntToString) { EXPECT_THAT("/0"_jptr.back(), "0"); EXPECT_THAT("/A"_jptr.back(), "A"); } TEST(PointerTest, BackIsEmptySafe) { EXPECT_THAT(""_jptr.back(), ""); } TEST(PointerTest, ForbidsBadTilde) { EXPECT_NO_THROW("/~1"_jptr); EXPECT_THROW("/~2"_jptr, std::runtime_error); } TEST(PointerTest, CanConcatenate) { EXPECT_THAT("/A"_jptr / "/B"_jptr, "/A/B"_jptr); } TEST(PointerTest, CanGoToParent) { EXPECT_THAT("/A/B"_jptr / parent, "/A"_jptr); } TEST(PointerTest, Print) { EXPECT_THAT(testing::PrintToString(Pointer("/B/0/A")), "/B/0/A"); } TEST(RelatvivePointerTest, CannotPrefixWithZero) { EXPECT_THROW(RelativePointer("01"), std::runtime_error); } TEST(RelatvivePointerTest, Print) { EXPECT_THAT(testing::PrintToString(RelativePointer("0")), "0"); EXPECT_THAT(testing::PrintToString(RelativePointer("1#")), "1#"); EXPECT_THAT(testing::PrintToString(RelativePointer("1/B/0/A")), "1/B/0/A"); } TEST(RelatvivePointerTest, ZeroIsHere) { Json::Value json; json["A"] = 1; RelativePointer const rel("0"); EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)), VariantWith(JsonCppAdapter(json["A"]))) << rel; } TEST(RelatvivePointerTest, CanWalkBackwards) { Json::Value json; json["A"] = 1; RelativePointer const rel("1"); EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)), VariantWith(JsonCppAdapter(json))) << rel; } TEST(RelatvivePointerTest, CanFetchKey) { Json::Value json; json["A"] = 1; RelativePointer const rel("0#"); EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)), VariantWith(Eq("A"))) << rel; } TEST(RelatvivePointerTest, CanGoUpAndDown) { Json::Value json; json["A"] = 1; json["B"] = 2; RelativePointer const rel("1/B"); EXPECT_THAT(rel.inspect("/A"_jptr, JsonCppAdapter(json)), VariantWith(JsonCppAdapter(json["B"]))) << rel; } TEST(ReferenceTest, Print) { EXPECT_THAT(testing::PrintToString(Reference(jvalidate::URI("file://path/to/document.json"), Anchor("Anchor"), Pointer("/key/1/id"))), "file://path/to/document.json#Anchor/key/1/id"); } TEST(ReferenceTest, RelativeBasedOnURIRelative) { { jvalidate::URI uri("file://path/to/document.json"); EXPECT_FALSE(uri.is_relative()); EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative()); } { jvalidate::URI uri("/path/to/document.json"); EXPECT_FALSE(uri.is_relative()); EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative()); } { jvalidate::URI uri("path/to/document.json"); EXPECT_TRUE(uri.is_relative()); EXPECT_THAT(RootReference(uri).is_relative(), uri.is_relative()); } } template class NumberFromStrTest : public Test {}; using Integers = Types; TYPED_TEST_SUITE(NumberFromStrTest, Integers); TEST(NumberTest, ULLFitsInInteger) { EXPECT_TRUE(fits_in_integer(9223372036854775807ULL)); EXPECT_FALSE(fits_in_integer(9223372036854775808ULL)); } TEST(NumberTest, DoubleDoesNotFitInIntegerWhenFractional) { EXPECT_FALSE(fits_in_integer(10.5)); } TEST(NumberTest, DoubleFitsInIntegerWhenWhole) { EXPECT_TRUE(fits_in_integer(10.0)); } TEST(NumberTest, DoubleOutOfIntegerRange) { EXPECT_FALSE(fits_in_integer(10000000000000000000.0)); EXPECT_FALSE(fits_in_integer(-10000000000000000000.0)); } TYPED_TEST(NumberFromStrTest, NumberParsesIntegers) { EXPECT_THAT(from_str("10"), 10); } TYPED_TEST(NumberFromStrTest, NumberParsesNegativeIntegers) { if constexpr (std::is_signed_v) { EXPECT_THAT(from_str("-10"), -10); } else { EXPECT_THAT([] { from_str("-10"); }, ThrowsMessage("Invalid argument")); } } TYPED_TEST(NumberFromStrTest, ThrowsOnPlusSign) { EXPECT_THAT([] { from_str("+10"); }, ThrowsMessage("Invalid argument")); } TYPED_TEST(NumberFromStrTest, ThrowsOnTooManyChars) { EXPECT_THAT([] { from_str("10 coconuts"); }, ThrowsMessage("NaN: 10 coconuts")); } TYPED_TEST(NumberFromStrTest, ThrowsOnOutOfRange) { EXPECT_THAT([] { from_str("99999999999999999999999999999"); }, ThrowsMessage("Result too large")); } TEST(StringAdapterTest, IsStringy) { EXPECT_THAT(StringAdapter("").type(), Type::String); EXPECT_THAT(StringAdapter("lorem ipsum").as_string(), "lorem ipsum"); } TEST(StringAdapterTest, DiesOnAccess) { EXPECT_THROW(StringAdapter("").as_boolean(), std::runtime_error); EXPECT_THROW(StringAdapter("").as_integer(), std::runtime_error); EXPECT_THROW(StringAdapter("").as_number(), std::runtime_error); EXPECT_THROW(StringAdapter("").as_array(), std::runtime_error); EXPECT_THROW(StringAdapter("").array_size(), std::runtime_error); EXPECT_THROW(StringAdapter("").as_object(), std::runtime_error); EXPECT_THROW(StringAdapter("").object_size(), std::runtime_error); } TEST(StringAdapterTest, DoesNotRunApplyArray) { StringAdapter("").apply_array([](auto const &) { ADD_FAILURE(); return jvalidate::Status::Noop; }); } TEST(StringAdapterTest, DoesNotRunApplyObject) { StringAdapter("").apply_object([](auto const &, auto const &) { ADD_FAILURE(); return jvalidate::Status::Noop; }); } TEST(UnsupportedArrayAdapterTest, Empty) { UnsupportedArrayAdapter array; EXPECT_THAT(array.size(), 0); EXPECT_THAT(array.begin(), array.end()); } TEST(UnsupportedArrayAdapterTest, DiesWhenIndexed) { UnsupportedArrayAdapter array; EXPECT_THROW(array[0], std::runtime_error); } TEST(UnsupportedObjectAdapterTest, Empty) { UnsupportedObjectAdapter object; EXPECT_THAT(object.size(), 0); EXPECT_THAT(object.begin(), object.end()); } TEST(UnsupportedObjectAdapterTest, DiesWhenIndexed) { UnsupportedObjectAdapter object; EXPECT_FALSE(object.contains("")); EXPECT_THROW(object[""], std::runtime_error); } #if JVALIDATE_HAS_ICU TEST(StringLengthTest, MultiCharLength) { // Dragon Emoji from non-bmp-regex test case EXPECT_THAT(length("\xF0\x9F\x90\xB2"), 1); } #endif #if !defined(JVALIDATE_MONOTEST) int main(int argc, char ** argv) { testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); } #endif