mirror of https://github.com/OpenMW/openmw
343 lines
12 KiB
C++
343 lines
12 KiB
C++
#include <components/vfs/pathutil.hpp>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <sstream>
|
|
|
|
namespace VFS::Path
|
|
{
|
|
namespace
|
|
{
|
|
using namespace testing;
|
|
|
|
template <class T0, class T1>
|
|
struct TypePair
|
|
{
|
|
using Type0 = T0;
|
|
using Type1 = T1;
|
|
};
|
|
|
|
struct VFSPathIsNormalizedTest : TestWithParam<std::pair<std::string_view, bool>>
|
|
{
|
|
};
|
|
|
|
TEST_P(VFSPathIsNormalizedTest, shouldReturnExpectedResult)
|
|
{
|
|
EXPECT_EQ(isNormalized(GetParam().first), GetParam().second);
|
|
}
|
|
|
|
const std::pair<std::string_view, bool> 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 <class T>
|
|
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<ExtensionView, ExtensionView>, TypePair<ExtensionView, const char*>,
|
|
TypePair<ExtensionView, std::string>, TypePair<ExtensionView, std::string_view>>;
|
|
|
|
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 <class T>
|
|
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<Normalized, Normalized>, TypePair<Normalized, const char*>,
|
|
TypePair<Normalized, std::string>, TypePair<Normalized, std::string_view>,
|
|
TypePair<Normalized, NormalizedView>, TypePair<NormalizedView, Normalized>,
|
|
TypePair<NormalizedView, const char*>, TypePair<NormalizedView, std::string>,
|
|
TypePair<NormalizedView, std::string_view>, TypePair<NormalizedView, NormalizedView>>;
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|