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/common/manifest.h" 6 7#include <algorithm> 8#include <set> 9#include <string> 10 11#include "base/memory/scoped_ptr.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/values.h" 14#include "extensions/common/error_utils.h" 15#include "extensions/common/features/feature.h" 16#include "extensions/common/features/simple_feature.h" 17#include "extensions/common/install_warning.h" 18#include "extensions/common/manifest_constants.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21namespace extensions { 22 23namespace errors = manifest_errors; 24namespace keys = manifest_keys; 25 26// Not named "ManifestTest" because a test utility class has that name. 27class ManifestUnitTest : public testing::Test { 28 public: 29 ManifestUnitTest() : default_value_("test") {} 30 31 protected: 32 void AssertType(Manifest* manifest, Manifest::Type type) { 33 EXPECT_EQ(type, manifest->type()); 34 EXPECT_EQ(type == Manifest::TYPE_THEME, manifest->is_theme()); 35 EXPECT_EQ(type == Manifest::TYPE_PLATFORM_APP, 36 manifest->is_platform_app()); 37 EXPECT_EQ(type == Manifest::TYPE_LEGACY_PACKAGED_APP, 38 manifest->is_legacy_packaged_app()); 39 EXPECT_EQ(type == Manifest::TYPE_HOSTED_APP, manifest->is_hosted_app()); 40 EXPECT_EQ(type == Manifest::TYPE_SHARED_MODULE, 41 manifest->is_shared_module()); 42 } 43 44 // Helper function that replaces the Manifest held by |manifest| with a copy 45 // with its |key| changed to |value|. If |value| is NULL, then |key| will 46 // instead be deleted. 47 void MutateManifest(scoped_ptr<Manifest>* manifest, 48 const std::string& key, 49 base::Value* value) { 50 scoped_ptr<base::DictionaryValue> manifest_value( 51 manifest->get()->value()->DeepCopy()); 52 if (value) 53 manifest_value->Set(key, value); 54 else 55 manifest_value->Remove(key, NULL); 56 manifest->reset(new Manifest(Manifest::INTERNAL, manifest_value.Pass())); 57 } 58 59 std::string default_value_; 60}; 61 62// Verifies that extensions can access the correct keys. 63TEST_F(ManifestUnitTest, Extension) { 64 scoped_ptr<base::DictionaryValue> manifest_value(new base::DictionaryValue()); 65 manifest_value->SetString(keys::kName, "extension"); 66 manifest_value->SetString(keys::kVersion, "1"); 67 // Only supported in manifest_version=1. 68 manifest_value->SetString(keys::kBackgroundPageLegacy, "bg.html"); 69 manifest_value->SetString("unknown_key", "foo"); 70 71 scoped_ptr<Manifest> manifest( 72 new Manifest(Manifest::INTERNAL, manifest_value.Pass())); 73 std::string error; 74 std::vector<InstallWarning> warnings; 75 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 76 EXPECT_TRUE(error.empty()); 77 ASSERT_EQ(1u, warnings.size()); 78 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 79 80 // The known key 'background_page' should be accessible. 81 std::string value; 82 EXPECT_TRUE(manifest->GetString(keys::kBackgroundPageLegacy, &value)); 83 EXPECT_EQ("bg.html", value); 84 85 // The unknown key 'unknown_key' should be accesible. 86 value.clear(); 87 EXPECT_TRUE(manifest->GetString("unknown_key", &value)); 88 EXPECT_EQ("foo", value); 89 90 // Set the manifest_version to 2; background_page should stop working. 91 value.clear(); 92 MutateManifest( 93 &manifest, keys::kManifestVersion, new base::FundamentalValue(2)); 94 EXPECT_FALSE(manifest->GetString("background_page", &value)); 95 EXPECT_EQ("", value); 96 97 // Validate should also give a warning. 98 warnings.clear(); 99 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 100 EXPECT_TRUE(error.empty()); 101 ASSERT_EQ(2u, warnings.size()); 102 { 103 SimpleFeature feature; 104 feature.set_name("background_page"); 105 feature.set_max_manifest_version(1); 106 EXPECT_EQ( 107 "'background_page' requires manifest version of 1 or lower.", 108 warnings[0].message); 109 } 110 111 // Test DeepCopy and Equals. 112 scoped_ptr<Manifest> manifest2(manifest->DeepCopy()); 113 EXPECT_TRUE(manifest->Equals(manifest2.get())); 114 EXPECT_TRUE(manifest2->Equals(manifest.get())); 115 MutateManifest( 116 &manifest, "foo", new base::StringValue("blah")); 117 EXPECT_FALSE(manifest->Equals(manifest2.get())); 118} 119 120// Verifies that key restriction based on type works. 121TEST_F(ManifestUnitTest, ExtensionTypes) { 122 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 123 value->SetString(keys::kName, "extension"); 124 value->SetString(keys::kVersion, "1"); 125 126 scoped_ptr<Manifest> manifest( 127 new Manifest(Manifest::INTERNAL, value.Pass())); 128 std::string error; 129 std::vector<InstallWarning> warnings; 130 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 131 EXPECT_TRUE(error.empty()); 132 EXPECT_TRUE(warnings.empty()); 133 134 // By default, the type is Extension. 135 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 136 137 // Theme. 138 MutateManifest( 139 &manifest, keys::kTheme, new base::DictionaryValue()); 140 AssertType(manifest.get(), Manifest::TYPE_THEME); 141 MutateManifest( 142 &manifest, keys::kTheme, NULL); 143 144 // Shared module. 145 MutateManifest( 146 &manifest, keys::kExport, new base::DictionaryValue()); 147 AssertType(manifest.get(), Manifest::TYPE_SHARED_MODULE); 148 MutateManifest( 149 &manifest, keys::kExport, NULL); 150 151 // Packaged app. 152 MutateManifest( 153 &manifest, keys::kApp, new base::DictionaryValue()); 154 AssertType(manifest.get(), Manifest::TYPE_LEGACY_PACKAGED_APP); 155 156 // Platform app with event page. 157 MutateManifest( 158 &manifest, keys::kPlatformAppBackground, new base::DictionaryValue()); 159 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 160 MutateManifest( 161 &manifest, keys::kPlatformAppBackground, NULL); 162 163 // Hosted app. 164 MutateManifest( 165 &manifest, keys::kWebURLs, new base::ListValue()); 166 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 167 MutateManifest( 168 &manifest, keys::kWebURLs, NULL); 169 MutateManifest( 170 &manifest, keys::kLaunchWebURL, new base::StringValue("foo")); 171 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 172 MutateManifest( 173 &manifest, keys::kLaunchWebURL, NULL); 174}; 175 176// Verifies that the getters filter restricted keys. 177TEST_F(ManifestUnitTest, RestrictedKeys) { 178 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 179 value->SetString(keys::kName, "extension"); 180 value->SetString(keys::kVersion, "1"); 181 182 scoped_ptr<Manifest> manifest( 183 new Manifest(Manifest::INTERNAL, value.Pass())); 184 std::string error; 185 std::vector<InstallWarning> warnings; 186 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 187 EXPECT_TRUE(error.empty()); 188 EXPECT_TRUE(warnings.empty()); 189 190 // "Commands" requires manifest version 2. 191 const base::Value* output = NULL; 192 MutateManifest( 193 &manifest, keys::kCommands, new base::DictionaryValue()); 194 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 195 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 196 197 MutateManifest( 198 &manifest, keys::kManifestVersion, new base::FundamentalValue(2)); 199 EXPECT_TRUE(manifest->HasKey(keys::kCommands)); 200 EXPECT_TRUE(manifest->Get(keys::kCommands, &output)); 201 202 MutateManifest( 203 &manifest, keys::kPageAction, new base::DictionaryValue()); 204 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 205 EXPECT_TRUE(manifest->HasKey(keys::kPageAction)); 206 EXPECT_TRUE(manifest->Get(keys::kPageAction, &output)); 207 208 // Platform apps cannot have a "page_action" key. 209 MutateManifest( 210 &manifest, keys::kPlatformAppBackground, new base::DictionaryValue()); 211 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 212 EXPECT_FALSE(manifest->HasKey(keys::kPageAction)); 213 EXPECT_FALSE(manifest->Get(keys::kPageAction, &output)); 214 MutateManifest( 215 &manifest, keys::kPlatformAppBackground, NULL); 216 217 // Platform apps also can't have a "Commands" key. 218 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 219 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 220}; 221 222} // namespace extensions 223