Home | History | Annotate | Download | only in files
      1 // Copyright 2014 The Android Open Source Project
      2 //
      3 // This software is licensed under the terms of the GNU General Public
      4 // License version 2, as published by the Free Software Foundation, and
      5 // may be copied, distributed, and modified under those terms.
      6 //
      7 // This program is distributed in the hope that it will be useful,
      8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 // GNU General Public License for more details.
     11 
     12 #include "android/base/files/PathUtils.h"
     13 
     14 #include "android/base/containers/StringVector.h"
     15 #include "android/base/String.h"
     16 
     17 #include <gtest/gtest.h>
     18 
     19 #define ARRAY_SIZE(x)  (sizeof(x)/sizeof(x[0]))
     20 
     21 namespace android {
     22 namespace base {
     23 
     24 static const int kHostTypeCount = PathUtils::kHostTypeCount;
     25 
     26 TEST(PathUtils, isDirSeparator) {
     27     static const struct {
     28         int ch;
     29         bool expected[kHostTypeCount];
     30     } kData[] = {
     31         { '/', { true, true }},
     32         { '\\', { false, true }},
     33         { '$', { false, false }},
     34         { ':', { false, false }},
     35         { ';', { false, false }},
     36     };
     37 
     38     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
     39         int ch = kData[n].ch;
     40         EXPECT_EQ(kData[n].expected[kHostPosix],
     41                   PathUtils::isDirSeparator(ch, kHostPosix))
     42                 << "Testing '" << ch << "'";
     43         EXPECT_EQ(kData[n].expected[kHostWin32],
     44                   PathUtils::isDirSeparator(ch, kHostWin32))
     45                 << "Testing '" << ch << "'";
     46         EXPECT_EQ(kData[n].expected[kHostType],
     47                   PathUtils::isDirSeparator(ch))
     48                 << "Testing '" << ch << "'";
     49     }
     50 }
     51 
     52 TEST(PathUtils, isPathSeparator) {
     53     static const struct {
     54         int ch;
     55         bool expected[kHostTypeCount];
     56     } kData[] = {
     57         { ':', { true, false }},
     58         { ';', { false, true }},
     59         { '/', { false, false }},
     60         { '\\', { false, false }},
     61         { '$', { false, false }},
     62     };
     63 
     64     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
     65         int ch = kData[n].ch;
     66         EXPECT_EQ(kData[n].expected[kHostPosix],
     67                   PathUtils::isPathSeparator(ch, kHostPosix))
     68                 << "Testing '" << ch << "'";
     69         EXPECT_EQ(kData[n].expected[kHostWin32],
     70                   PathUtils::isPathSeparator(ch, kHostWin32))
     71                 << "Testing '" << ch << "'";
     72         EXPECT_EQ(kData[n].expected[kHostType],
     73                   PathUtils::isPathSeparator(ch))
     74                 << "Testing '" << ch << "'";
     75     }
     76 }
     77 
     78 TEST(PathUtils, rootPrefixSize) {
     79     static const struct {
     80         const char* path;
     81         size_t prefixSize[kHostTypeCount];
     82     } kData[] = {
     83         { NULL, { 0u, 0u} },
     84         { "", { 0u, 0u } },
     85         { "foo", { 0u, 0u } },
     86         { "foo/bar", { 0u, 0u } },
     87         { "/foo", { 1u, 1u } },
     88         { "//foo", { 1u, 5u } },
     89         { "//foo/bar", { 1u, 6u } },
     90         { "c:", { 0u, 2u } },
     91         { "c:foo", { 0u, 2u } },
     92         { "c/foo", { 0u, 0u } },
     93         { "c:/foo", { 0u, 3u } },
     94         { "c:\\", { 0u, 3u } },
     95         { "c:\\\\", { 0u, 3u } },
     96         { "1:/foo", { 0u, 0u } },
     97         { "\\", { 0u, 1u } },
     98         { "\\foo", { 0u, 1u } },
     99         { "\\foo\\bar", { 0u, 1u } },
    100         { "\\\\foo", { 0u, 5u } },
    101         { "\\\\foo\\", { 0u, 6u } },
    102         { "\\\\foo\\\\bar", { 0u, 6u } },
    103     };
    104     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
    105         const char* path = kData[n].path;
    106         EXPECT_EQ(kData[n].prefixSize[kHostPosix],
    107                   PathUtils::rootPrefixSize(path, kHostPosix))
    108                 << "Testing '" << (path ? path : "<NULL>") << "'";
    109         EXPECT_EQ(kData[n].prefixSize[kHostWin32],
    110                   PathUtils::rootPrefixSize(path, kHostWin32))
    111                 << "Testing '" << (path ? path : "<NULL>") << "'";
    112         EXPECT_EQ(kData[n].prefixSize[kHostType],
    113                   PathUtils::rootPrefixSize(path))
    114                 << "Testing '" << (path ? path : "<NULL>") << "'";
    115     }
    116 }
    117 
    118 TEST(PathUtils, isAbsolute) {
    119     static const struct {
    120         const char* path;
    121         bool expected[kHostTypeCount];
    122     } kData[] = {
    123         { "foo", { false, false } },
    124         { "/foo", { true, true } },
    125         { "\\foo", { false, true } },
    126         { "/foo/bar", { true, true } },
    127         { "\\foo\\bar", { false, true } },
    128         { "C:foo", { false, false } },
    129         { "C:/foo", { false, true } },
    130         { "C:\\foo", { false, true } },
    131         { "//server", { true, false } },
    132         { "//server/path", { true, true } },
    133     };
    134     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
    135         const char* path = kData[n].path;
    136         EXPECT_EQ(kData[n].expected[kHostPosix],
    137                   PathUtils::isAbsolute(path, kHostPosix))
    138                 << "Testing '" << (path ? path : "<NULL>") << "'";
    139         EXPECT_EQ(kData[n].expected[kHostWin32],
    140                   PathUtils::isAbsolute(path, kHostWin32))
    141                 << "Testing '" << (path ? path : "<NULL>") << "'";
    142         EXPECT_EQ(kData[n].expected[kHostType],
    143                   PathUtils::isAbsolute(path))
    144                 << "Testing '" << (path ? path : "<NULL>") << "'";
    145     }
    146 }
    147 
    148 static const int kMaxComponents = 10;
    149 
    150 typedef const char* ComponentList[kMaxComponents];
    151 
    152 static void checkComponents(const ComponentList& expected,
    153                             const StringVector& components,
    154                             const char* hostType,
    155                             const char* path) {
    156     size_t m;
    157     for (m = 0; m < components.size(); ++m) {
    158         if (!expected[m])
    159             break;
    160         const char* component = expected[m];
    161         EXPECT_STREQ(component, components[m].c_str())
    162                 << hostType << " component #" << (m + 1) << " in " << path;
    163     }
    164     EXPECT_EQ(m, components.size())
    165                 << hostType << " component #" << (m + 1) << " in " << path;
    166 }
    167 
    168 TEST(PathUtils, decompose) {
    169     static const struct {
    170         const char* path;
    171         const ComponentList components[kHostTypeCount];
    172     } kData[] = {
    173         { "", { { NULL }, { NULL } } },
    174         { "foo", {
    175             { "foo", NULL },
    176             { "foo", NULL } } },
    177         { "foo/", {
    178             { "foo", NULL },
    179             { "foo", NULL } } },
    180         { "foo/bar", {
    181             { "foo", "bar", NULL },
    182             { "foo", "bar", NULL } } },
    183         { "foo//bar/zoo", {
    184             { "foo", "bar", "zoo", NULL },
    185             { "foo", "bar", "zoo", NULL } } },
    186         { "\\foo\\bar\\", {
    187             { "\\foo\\bar\\", NULL },
    188             { "\\", "foo", "bar", NULL } } },
    189         { "C:foo\\bar", {
    190             { "C:foo\\bar", NULL },
    191             { "C:", "foo", "bar", NULL } } },
    192         { "C:/foo", {
    193             { "C:", "foo", NULL },
    194             { "C:/", "foo", NULL } } },
    195         { "/foo", {
    196             { "/", "foo", NULL },
    197             { "/", "foo", NULL } } },
    198         { "\\foo", {
    199             { "\\foo", NULL },
    200             { "\\", "foo", NULL } } },
    201     };
    202     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
    203         const char* path = kData[n].path;
    204         checkComponents(kData[n].components[kHostPosix],
    205                         PathUtils::decompose(path, kHostPosix),
    206                         "posix",
    207                         path);
    208 
    209         checkComponents(kData[n].components[kHostWin32],
    210                         PathUtils::decompose(path, kHostWin32),
    211                         "win32",
    212                         path);
    213 
    214         checkComponents(kData[n].components[kHostType],
    215                         PathUtils::decompose(path),
    216                         "host",
    217                         path);
    218     }
    219 }
    220 
    221 static StringVector componentListToVector(
    222         const ComponentList& input) {
    223     StringVector result;
    224     for (size_t i = 0; input[i]; ++i)
    225         result.push_back(input[i]);
    226     return result;
    227 }
    228 
    229 TEST(PathUtils, recompose) {
    230     static const struct {
    231         const ComponentList input;
    232         const char* path[kHostTypeCount];
    233     } kData[] = {
    234         { { NULL }, { "", "" } },
    235         { { ".", NULL }, { ".", "." } },
    236         { { "..", NULL }, { "..", ".." } },
    237         { { "/", NULL }, { "/", "/" } },
    238         { { "/", "foo", NULL }, { "/foo", "/foo" } },
    239         { { "\\", "foo", NULL }, { "\\/foo", "\\foo" } },
    240         { { "foo", NULL }, { "foo", "foo" } },
    241         { { "foo", "bar", NULL }, { "foo/bar", "foo\\bar" } },
    242         { { ".", "foo", "..", NULL }, { "./foo/..", ".\\foo\\.." } },
    243         { { "C:", "foo", NULL }, { "C:/foo", "C:foo" } },
    244     };
    245     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
    246         StringVector components = componentListToVector(kData[n].input);
    247         EXPECT_STREQ(kData[n].path[kHostPosix],
    248                      PathUtils::recompose(components, kHostPosix).c_str());
    249         EXPECT_STREQ(kData[n].path[kHostWin32],
    250                      PathUtils::recompose(components, kHostWin32).c_str());
    251         EXPECT_STREQ(kData[n].path[kHostType],
    252                      PathUtils::recompose(components).c_str());
    253     }
    254 }
    255 
    256 
    257 // Convert a vector of strings |components| into a file path, using
    258 // |separator| as the directory separator.
    259 static String componentsToPath(
    260         const ComponentList& components,
    261         char separator) {
    262     String result;
    263     for (size_t n = 0; components[n]; ++n) {
    264         if (n)
    265             result += separator;
    266         result += components[n];
    267     }
    268     return result;
    269 }
    270 
    271 static String stringVectorToPath(
    272         const StringVector& input,
    273         char separator) {
    274     String result;
    275     for (size_t n = 0; n < input.size(); ++n) {
    276         if (n)
    277             result += separator;
    278         result += input[n];
    279     }
    280     return result;
    281 }
    282 
    283 TEST(PathUtils, simplifyComponents) {
    284     static const struct {
    285         const ComponentList input;
    286         const ComponentList expected;
    287     } kData[] = {
    288         { { NULL }, { ".", NULL } },
    289         { { ".", NULL }, { ".", NULL } },
    290         { { "..", NULL }, { "..", NULL } },
    291         { { "foo", NULL }, { "foo", NULL } },
    292         { { "foo", ".", NULL }, { "foo", NULL } },
    293         { { "foo", "bar", NULL }, { "foo", "bar", NULL } },
    294         { { ".", "foo", ".", "bar", ".", NULL }, { "foo", "bar", NULL } },
    295         { { "foo", "..", "bar", NULL }, { "bar", NULL } },
    296         { { ".", "..", "foo", "bar", NULL }, { "..", "foo", "bar", NULL } },
    297         { { "..", "foo", "..", "bar", NULL }, { "..", "bar", NULL } },
    298         { { "foo", "..", "..", "bar", NULL }, { "..", "bar", NULL } },
    299     };
    300     for (size_t n = 0; n < ARRAY_SIZE(kData); ++n) {
    301         const ComponentList& input = kData[n].input;
    302         String inputPath = componentsToPath(input, '!');
    303         String expectedPath = componentsToPath(kData[n].expected, '!');
    304         StringVector components = componentListToVector(input);
    305         PathUtils::simplifyComponents(&components);
    306         String path = stringVectorToPath(components, '!');
    307 
    308         EXPECT_STREQ(expectedPath.c_str(), path.c_str())
    309             << "When simplifying " << inputPath.c_str();
    310     }
    311 };
    312 
    313 }  // namespace android
    314 }  // namespace base
    315