blob: d4ca2b8f6648c130faacb3c4ed9f4afb20c07830 [file] [log] [blame]
// Copyright 2014 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/base/files/PathUtils.h"
#include "android/base/containers/StringVector.h"
#include "android/base/String.h"
#include <gtest/gtest.h>
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
namespace android {
namespace base {
static const int kHostTypeCount = PathUtils::kHostTypeCount;
TEST(PathUtils, isDirSeparator) {
static const struct {
int ch;
bool expected[kHostTypeCount];
} kData[] = {
{ '/', { true, true }},
{ '\\', { false, true }},
{ '$', { false, false }},
{ ':', { false, false }},
{ ';', { false, false }},
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
int ch = kData[n].ch;
EXPECT_EQ(kData[n].expected[kHostPosix],
PathUtils::isDirSeparator(ch, kHostPosix))
<< "Testing '" << ch << "'";
EXPECT_EQ(kData[n].expected[kHostWin32],
PathUtils::isDirSeparator(ch, kHostWin32))
<< "Testing '" << ch << "'";
EXPECT_EQ(kData[n].expected[kHostType],
PathUtils::isDirSeparator(ch))
<< "Testing '" << ch << "'";
}
}
TEST(PathUtils, isPathSeparator) {
static const struct {
int ch;
bool expected[kHostTypeCount];
} kData[] = {
{ ':', { true, false }},
{ ';', { false, true }},
{ '/', { false, false }},
{ '\\', { false, false }},
{ '$', { false, false }},
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
int ch = kData[n].ch;
EXPECT_EQ(kData[n].expected[kHostPosix],
PathUtils::isPathSeparator(ch, kHostPosix))
<< "Testing '" << ch << "'";
EXPECT_EQ(kData[n].expected[kHostWin32],
PathUtils::isPathSeparator(ch, kHostWin32))
<< "Testing '" << ch << "'";
EXPECT_EQ(kData[n].expected[kHostType],
PathUtils::isPathSeparator(ch))
<< "Testing '" << ch << "'";
}
}
TEST(PathUtils, rootPrefixSize) {
static const struct {
const char* path;
size_t prefixSize[kHostTypeCount];
} kData[] = {
{ NULL, { 0u, 0u} },
{ "", { 0u, 0u } },
{ "foo", { 0u, 0u } },
{ "foo/bar", { 0u, 0u } },
{ "/foo", { 1u, 1u } },
{ "//foo", { 1u, 5u } },
{ "//foo/bar", { 1u, 6u } },
{ "c:", { 0u, 2u } },
{ "c:foo", { 0u, 2u } },
{ "c/foo", { 0u, 0u } },
{ "c:/foo", { 0u, 3u } },
{ "c:\\", { 0u, 3u } },
{ "c:\\\\", { 0u, 3u } },
{ "1:/foo", { 0u, 0u } },
{ "\\", { 0u, 1u } },
{ "\\foo", { 0u, 1u } },
{ "\\foo\\bar", { 0u, 1u } },
{ "\\\\foo", { 0u, 5u } },
{ "\\\\foo\\", { 0u, 6u } },
{ "\\\\foo\\\\bar", { 0u, 6u } },
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
const char* path = kData[n].path;
EXPECT_EQ(kData[n].prefixSize[kHostPosix],
PathUtils::rootPrefixSize(path, kHostPosix))
<< "Testing '" << (path ? path : "<NULL>") << "'";
EXPECT_EQ(kData[n].prefixSize[kHostWin32],
PathUtils::rootPrefixSize(path, kHostWin32))
<< "Testing '" << (path ? path : "<NULL>") << "'";
EXPECT_EQ(kData[n].prefixSize[kHostType],
PathUtils::rootPrefixSize(path))
<< "Testing '" << (path ? path : "<NULL>") << "'";
}
}
TEST(PathUtils, isAbsolute) {
static const struct {
const char* path;
bool expected[kHostTypeCount];
} kData[] = {
{ "foo", { false, false } },
{ "/foo", { true, true } },
{ "\\foo", { false, true } },
{ "/foo/bar", { true, true } },
{ "\\foo\\bar", { false, true } },
{ "C:foo", { false, false } },
{ "C:/foo", { false, true } },
{ "C:\\foo", { false, true } },
{ "//server", { true, false } },
{ "//server/path", { true, true } },
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
const char* path = kData[n].path;
EXPECT_EQ(kData[n].expected[kHostPosix],
PathUtils::isAbsolute(path, kHostPosix))
<< "Testing '" << (path ? path : "<NULL>") << "'";
EXPECT_EQ(kData[n].expected[kHostWin32],
PathUtils::isAbsolute(path, kHostWin32))
<< "Testing '" << (path ? path : "<NULL>") << "'";
EXPECT_EQ(kData[n].expected[kHostType],
PathUtils::isAbsolute(path))
<< "Testing '" << (path ? path : "<NULL>") << "'";
}
}
static const int kMaxComponents = 10;
typedef const char* ComponentList[kMaxComponents];
static void checkComponents(const ComponentList& expected,
const StringVector& components,
const char* hostType,
const char* path) {
size_t m;
for (m = 0; m < components.size(); ++m) {
if (!expected[m])
break;
const char* component = expected[m];
EXPECT_STREQ(component, components[m].c_str())
<< hostType << " component #" << (m + 1) << " in " << path;
}
EXPECT_EQ(m, components.size())
<< hostType << " component #" << (m + 1) << " in " << path;
}
TEST(PathUtils, decompose) {
static const struct {
const char* path;
const ComponentList components[kHostTypeCount];
} kData[] = {
{ "", { { NULL }, { NULL } } },
{ "foo", {
{ "foo", NULL },
{ "foo", NULL } } },
{ "foo/", {
{ "foo", NULL },
{ "foo", NULL } } },
{ "foo/bar", {
{ "foo", "bar", NULL },
{ "foo", "bar", NULL } } },
{ "foo//bar/zoo", {
{ "foo", "bar", "zoo", NULL },
{ "foo", "bar", "zoo", NULL } } },
{ "\\foo\\bar\\", {
{ "\\foo\\bar\\", NULL },
{ "\\", "foo", "bar", NULL } } },
{ "C:foo\\bar", {
{ "C:foo\\bar", NULL },
{ "C:", "foo", "bar", NULL } } },
{ "C:/foo", {
{ "C:", "foo", NULL },
{ "C:/", "foo", NULL } } },
{ "/foo", {
{ "/", "foo", NULL },
{ "/", "foo", NULL } } },
{ "\\foo", {
{ "\\foo", NULL },
{ "\\", "foo", NULL } } },
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
const char* path = kData[n].path;
checkComponents(kData[n].components[kHostPosix],
PathUtils::decompose(path, kHostPosix),
"posix",
path);
checkComponents(kData[n].components[kHostWin32],
PathUtils::decompose(path, kHostWin32),
"win32",
path);
checkComponents(kData[n].components[kHostType],
PathUtils::decompose(path),
"host",
path);
}
}
static StringVector componentListToVector(
const ComponentList& input) {
StringVector result;
for (size_t i = 0; input[i]; ++i)
result.push_back(input[i]);
return result;
}
TEST(PathUtils, recompose) {
static const struct {
const ComponentList input;
const char* path[kHostTypeCount];
} kData[] = {
{ { NULL }, { "", "" } },
{ { ".", NULL }, { ".", "." } },
{ { "..", NULL }, { "..", ".." } },
{ { "/", NULL }, { "/", "/" } },
{ { "/", "foo", NULL }, { "/foo", "/foo" } },
{ { "\\", "foo", NULL }, { "\\/foo", "\\foo" } },
{ { "foo", NULL }, { "foo", "foo" } },
{ { "foo", "bar", NULL }, { "foo/bar", "foo\\bar" } },
{ { ".", "foo", "..", NULL }, { "./foo/..", ".\\foo\\.." } },
{ { "C:", "foo", NULL }, { "C:/foo", "C:foo" } },
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
StringVector components = componentListToVector(kData[n].input);
EXPECT_STREQ(kData[n].path[kHostPosix],
PathUtils::recompose(components, kHostPosix).c_str());
EXPECT_STREQ(kData[n].path[kHostWin32],
PathUtils::recompose(components, kHostWin32).c_str());
EXPECT_STREQ(kData[n].path[kHostType],
PathUtils::recompose(components).c_str());
}
}
// Convert a vector of strings |components| into a file path, using
// |separator| as the directory separator.
static String componentsToPath(
const ComponentList& components,
char separator) {
String result;
for (size_t n = 0; components[n]; ++n) {
if (n)
result += separator;
result += components[n];
}
return result;
}
static String stringVectorToPath(
const StringVector& input,
char separator) {
String result;
for (size_t n = 0; n < input.size(); ++n) {
if (n)
result += separator;
result += input[n];
}
return result;
}
TEST(PathUtils, simplifyComponents) {
static const struct {
const ComponentList input;
const ComponentList expected;
} kData[] = {
{ { NULL }, { ".", NULL } },
{ { ".", NULL }, { ".", NULL } },
{ { "..", NULL }, { "..", NULL } },
{ { "foo", NULL }, { "foo", NULL } },
{ { "foo", ".", NULL }, { "foo", NULL } },
{ { "foo", "bar", NULL }, { "foo", "bar", NULL } },
{ { ".", "foo", ".", "bar", ".", NULL }, { "foo", "bar", NULL } },
{ { "foo", "..", "bar", NULL }, { "bar", NULL } },
{ { ".", "..", "foo", "bar", NULL }, { "..", "foo", "bar", NULL } },
{ { "..", "foo", "..", "bar", NULL }, { "..", "bar", NULL } },
{ { "foo", "..", "..", "bar", NULL }, { "..", "bar", NULL } },
};
for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
const ComponentList& input = kData[n].input;
String inputPath = componentsToPath(input, '!');
String expectedPath = componentsToPath(kData[n].expected, '!');
StringVector components = componentListToVector(input);
PathUtils::simplifyComponents(&components);
String path = stringVectorToPath(components, '!');
EXPECT_STREQ(expectedPath.c_str(), path.c_str())
<< "When simplifying " << inputPath.c_str();
}
};
} // namespace android
} // namespace base