1 // Copyright (c) 2012 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.
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/path_service.h"
10 #include "components/crx_file/id_util.h"
11 #include "extensions/common/constants.h"
12 #include "extensions/common/extension_paths.h"
13 #include "extensions/common/extension_resource.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/l10n/l10n_util.h"
17 namespace extensions
{
19 TEST(ExtensionResourceTest
, CreateEmptyResource
) {
20 ExtensionResource resource
;
22 EXPECT_TRUE(resource
.extension_root().empty());
23 EXPECT_TRUE(resource
.relative_path().empty());
24 EXPECT_TRUE(resource
.GetFilePath().empty());
27 const base::FilePath::StringType
ToLower(
28 const base::FilePath::StringType
& in_str
) {
29 base::FilePath::StringType
str(in_str
);
30 std::transform(str
.begin(), str
.end(), str
.begin(), tolower
);
34 TEST(ExtensionResourceTest
, CreateWithMissingResourceOnDisk
) {
35 base::FilePath root_path
;
36 ASSERT_TRUE(PathService::Get(DIR_TEST_DATA
, &root_path
));
37 base::FilePath relative_path
;
38 relative_path
= relative_path
.AppendASCII("cira.js");
39 std::string extension_id
= crx_file::id_util::GenerateId("test");
40 ExtensionResource
resource(extension_id
, root_path
, relative_path
);
42 // The path doesn't exist on disk, we will be returned an empty path.
43 EXPECT_EQ(root_path
.value(), resource
.extension_root().value());
44 EXPECT_EQ(relative_path
.value(), resource
.relative_path().value());
45 EXPECT_TRUE(resource
.GetFilePath().empty());
48 TEST(ExtensionResourceTest
, ResourcesOutsideOfPath
) {
49 base::ScopedTempDir temp
;
50 ASSERT_TRUE(temp
.CreateUniqueTempDir());
52 base::FilePath inner_dir
= temp
.path().AppendASCII("directory");
53 ASSERT_TRUE(base::CreateDirectory(inner_dir
));
54 base::FilePath sub_dir
= inner_dir
.AppendASCII("subdir");
55 ASSERT_TRUE(base::CreateDirectory(sub_dir
));
56 base::FilePath inner_file
= inner_dir
.AppendASCII("inner");
57 base::FilePath outer_file
= temp
.path().AppendASCII("outer");
58 ASSERT_TRUE(base::WriteFile(outer_file
, "X", 1));
59 ASSERT_TRUE(base::WriteFile(inner_file
, "X", 1));
60 std::string extension_id
= crx_file::id_util::GenerateId("test");
63 base::FilePath symlink_file
= inner_dir
.AppendASCII("symlink");
64 base::CreateSymbolicLink(
65 base::FilePath().AppendASCII("..").AppendASCII("outer"),
69 // A non-packing extension should be able to access the file within the
71 ExtensionResource
r1(extension_id
, inner_dir
,
72 base::FilePath().AppendASCII("inner"));
73 EXPECT_FALSE(r1
.GetFilePath().empty());
75 // ... but not a relative path that walks out of |inner_dir|.
76 ExtensionResource
r2(extension_id
, inner_dir
,
77 base::FilePath().AppendASCII("..").AppendASCII("outer"));
78 EXPECT_TRUE(r2
.GetFilePath().empty());
80 // A packing extension should also be able to access the file within the
82 ExtensionResource
r3(extension_id
, inner_dir
,
83 base::FilePath().AppendASCII("inner"));
84 r3
.set_follow_symlinks_anywhere();
85 EXPECT_FALSE(r3
.GetFilePath().empty());
87 // ... but, again, not a relative path that walks out of |inner_dir|.
88 ExtensionResource
r4(extension_id
, inner_dir
,
89 base::FilePath().AppendASCII("..").AppendASCII("outer"));
90 r4
.set_follow_symlinks_anywhere();
91 EXPECT_TRUE(r4
.GetFilePath().empty());
93 // ... and not even when clever current-directory syntax is present. Note
94 // that the path for this test case can't start with the current directory
95 // component due to quirks in FilePath::Append(), and the path must exist.
96 ExtensionResource
r4a(
97 extension_id
, inner_dir
,
98 base::FilePath().AppendASCII("subdir").AppendASCII(".").AppendASCII("..").
99 AppendASCII("..").AppendASCII("outer"));
100 r4a
.set_follow_symlinks_anywhere();
101 EXPECT_TRUE(r4a
.GetFilePath().empty());
103 #if defined(OS_POSIX)
104 // The non-packing extension should also not be able to access a resource that
105 // symlinks out of the directory.
106 ExtensionResource
r5(extension_id
, inner_dir
,
107 base::FilePath().AppendASCII("symlink"));
108 EXPECT_TRUE(r5
.GetFilePath().empty());
110 // ... but a packing extension can.
111 ExtensionResource
r6(extension_id
, inner_dir
,
112 base::FilePath().AppendASCII("symlink"));
113 r6
.set_follow_symlinks_anywhere();
114 EXPECT_FALSE(r6
.GetFilePath().empty());
118 TEST(ExtensionResourceTest
, CreateWithAllResourcesOnDisk
) {
119 base::ScopedTempDir temp
;
120 ASSERT_TRUE(temp
.CreateUniqueTempDir());
122 // Create resource in the extension root.
123 const char* filename
= "res.ico";
124 base::FilePath root_resource
= temp
.path().AppendASCII(filename
);
125 std::string data
= "some foo";
126 ASSERT_TRUE(base::WriteFile(root_resource
, data
.c_str(), data
.length()));
128 // Create l10n resources (for current locale and its parents).
129 base::FilePath l10n_path
=
130 temp
.path().Append(kLocaleFolder
);
131 ASSERT_TRUE(base::CreateDirectory(l10n_path
));
133 std::vector
<std::string
> locales
;
134 l10n_util::GetParentLocales(l10n_util::GetApplicationLocale(std::string()),
136 ASSERT_FALSE(locales
.empty());
137 for (size_t i
= 0; i
< locales
.size(); i
++) {
138 base::FilePath make_path
;
139 make_path
= l10n_path
.AppendASCII(locales
[i
]);
140 ASSERT_TRUE(base::CreateDirectory(make_path
));
141 ASSERT_TRUE(base::WriteFile(make_path
.AppendASCII(filename
),
142 data
.c_str(), data
.length()));
146 std::string extension_id
= crx_file::id_util::GenerateId("test");
147 ExtensionResource
resource(extension_id
, temp
.path(),
148 base::FilePath().AppendASCII(filename
));
149 base::FilePath resolved_path
= resource
.GetFilePath();
151 base::FilePath expected_path
;
152 // Expect default path only, since fallback logic is disabled.
153 // See http://crbug.com/27359.
154 expected_path
= base::MakeAbsoluteFilePath(root_resource
);
155 ASSERT_FALSE(expected_path
.empty());
157 EXPECT_EQ(ToLower(expected_path
.value()), ToLower(resolved_path
.value()));
158 EXPECT_EQ(ToLower(temp
.path().value()),
159 ToLower(resource
.extension_root().value()));
160 EXPECT_EQ(ToLower(base::FilePath().AppendASCII(filename
).value()),
161 ToLower(resource
.relative_path().value()));
164 } // namespace extensions