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.
4
5 #include "extensions/browser/extension_creator_filter.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/macros.h"
14 #include "base/stl_util.h"
15 #include "build/build_config.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/platform_test.h"
18
19 #if defined(OS_WIN)
20 #include <windows.h>
21 #endif
22
23 namespace {
24
25 class ExtensionCreatorFilterTest : public PlatformTest {
26 protected:
SetUp()27 void SetUp() override {
28 PlatformTest::SetUp();
29
30 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
31 extension_dir_ = temp_dir_.GetPath();
32
33 filter_ = base::MakeRefCounted<extensions::ExtensionCreatorFilter>(
34 extension_dir_);
35 }
36
CreateTestFile(const base::FilePath & file_path)37 base::FilePath CreateTestFile(const base::FilePath& file_path) {
38 return CreateRelativeFilePath(file_path);
39 }
40
41 // Creates an empty file with the given relative path. Creates parent
42 // directories if needed.
CreateRelativeFilePath(const base::FilePath & relative_file_path)43 base::FilePath CreateRelativeFilePath(
44 const base::FilePath& relative_file_path) {
45 base::FilePath path = extension_dir_.Append(relative_file_path);
46 EXPECT_TRUE(base::CreateDirectory(path.DirName()));
47
48 std::string contents = "test";
49 EXPECT_EQ(static_cast<int>(contents.size()),
50 base::WriteFile(path, contents.c_str(), contents.size()));
51 return path;
52 }
53
CreateTestFileInDir(const base::FilePath::StringType & file_name,const base::FilePath::StringType & dir)54 base::FilePath CreateTestFileInDir(
55 const base::FilePath::StringType& file_name,
56 const base::FilePath::StringType& dir) {
57 return CreateRelativeFilePath(base::FilePath(dir).Append(file_name));
58 }
59
60 scoped_refptr<extensions::ExtensionCreatorFilter> filter_;
61
62 base::ScopedTempDir temp_dir_;
63
64 base::FilePath extension_dir_;
65 };
66
67 struct UnaryBooleanTestData {
68 const base::FilePath::CharType* input;
69 bool expected;
70 };
71
TEST_F(ExtensionCreatorFilterTest,NormalCases)72 TEST_F(ExtensionCreatorFilterTest, NormalCases) {
73 const struct UnaryBooleanTestData cases[] = {
74 {FILE_PATH_LITERAL("foo"), true},
75 {FILE_PATH_LITERAL(".foo"), false},
76 {FILE_PATH_LITERAL("~foo"), true},
77 {FILE_PATH_LITERAL("foo~"), false},
78 {FILE_PATH_LITERAL("#foo"), true},
79 {FILE_PATH_LITERAL("foo#"), true},
80 {FILE_PATH_LITERAL("#foo#"), false},
81 {FILE_PATH_LITERAL(".svn"), false},
82 {FILE_PATH_LITERAL("__MACOSX"), false},
83 {FILE_PATH_LITERAL(".DS_Store"), false},
84 {FILE_PATH_LITERAL("desktop.ini"), false},
85 {FILE_PATH_LITERAL("Thumbs.db"), false},
86 };
87
88 for (size_t i = 0; i < base::size(cases); ++i) {
89 base::FilePath input(cases[i].input);
90 base::FilePath test_file(CreateTestFile(input));
91 bool observed = filter_->ShouldPackageFile(test_file);
92
93 EXPECT_EQ(cases[i].expected, observed)
94 << "i: " << i << ", input: " << test_file.value();
95 }
96 }
97
TEST_F(ExtensionCreatorFilterTest,MetadataFolderExcluded)98 TEST_F(ExtensionCreatorFilterTest, MetadataFolderExcluded) {
99 const struct UnaryBooleanTestData cases[] = {
100 {FILE_PATH_LITERAL("_metadata/foo"), false},
101 {FILE_PATH_LITERAL("_metadata/abc/foo"), false},
102 {FILE_PATH_LITERAL("_metadata/abc/xyz/foo"), false},
103 {FILE_PATH_LITERAL("abc/_metadata/xyz"), true},
104 {FILE_PATH_LITERAL("xyz/_metadata"), true},
105 };
106
107 // Create and test the filepaths.
108 for (size_t i = 0; i < base::size(cases); ++i) {
109 base::FilePath test_file =
110 CreateRelativeFilePath(base::FilePath(cases[i].input));
111 bool observed = filter_->ShouldPackageFile(test_file);
112
113 EXPECT_EQ(cases[i].expected, observed)
114 << "i: " << i << ", input: " << test_file.value();
115 }
116
117 // Also test directories.
118 const struct UnaryBooleanTestData directory_cases[] = {
119 {FILE_PATH_LITERAL("_metadata"), false},
120 {FILE_PATH_LITERAL("_metadata/abc"), false},
121 {FILE_PATH_LITERAL("_metadata/abc/xyz"), false},
122 {FILE_PATH_LITERAL("abc"), true},
123 {FILE_PATH_LITERAL("abc/_metadata"), true},
124 {FILE_PATH_LITERAL("xyz"), true},
125 };
126 for (size_t i = 0; i < base::size(directory_cases); ++i) {
127 base::FilePath directory = extension_dir_.Append(directory_cases[i].input);
128 bool observed = filter_->ShouldPackageFile(directory);
129
130 EXPECT_EQ(directory_cases[i].expected, observed)
131 << "i: " << i << ", input: " << directory.value();
132 }
133 }
134
135 struct StringStringWithBooleanTestData {
136 const base::FilePath::StringType file_name;
137 const base::FilePath::StringType dir;
138 bool expected;
139 };
140
141 // Ignore the files in special directories, including ".git", ".svn",
142 // "__MACOSX".
TEST_F(ExtensionCreatorFilterTest,IgnoreFilesInSpecialDir)143 TEST_F(ExtensionCreatorFilterTest, IgnoreFilesInSpecialDir) {
144 const struct StringStringWithBooleanTestData cases[] = {
145 {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL(".git"), false},
146 {FILE_PATH_LITERAL("goo"), FILE_PATH_LITERAL(".svn"), false},
147 {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("__MACOSX"), false},
148 {FILE_PATH_LITERAL("foo"), FILE_PATH_LITERAL("foo"), true},
149 {FILE_PATH_LITERAL("index.js"), FILE_PATH_LITERAL("scripts"), true},
150 };
151
152 for (size_t i = 0; i < base::size(cases); ++i) {
153 base::FilePath test_file(
154 CreateTestFileInDir(cases[i].file_name, cases[i].dir));
155 bool observed = filter_->ShouldPackageFile(test_file);
156 EXPECT_EQ(cases[i].expected, observed)
157 << "i: " << i << ", input: " << test_file.value();
158 }
159 }
160
161 #if defined(OS_WIN)
162 struct StringBooleanWithBooleanTestData {
163 const base::FilePath::CharType* input_char;
164 bool input_bool;
165 bool expected;
166 };
167
TEST_F(ExtensionCreatorFilterTest,WindowsHiddenFiles)168 TEST_F(ExtensionCreatorFilterTest, WindowsHiddenFiles) {
169 const struct StringBooleanWithBooleanTestData cases[] = {
170 {FILE_PATH_LITERAL("a-normal-file"), false, true},
171 {FILE_PATH_LITERAL(".a-dot-file"), false, false},
172 {FILE_PATH_LITERAL(".a-dot-file-that-we-have-set-to-hidden"), true,
173 false},
174 {FILE_PATH_LITERAL("a-file-that-we-have-set-to-hidden"), true, false},
175 {FILE_PATH_LITERAL("a-file-that-we-have-not-set-to-hidden"), false, true},
176 };
177
178 for (size_t i = 0; i < base::size(cases); ++i) {
179 base::FilePath input(cases[i].input_char);
180 bool should_hide = cases[i].input_bool;
181 base::FilePath test_file(CreateTestFile(input));
182
183 if (should_hide) {
184 SetFileAttributes(test_file.value().c_str(), FILE_ATTRIBUTE_HIDDEN);
185 }
186 bool observed = filter_->ShouldPackageFile(test_file);
187 EXPECT_EQ(cases[i].expected, observed)
188 << "i: " << i << ", input: " << test_file.value();
189 }
190 }
191 #endif
192
193 } // namespace
194