1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "storage/common/fileapi/file_system_util.h"
6
7#include "base/files/file_path.h"
8#include "testing/gtest/include/gtest/gtest.h"
9#include "url/gurl.h"
10
11using storage::CrackIsolatedFileSystemName;
12using storage::GetExternalFileSystemRootURIString;
13using storage::GetIsolatedFileSystemName;
14using storage::GetIsolatedFileSystemRootURIString;
15using storage::ValidateIsolatedFileSystemId;
16using storage::VirtualPath;
17
18namespace content {
19namespace {
20
21class FileSystemUtilTest : public testing::Test {};
22
23TEST_F(FileSystemUtilTest, ParseFileSystemSchemeURL) {
24  GURL uri("filesystem:http://chromium.org/temporary/foo/bar");
25  GURL origin_url;
26  storage::FileSystemType type;
27  base::FilePath virtual_path;
28  ParseFileSystemSchemeURL(uri, &origin_url, &type, &virtual_path);
29  EXPECT_EQ(GURL("http://chromium.org"), origin_url);
30  EXPECT_EQ(storage::kFileSystemTypeTemporary, type);
31#if defined(FILE_PATH_USES_WIN_SEPARATORS)
32  base::FilePath expected_path(FILE_PATH_LITERAL("foo\\bar"));
33#else
34  base::FilePath expected_path(FILE_PATH_LITERAL("foo/bar"));
35#endif
36  EXPECT_EQ(expected_path, virtual_path);
37}
38
39TEST_F(FileSystemUtilTest, GetTempFileSystemRootURI) {
40  GURL origin_url("http://chromium.org");
41  storage::FileSystemType type = storage::kFileSystemTypeTemporary;
42  GURL uri = GURL("filesystem:http://chromium.org/temporary/");
43  EXPECT_EQ(uri, GetFileSystemRootURI(origin_url, type));
44}
45
46TEST_F(FileSystemUtilTest, GetPersistentFileSystemRootURI) {
47  GURL origin_url("http://chromium.org");
48  storage::FileSystemType type = storage::kFileSystemTypePersistent;
49  GURL uri = GURL("filesystem:http://chromium.org/persistent/");
50  EXPECT_EQ(uri, GetFileSystemRootURI(origin_url, type));
51}
52
53TEST_F(FileSystemUtilTest, VirtualPathBaseName) {
54  struct test_data {
55    const base::FilePath::StringType path;
56    const base::FilePath::StringType base_name;
57  } test_cases[] = {
58    { FILE_PATH_LITERAL("foo/bar"), FILE_PATH_LITERAL("bar") },
59    { FILE_PATH_LITERAL("foo/b:bar"), FILE_PATH_LITERAL("b:bar") },
60    { FILE_PATH_LITERAL(""), FILE_PATH_LITERAL("") },
61    { FILE_PATH_LITERAL("/"), FILE_PATH_LITERAL("/") },
62    { FILE_PATH_LITERAL("foo//////bar"), FILE_PATH_LITERAL("bar") },
63    { FILE_PATH_LITERAL("foo/bar/"), FILE_PATH_LITERAL("bar") },
64    { FILE_PATH_LITERAL("foo/bar/////"), FILE_PATH_LITERAL("bar") },
65    { FILE_PATH_LITERAL("/bar/////"), FILE_PATH_LITERAL("bar") },
66    { FILE_PATH_LITERAL("bar/////"), FILE_PATH_LITERAL("bar") },
67    { FILE_PATH_LITERAL("bar/"), FILE_PATH_LITERAL("bar") },
68    { FILE_PATH_LITERAL("/bar"), FILE_PATH_LITERAL("bar") },
69    { FILE_PATH_LITERAL("////bar"), FILE_PATH_LITERAL("bar") },
70    { FILE_PATH_LITERAL("bar"), FILE_PATH_LITERAL("bar") }
71  };
72  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
73    base::FilePath input = base::FilePath(test_cases[i].path);
74    base::FilePath base_name = VirtualPath::BaseName(input);
75    EXPECT_EQ(test_cases[i].base_name, base_name.value());
76  }
77}
78
79TEST_F(FileSystemUtilTest, VirtualPathDirName) {
80  struct test_data {
81    const base::FilePath::StringType path;
82    const base::FilePath::StringType dir_name;
83  } test_cases[] = {
84    { FILE_PATH_LITERAL("foo/bar"), FILE_PATH_LITERAL("foo") },
85    { FILE_PATH_LITERAL("foo/b:bar"), FILE_PATH_LITERAL("foo") },
86    { FILE_PATH_LITERAL(""), FILE_PATH_LITERAL(".") },
87    { FILE_PATH_LITERAL("/"), FILE_PATH_LITERAL("/") },
88    { FILE_PATH_LITERAL("foo//////bar"), FILE_PATH_LITERAL("foo") },
89    { FILE_PATH_LITERAL("foo/bar/"), FILE_PATH_LITERAL("foo") },
90    { FILE_PATH_LITERAL("foo/bar/////"), FILE_PATH_LITERAL("foo") },
91    { FILE_PATH_LITERAL("/bar/////"), FILE_PATH_LITERAL("/") },
92    { FILE_PATH_LITERAL("bar/////"), FILE_PATH_LITERAL(".") },
93    { FILE_PATH_LITERAL("bar/"), FILE_PATH_LITERAL(".") },
94    { FILE_PATH_LITERAL("/bar"), FILE_PATH_LITERAL("/") },
95    { FILE_PATH_LITERAL("////bar"), FILE_PATH_LITERAL("/") },
96    { FILE_PATH_LITERAL("bar"), FILE_PATH_LITERAL(".") },
97    { FILE_PATH_LITERAL("c:bar"), FILE_PATH_LITERAL(".") },
98#ifdef FILE_PATH_USES_WIN_SEPARATORS
99    { FILE_PATH_LITERAL("foo\\bar"), FILE_PATH_LITERAL("foo") },
100    { FILE_PATH_LITERAL("foo\\b:bar"), FILE_PATH_LITERAL("foo") },
101    { FILE_PATH_LITERAL("\\"), FILE_PATH_LITERAL("\\") },
102    { FILE_PATH_LITERAL("foo\\\\\\\\\\\\bar"), FILE_PATH_LITERAL("foo") },
103    { FILE_PATH_LITERAL("foo\\bar\\"), FILE_PATH_LITERAL("foo") },
104    { FILE_PATH_LITERAL("foo\\bar\\\\\\\\\\"), FILE_PATH_LITERAL("foo") },
105    { FILE_PATH_LITERAL("\\bar\\\\\\\\\\"), FILE_PATH_LITERAL("\\") },
106    { FILE_PATH_LITERAL("bar\\\\\\\\\\"), FILE_PATH_LITERAL(".") },
107    { FILE_PATH_LITERAL("bar\\"), FILE_PATH_LITERAL(".") },
108    { FILE_PATH_LITERAL("\\bar"), FILE_PATH_LITERAL("\\") },
109    { FILE_PATH_LITERAL("\\\\\\\\bar"), FILE_PATH_LITERAL("\\") },
110#endif
111  };
112  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
113    base::FilePath input = base::FilePath(test_cases[i].path);
114    base::FilePath dir_name = VirtualPath::DirName(input);
115    EXPECT_EQ(test_cases[i].dir_name, dir_name.value());
116  }
117}
118
119TEST_F(FileSystemUtilTest, GetNormalizedFilePath) {
120  struct test_data {
121    const base::FilePath::StringType path;
122    const base::FilePath::StringType normalized_path;
123  } test_cases[] = {
124    { FILE_PATH_LITERAL(""), FILE_PATH_LITERAL("/") },
125    { FILE_PATH_LITERAL("/"), FILE_PATH_LITERAL("/") },
126    { FILE_PATH_LITERAL("foo/bar"), FILE_PATH_LITERAL("/foo/bar") },
127    { FILE_PATH_LITERAL("/foo/bar"), FILE_PATH_LITERAL("/foo/bar") },
128#if defined(FILE_PATH_USES_WIN_SEPARATORS)
129    { FILE_PATH_LITERAL("\\foo"), FILE_PATH_LITERAL("/foo") },
130#endif
131  };
132  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
133    base::FilePath input = base::FilePath(test_cases[i].path);
134    base::FilePath::StringType normalized_path_string =
135        VirtualPath::GetNormalizedFilePath(input);
136    EXPECT_EQ(test_cases[i].normalized_path, normalized_path_string);
137  }
138}
139
140TEST_F(FileSystemUtilTest, IsAbsolutePath) {
141  EXPECT_TRUE(VirtualPath::IsAbsolute(FILE_PATH_LITERAL("/")));
142  EXPECT_TRUE(VirtualPath::IsAbsolute(FILE_PATH_LITERAL("/foo/bar")));
143  EXPECT_FALSE(VirtualPath::IsAbsolute(base::FilePath::StringType()));
144  EXPECT_FALSE(VirtualPath::IsAbsolute(FILE_PATH_LITERAL("foo/bar")));
145}
146
147TEST_F(FileSystemUtilTest, IsRootPath) {
148  EXPECT_TRUE(VirtualPath::IsRootPath(base::FilePath(FILE_PATH_LITERAL(""))));
149  EXPECT_TRUE(VirtualPath::IsRootPath(base::FilePath()));
150  EXPECT_TRUE(VirtualPath::IsRootPath(base::FilePath(FILE_PATH_LITERAL("/"))));
151  EXPECT_TRUE(VirtualPath::IsRootPath(base::FilePath(FILE_PATH_LITERAL("//"))));
152  EXPECT_FALSE(VirtualPath::IsRootPath(
153      base::FilePath(FILE_PATH_LITERAL("c:/"))));
154#if defined(FILE_PATH_USES_WIN_SEPARATORS)
155  EXPECT_TRUE(VirtualPath::IsRootPath(base::FilePath(FILE_PATH_LITERAL("\\"))));
156  EXPECT_FALSE(VirtualPath::IsRootPath(
157      base::FilePath(FILE_PATH_LITERAL("c:\\"))));
158#endif
159}
160
161TEST_F(FileSystemUtilTest, VirtualPathGetComponents) {
162  struct test_data {
163    const base::FilePath::StringType path;
164    size_t count;
165    const base::FilePath::StringType components[2];
166  } test_cases[] = {
167    { FILE_PATH_LITERAL("foo/bar"),
168      2,
169      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("bar") } },
170    { FILE_PATH_LITERAL("foo"),
171      1,
172      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("") } },
173    { FILE_PATH_LITERAL("foo////bar"),
174      2,
175      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("bar") } },
176    { FILE_PATH_LITERAL("foo/c:bar"),
177      2,
178      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("c:bar") } },
179    { FILE_PATH_LITERAL("c:foo/bar"),
180      2,
181      { FILE_PATH_LITERAL("c:foo"), FILE_PATH_LITERAL("bar") } },
182    { FILE_PATH_LITERAL("foo/bar"),
183      2,
184      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("bar") } },
185    { FILE_PATH_LITERAL("/foo/bar"),
186      2,
187      { FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("bar") } },
188    { FILE_PATH_LITERAL("c:/bar"),
189      2,
190      { FILE_PATH_LITERAL("c:"), FILE_PATH_LITERAL("bar") } },
191#ifdef FILE_PATH_USES_WIN_SEPARATORS
192    { FILE_PATH_LITERAL("c:\\bar"),
193      2,
194      { FILE_PATH_LITERAL("c:"), FILE_PATH_LITERAL("bar") } },
195#endif
196  };
197  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
198    base::FilePath input = base::FilePath(test_cases[i].path);
199    std::vector<base::FilePath::StringType> components;
200    VirtualPath::GetComponents(input, &components);
201    EXPECT_EQ(test_cases[i].count, components.size());
202    for (size_t j = 0; j < components.size(); ++j)
203      EXPECT_EQ(test_cases[i].components[j], components[j]);
204  }
205  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
206    base::FilePath input = base::FilePath(test_cases[i].path);
207    std::vector<std::string> components;
208    VirtualPath::GetComponentsUTF8Unsafe(input, &components);
209    EXPECT_EQ(test_cases[i].count, components.size());
210    for (size_t j = 0; j < components.size(); ++j) {
211      EXPECT_EQ(base::FilePath(test_cases[i].components[j]).AsUTF8Unsafe(),
212                components[j]);
213    }
214  }
215}
216
217TEST_F(FileSystemUtilTest, GetIsolatedFileSystemName) {
218  GURL origin_url("http://foo");
219  std::string fsname1 = GetIsolatedFileSystemName(origin_url, "bar");
220  EXPECT_EQ("http_foo_0:Isolated_bar", fsname1);
221}
222
223TEST_F(FileSystemUtilTest, CrackIsolatedFileSystemName) {
224  std::string fsid;
225  EXPECT_TRUE(CrackIsolatedFileSystemName("foo:Isolated_bar", &fsid));
226  EXPECT_EQ("bar", fsid);
227  EXPECT_TRUE(CrackIsolatedFileSystemName("foo:isolated_bar", &fsid));
228  EXPECT_EQ("bar", fsid);
229  EXPECT_TRUE(CrackIsolatedFileSystemName("foo:Isolated__bar", &fsid));
230  EXPECT_EQ("_bar", fsid);
231  EXPECT_TRUE(CrackIsolatedFileSystemName("foo::Isolated_bar", &fsid));
232  EXPECT_EQ("bar", fsid);
233}
234
235TEST_F(FileSystemUtilTest, RejectBadIsolatedFileSystemName) {
236  std::string fsid;
237  EXPECT_FALSE(CrackIsolatedFileSystemName("foobar", &fsid));
238  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:_bar", &fsid));
239  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Isolatedbar", &fsid));
240  EXPECT_FALSE(CrackIsolatedFileSystemName("fooIsolatedbar", &fsid));
241  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Persistent", &fsid));
242  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Temporary", &fsid));
243  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:External", &fsid));
244  EXPECT_FALSE(CrackIsolatedFileSystemName(":Isolated_bar", &fsid));
245  EXPECT_FALSE(CrackIsolatedFileSystemName("foo:Isolated_", &fsid));
246}
247
248TEST_F(FileSystemUtilTest, ValidateIsolatedFileSystemId) {
249  EXPECT_TRUE(ValidateIsolatedFileSystemId("ABCDEF0123456789ABCDEF0123456789"));
250  EXPECT_TRUE(ValidateIsolatedFileSystemId("ABCDEFABCDEFABCDEFABCDEFABCDEFAB"));
251  EXPECT_TRUE(ValidateIsolatedFileSystemId("01234567890123456789012345678901"));
252
253  const size_t kExpectedFileSystemIdSize = 32;
254
255  // Should not contain lowercase characters.
256  const std::string kLowercaseId = "abcdef0123456789abcdef0123456789";
257  EXPECT_EQ(kExpectedFileSystemIdSize, kLowercaseId.size());
258  EXPECT_FALSE(ValidateIsolatedFileSystemId(kLowercaseId));
259
260  // Should not be shorter/longer than expected.
261  EXPECT_FALSE(ValidateIsolatedFileSystemId(std::string()));
262
263  const std::string kShorterId = "ABCDEF0123456789ABCDEF";
264  EXPECT_GT(kExpectedFileSystemIdSize, kShorterId.size());
265  EXPECT_FALSE(ValidateIsolatedFileSystemId(kShorterId));
266
267  const std::string kLongerId = "ABCDEF0123456789ABCDEF0123456789ABCDEF";
268  EXPECT_LT(kExpectedFileSystemIdSize, kLongerId.size());
269  EXPECT_FALSE(ValidateIsolatedFileSystemId(kLongerId));
270
271  // Should not contain not alphabetical nor numerical characters.
272  const std::string kSlashId = "ABCD/EFGH/IJKL/MNOP/QRST/UVWX/YZ";
273  EXPECT_EQ(kExpectedFileSystemIdSize, kSlashId.size());
274  EXPECT_FALSE(ValidateIsolatedFileSystemId(kSlashId));
275
276  const std::string kBackslashId = "ABCD\\EFGH\\IJKL\\MNOP\\QRST\\UVWX\\YZ";
277  EXPECT_EQ(kExpectedFileSystemIdSize, kBackslashId.size());
278  EXPECT_FALSE(ValidateIsolatedFileSystemId(kBackslashId));
279
280  const std::string kSpaceId = "ABCD EFGH IJKL MNOP QRST UVWX YZ";
281  EXPECT_EQ(kExpectedFileSystemIdSize, kSpaceId.size());
282  EXPECT_FALSE(ValidateIsolatedFileSystemId(kSpaceId));
283}
284
285TEST_F(FileSystemUtilTest, GetIsolatedFileSystemRootURIString) {
286  const GURL kOriginURL("http://foo");
287  // Percents must be escaped, otherwise they will be unintentionally unescaped.
288  const std::string kFileSystemId = "A%20B";
289  const std::string kRootName = "C%20D";
290
291  const std::string url_string =
292      GetIsolatedFileSystemRootURIString(kOriginURL, kFileSystemId, kRootName);
293  EXPECT_EQ("filesystem:http://foo/isolated/A%2520B/C%2520D/", url_string);
294}
295
296TEST_F(FileSystemUtilTest, GetExternalFileSystemRootURIString) {
297  const GURL kOriginURL("http://foo");
298  // Percents must be escaped, otherwise they will be unintentionally unescaped.
299  const std::string kMountName = "X%20Y";
300
301  const std::string url_string =
302      GetExternalFileSystemRootURIString(kOriginURL, kMountName);
303  EXPECT_EQ("filesystem:http://foo/external/X%2520Y/", url_string);
304}
305
306}  // namespace
307}  // namespace content
308