#include #include #include namespace VFS::Path { namespace { using namespace testing; template struct TypePair { using Type0 = T0; using Type1 = T1; }; struct VFSPathIsNormalizedTest : TestWithParam> { }; TEST_P(VFSPathIsNormalizedTest, shouldReturnExpectedResult) { EXPECT_EQ(isNormalized(GetParam().first), GetParam().second); } const std::pair isNormalizedTestParams[] = { { std::string_view(), true }, { "foo", true }, { "foo/bar", true }, { "foo/bar/baz", true }, { "/foo", false }, { "foo//", false }, { "foo\\", false }, { "Foo", false }, }; INSTANTIATE_TEST_SUITE_P(IsNormalizedTestParams, VFSPathIsNormalizedTest, ValuesIn(isNormalizedTestParams)); TEST(VFSPathNormalizeFilenameInPlaceTest, shouldRemoveLeadingSeparators) { std::string value("//foo"); normalizeFilenameInPlace(value); EXPECT_EQ(value, "foo"); } TEST(VFSPathNormalizeFilenameInPlaceTest, shouldRemoveDuplicatedSeparators) { std::string value("foo//bar///baz"); normalizeFilenameInPlace(value); EXPECT_EQ(value, "foo/bar/baz"); } TEST(VFSPathNormalizeFilenameInPlaceTest, shouldRemoveDuplicatedLeadingSeparator) { std::string value("//foo"); normalizeFilenameInPlace(value); EXPECT_EQ(value, "foo"); } TEST(VFSPathExtensionViewTest, shouldSupportDefaultConstructor) { constexpr ExtensionView extension; EXPECT_TRUE(extension.empty()); EXPECT_EQ(extension.value(), ""); } TEST(VFSPathExtensionViewTest, shouldSupportConstexprConstructorFromConstCharPtr) { constexpr ExtensionView extension("png"); EXPECT_FALSE(extension.empty()); EXPECT_EQ(extension.value(), "png"); } TEST(VFSPathExtensionViewTest, constructorShouldThrowExceptionOnNotNormalizedValue) { EXPECT_THROW([] { ExtensionView("PNG"); }(), std::invalid_argument); } TEST(VFSPathExtensionViewTest, constructorShouldThrowExceptionIfValueContainsExtensionSeparator) { EXPECT_THROW([] { ExtensionView(".png"); }(), std::invalid_argument); } TEST(VFSPathExtensionViewTest, constructorShouldThrowExceptionIfValueContainsSeparator) { EXPECT_THROW([] { ExtensionView("/png"); }(), std::invalid_argument); } template struct VFSPathExtensionViewOperatorsTest : Test { }; TYPED_TEST_SUITE_P(VFSPathExtensionViewOperatorsTest); TYPED_TEST_P(VFSPathExtensionViewOperatorsTest, supportsEqual) { using Type0 = typename TypeParam::Type0; using Type1 = typename TypeParam::Type1; const Type0 extension{ "png" }; const Type1 otherEqual{ "png" }; const Type1 otherNotEqual{ "jpg" }; EXPECT_EQ(extension, otherEqual); EXPECT_EQ(otherEqual, extension); EXPECT_NE(extension, otherNotEqual); EXPECT_NE(otherNotEqual, extension); } TYPED_TEST_P(VFSPathExtensionViewOperatorsTest, supportsLess) { using Type0 = typename TypeParam::Type0; using Type1 = typename TypeParam::Type1; const Type0 extension{ "png" }; const Type1 otherEqual{ "png" }; const Type1 otherLess{ "jpg" }; const Type1 otherGreater{ "tga" }; EXPECT_FALSE(extension < otherEqual); EXPECT_FALSE(otherEqual < extension); EXPECT_LT(otherLess, extension); EXPECT_FALSE(extension < otherLess); EXPECT_LT(extension, otherGreater); EXPECT_FALSE(otherGreater < extension); } REGISTER_TYPED_TEST_SUITE_P(VFSPathExtensionViewOperatorsTest, supportsEqual, supportsLess); using VFSPathExtensionViewOperatorsTypePairs = Types, TypePair, TypePair, TypePair>; INSTANTIATE_TYPED_TEST_SUITE_P( Typed, VFSPathExtensionViewOperatorsTest, VFSPathExtensionViewOperatorsTypePairs); TEST(VFSPathNormalizedTest, shouldSupportDefaultConstructor) { const Normalized value; EXPECT_EQ(value.value(), ""); } TEST(VFSPathNormalizedTest, shouldSupportConstructorFromString) { const std::string string("Foo\\Bar/baz"); const Normalized value(string); EXPECT_EQ(value.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportConstructorFromConstCharPtr) { const char* const ptr = "Foo\\Bar/baz"; const Normalized value(ptr); EXPECT_EQ(value.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportConstructorFromStringView) { const std::string_view view = "Foo\\Bar/baz"; const Normalized value(view); EXPECT_EQ(value.view(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportConstructorFromNormalizedView) { const NormalizedView view("foo/bar/baz"); const Normalized value(view); EXPECT_EQ(value.view(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, supportMovingValueOut) { Normalized value("Foo\\Bar/baz"); EXPECT_EQ(std::move(value).value(), "foo/bar/baz"); EXPECT_EQ(value.value(), ""); } TEST(VFSPathNormalizedTest, isNotEqualToNotNormalized) { const Normalized value("Foo\\Bar/baz"); EXPECT_NE(value.value(), "Foo\\Bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportOperatorLeftShiftToOStream) { const Normalized value("Foo\\Bar/baz"); std::stringstream stream; stream << value; EXPECT_EQ(stream.str(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportOperatorDivEqual) { Normalized value("foo/bar"); value /= NormalizedView("baz"); EXPECT_EQ(value.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, shouldSupportOperatorDivEqualWithStringView) { Normalized value("foo/bar"); value /= std::string_view("BAZ"); EXPECT_EQ(value.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedTest, operatorDivShouldNormalizeSuffix) { Normalized value("foo/bar"); value /= std::string_view("\\A\\\\B"); EXPECT_EQ(value.value(), "foo/bar/a/b"); } TEST(VFSPathNormalizedTest, changeExtensionShouldReplaceAfterLastDot) { Normalized value("foo/ba.r.a"); constexpr ExtensionView extension("so"); ASSERT_TRUE(value.changeExtension(extension)); EXPECT_EQ(value.value(), "foo/ba.r.so"); } TEST(VFSPathNormalizedTest, changeExtensionShouldIgnorePathWithoutADot) { Normalized value("foo/bar"); constexpr ExtensionView extension("so"); ASSERT_FALSE(value.changeExtension(extension)); EXPECT_EQ(value.value(), "foo/bar"); } TEST(VFSPathNormalizedTest, changeExtensionShouldIgnorePathWithDotBeforeSeparator) { Normalized value("foo.bar/baz"); constexpr ExtensionView extension("so"); ASSERT_FALSE(value.changeExtension(extension)); EXPECT_EQ(value.value(), "foo.bar/baz"); } TEST(VFSPathNormalizedTest, changeExtensionShouldReplaceWithShorterExtension) { Normalized value("foo/bar.nif"); constexpr ExtensionView extension("kf"); ASSERT_TRUE(value.changeExtension(extension)); EXPECT_EQ(value.value(), "foo/bar.kf"); } TEST(VFSPathNormalizedTest, filenameShouldReturnLastComponentOfThePath) { const Normalized value("foo/bar"); EXPECT_EQ(value.filename(), "bar"); } TEST(VFSPathNormalizedTest, filenameShouldReturnSameValueForPathWithSingleComponent) { const Normalized value("foo"); EXPECT_EQ(value.filename(), "foo"); } template struct VFSPathNormalizedOperatorsTest : Test { }; TYPED_TEST_SUITE_P(VFSPathNormalizedOperatorsTest); TYPED_TEST_P(VFSPathNormalizedOperatorsTest, supportsEqual) { using Type0 = typename TypeParam::Type0; using Type1 = typename TypeParam::Type1; const Type0 normalized{ "a/foo/bar/baz" }; const Type1 otherEqual{ "a/foo/bar/baz" }; const Type1 otherNotEqual{ "b/foo/bar/baz" }; EXPECT_EQ(normalized, otherEqual); EXPECT_EQ(otherEqual, normalized); EXPECT_NE(normalized, otherNotEqual); EXPECT_NE(otherNotEqual, normalized); } TYPED_TEST_P(VFSPathNormalizedOperatorsTest, supportsLess) { using Type0 = typename TypeParam::Type0; using Type1 = typename TypeParam::Type1; const Type0 normalized{ "b/foo/bar/baz" }; const Type1 otherEqual{ "b/foo/bar/baz" }; const Type1 otherLess{ "a/foo/bar/baz" }; const Type1 otherGreater{ "c/foo/bar/baz" }; EXPECT_FALSE(normalized < otherEqual); EXPECT_FALSE(otherEqual < normalized); EXPECT_LT(otherLess, normalized); EXPECT_FALSE(normalized < otherLess); EXPECT_LT(normalized, otherGreater); EXPECT_FALSE(otherGreater < normalized); } REGISTER_TYPED_TEST_SUITE_P(VFSPathNormalizedOperatorsTest, supportsEqual, supportsLess); using VFSPathNormalizedOperatorsTypePairs = Types, TypePair, TypePair, TypePair, TypePair, TypePair, TypePair, TypePair, TypePair, TypePair>; INSTANTIATE_TYPED_TEST_SUITE_P(Typed, VFSPathNormalizedOperatorsTest, VFSPathNormalizedOperatorsTypePairs); TEST(VFSPathNormalizedViewTest, shouldSupportConstructorFromNormalized) { const Normalized value("Foo\\Bar/baz"); const NormalizedView view(value); EXPECT_EQ(view.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedViewTest, shouldSupportConstexprConstructorFromNormalizedStringLiteral) { constexpr NormalizedView view("foo/bar/baz"); EXPECT_EQ(view.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedViewTest, constructorShouldThrowExceptionOnNotNormalized) { EXPECT_THROW([] { NormalizedView("Foo\\Bar/baz"); }(), std::invalid_argument); } TEST(VFSPathNormalizedViewTest, shouldSupportOperatorDiv) { const NormalizedView a("foo/bar"); const NormalizedView b("baz"); const Normalized result = a / b; EXPECT_EQ(result.value(), "foo/bar/baz"); } TEST(VFSPathNormalizedViewTest, filenameShouldReturnLastComponentOfThePath) { const NormalizedView value("foo/bar"); EXPECT_EQ(value.filename(), "bar"); } TEST(VFSPathNormalizedViewTest, filenameShouldReturnSameValueForPathWithSingleComponent) { const NormalizedView value("foo"); EXPECT_EQ(value.filename(), "foo"); } TEST(VFSPathNormalizedViewTest, stemShouldOmitPathAndExtension) { const NormalizedView value("foo/bar.a"); EXPECT_EQ(value.stem(), "bar"); } TEST(VFSPathNormalizedViewTest, stemShouldReturnSameValueForPathWithSingleComponent) { const NormalizedView value("foo"); EXPECT_EQ(value.stem(), "foo"); } TEST(VFSPathNormalizedViewTest, stemShouldIncludeDotsBeforeTheExtension) { const NormalizedView value("last voyage of the u.s.s. constitution.swf"); EXPECT_EQ(value.stem(), "last voyage of the u.s.s. constitution"); } } }