• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(PathUtils,isDirSeparator)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 
TEST(PathUtils,isPathSeparator)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 
TEST(PathUtils,rootPrefixSize)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 
TEST(PathUtils,isAbsolute)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 
checkComponents(const ComponentList & expected,const StringVector & components,const char * hostType,const char * path)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 
TEST(PathUtils,decompose)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 
componentListToVector(const ComponentList & input)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 
TEST(PathUtils,recompose)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.
componentsToPath(const ComponentList & components,char 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 
stringVectorToPath(const StringVector & input,char separator)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 
TEST(PathUtils,simplifyComponents)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