Home | History | Annotate | Download | only in extensions
      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