1 // Copyright (c) 2011 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 "chrome/common/extensions/extension_file_util.h" 6 7 #include "base/file_util.h" 8 #include "base/memory/scoped_temp_dir.h" 9 #include "base/path_service.h" 10 #include "base/utf_string_conversions.h" 11 #include "chrome/common/chrome_paths.h" 12 #include "chrome/common/extensions/extension.h" 13 #include "chrome/common/extensions/extension_constants.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace keys = extension_manifest_keys; 17 18 TEST(ExtensionFileUtil, InstallUninstallGarbageCollect) { 19 ScopedTempDir temp; 20 ASSERT_TRUE(temp.CreateUniqueTempDir()); 21 22 // Create a source extension. 23 std::string extension_id("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); 24 std::string version("1.0"); 25 FilePath src = temp.path().AppendASCII(extension_id); 26 ASSERT_TRUE(file_util::CreateDirectory(src)); 27 28 // Create a extensions tree. 29 FilePath all_extensions = temp.path().AppendASCII("extensions"); 30 ASSERT_TRUE(file_util::CreateDirectory(all_extensions)); 31 32 // Install in empty directory. Should create parent directories as needed. 33 FilePath version_1 = extension_file_util::InstallExtension(src, 34 extension_id, 35 version, 36 all_extensions); 37 ASSERT_EQ(version_1.value(), 38 all_extensions.AppendASCII(extension_id).AppendASCII("1.0_0") 39 .value()); 40 ASSERT_TRUE(file_util::DirectoryExists(version_1)); 41 42 // Should have moved the source. 43 ASSERT_FALSE(file_util::DirectoryExists(src)); 44 45 // Install again. Should create a new one with different name. 46 ASSERT_TRUE(file_util::CreateDirectory(src)); 47 FilePath version_2 = extension_file_util::InstallExtension(src, 48 extension_id, 49 version, 50 all_extensions); 51 ASSERT_EQ(version_2.value(), 52 all_extensions.AppendASCII(extension_id).AppendASCII("1.0_1") 53 .value()); 54 ASSERT_TRUE(file_util::DirectoryExists(version_2)); 55 56 // Collect garbage. Should remove first one. 57 std::map<std::string, FilePath> extension_paths; 58 extension_paths[extension_id] = 59 FilePath().AppendASCII(extension_id).Append(version_2.BaseName()); 60 extension_file_util::GarbageCollectExtensions(all_extensions, 61 extension_paths); 62 ASSERT_FALSE(file_util::DirectoryExists(version_1)); 63 ASSERT_TRUE(file_util::DirectoryExists(version_2)); 64 65 // Uninstall. Should remove entire extension subtree. 66 extension_file_util::UninstallExtension(all_extensions, extension_id); 67 ASSERT_FALSE(file_util::DirectoryExists(version_2.DirName())); 68 ASSERT_TRUE(file_util::DirectoryExists(all_extensions)); 69 } 70 71 TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) { 72 FilePath install_dir; 73 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); 74 install_dir = install_dir.AppendASCII("extensions") 75 .AppendASCII("good") 76 .AppendASCII("Extensions") 77 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 78 .AppendASCII("1.0.0.0"); 79 80 std::string error; 81 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( 82 install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error)); 83 ASSERT_TRUE(extension != NULL); 84 EXPECT_EQ("The first extension that I made.", extension->description()); 85 } 86 87 TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) { 88 FilePath install_dir; 89 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); 90 install_dir = install_dir.AppendASCII("extensions") 91 .AppendASCII("good") 92 .AppendASCII("Extensions") 93 .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") 94 .AppendASCII("1.0"); 95 96 std::string error; 97 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( 98 install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error)); 99 ASSERT_FALSE(extension == NULL); 100 EXPECT_TRUE(error.empty()); 101 } 102 103 TEST(ExtensionFileUtil, CheckIllegalFilenamesNoUnderscores) { 104 ScopedTempDir temp; 105 ASSERT_TRUE(temp.CreateUniqueTempDir()); 106 107 FilePath src_path = temp.path().AppendASCII("some_dir"); 108 ASSERT_TRUE(file_util::CreateDirectory(src_path)); 109 110 std::string data = "{ \"name\": { \"message\": \"foobar\" } }"; 111 ASSERT_TRUE(file_util::WriteFile(src_path.AppendASCII("some_file.txt"), 112 data.c_str(), data.length())); 113 std::string error; 114 EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(), 115 &error)); 116 } 117 118 TEST(ExtensionFileUtil, CheckIllegalFilenamesOnlyReserved) { 119 ScopedTempDir temp; 120 ASSERT_TRUE(temp.CreateUniqueTempDir()); 121 122 FilePath src_path = temp.path().Append(Extension::kLocaleFolder); 123 ASSERT_TRUE(file_util::CreateDirectory(src_path)); 124 125 std::string error; 126 EXPECT_TRUE(extension_file_util::CheckForIllegalFilenames(temp.path(), 127 &error)); 128 } 129 130 TEST(ExtensionFileUtil, CheckIllegalFilenamesReservedAndIllegal) { 131 ScopedTempDir temp; 132 ASSERT_TRUE(temp.CreateUniqueTempDir()); 133 134 FilePath src_path = temp.path().Append(Extension::kLocaleFolder); 135 ASSERT_TRUE(file_util::CreateDirectory(src_path)); 136 137 src_path = temp.path().AppendASCII("_some_dir"); 138 ASSERT_TRUE(file_util::CreateDirectory(src_path)); 139 140 std::string error; 141 EXPECT_FALSE(extension_file_util::CheckForIllegalFilenames(temp.path(), 142 &error)); 143 } 144 145 TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnMissingManifest) { 146 FilePath install_dir; 147 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); 148 install_dir = install_dir.AppendASCII("extensions") 149 .AppendASCII("bad") 150 .AppendASCII("Extensions") 151 .AppendASCII("dddddddddddddddddddddddddddddddd") 152 .AppendASCII("1.0"); 153 154 std::string error; 155 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( 156 install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error)); 157 ASSERT_TRUE(extension == NULL); 158 ASSERT_FALSE(error.empty()); 159 ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str()); 160 } 161 162 TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnBadManifest) { 163 FilePath install_dir; 164 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); 165 install_dir = install_dir.AppendASCII("extensions") 166 .AppendASCII("bad") 167 .AppendASCII("Extensions") 168 .AppendASCII("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") 169 .AppendASCII("1.0"); 170 171 std::string error; 172 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( 173 install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error)); 174 ASSERT_TRUE(extension == NULL); 175 ASSERT_FALSE(error.empty()); 176 ASSERT_STREQ("Manifest is not valid JSON. " 177 "Line: 2, column: 16, Syntax error.", error.c_str()); 178 } 179 180 TEST(ExtensionFileUtil, FailLoadingNonUTF8Scripts) { 181 FilePath install_dir; 182 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir)); 183 install_dir = install_dir.AppendASCII("extensions") 184 .AppendASCII("bad") 185 .AppendASCII("bad_encoding"); 186 187 std::string error; 188 scoped_refptr<Extension> extension(extension_file_util::LoadExtension( 189 install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error)); 190 ASSERT_TRUE(extension == NULL); 191 ASSERT_STREQ("Could not load file 'bad_encoding.js' for content script. " 192 "It isn't UTF-8 encoded.", error.c_str()); 193 } 194 195 #define URL_PREFIX "chrome-extension://extension-id/" 196 197 TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) { 198 struct TestCase { 199 const char* url; 200 const char* expected_relative_path; 201 } test_cases[] = { 202 { URL_PREFIX "simple.html", 203 "simple.html" }, 204 { URL_PREFIX "directory/to/file.html", 205 "directory/to/file.html" }, 206 { URL_PREFIX "escape%20spaces.html", 207 "escape spaces.html" }, 208 { URL_PREFIX "%C3%9Cber.html", 209 "\xC3\x9C" "ber.html" }, 210 #if defined(OS_WIN) 211 { URL_PREFIX "C%3A/simple.html", 212 "" }, 213 #endif 214 { URL_PREFIX "////simple.html", 215 "simple.html" }, 216 { URL_PREFIX "/simple.html", 217 "simple.html" }, 218 { URL_PREFIX "\\simple.html", 219 "simple.html" }, 220 { URL_PREFIX "\\\\foo\\simple.html", 221 "foo/simple.html" }, 222 }; 223 224 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { 225 GURL url(test_cases[i].url); 226 #if defined(OS_POSIX) 227 FilePath expected_path(test_cases[i].expected_relative_path); 228 #elif defined(OS_WIN) 229 FilePath expected_path(UTF8ToWide(test_cases[i].expected_relative_path)); 230 #endif 231 232 FilePath actual_path = 233 extension_file_util::ExtensionURLToRelativeFilePath(url); 234 EXPECT_FALSE(actual_path.IsAbsolute()) << 235 " For the path " << actual_path.value(); 236 EXPECT_EQ(expected_path.value(), actual_path.value()) << 237 " For the path " << url; 238 } 239 } 240 241 // TODO(aa): More tests as motivation allows. Maybe steal some from 242 // ExtensionService? Many of them could probably be tested here without the 243 // MessageLoop shenanigans. 244