Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/common/features/base_feature_provider.h" | 5 #include "extensions/common/features/base_feature_provider.h" |
| 6 | 6 |
| 7 #include "chrome/common/extensions/features/chrome_channel_feature_filter.h" | 7 #include <set> |
| 8 #include "chrome/common/extensions/features/feature_channel.h" | 8 #include <string> |
| 9 #include "extensions/common/features/permission_feature.h" | 9 |
| 10 #include "extensions/common/extension_builder.h" | |
| 11 #include "extensions/common/features/feature.h" | |
| 12 #include "extensions/common/features/simple_feature.h" | |
| 13 #include "extensions/common/manifest.h" | |
| 10 #include "extensions/common/value_builder.h" | 14 #include "extensions/common/value_builder.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 12 | 16 |
| 13 using chrome::VersionInfo; | |
| 14 | |
| 15 namespace extensions { | 17 namespace extensions { |
| 16 | 18 |
| 17 namespace { | 19 // Tests that a real manifest feature is available for the correct types of |
| 18 | 20 // extensions and apps. |
| 19 template <class FeatureClass> | 21 TEST(BaseFeatureProviderTest, ManifestFeatureTypes) { |
| 20 SimpleFeature* CreateFeature() { | |
| 21 SimpleFeature* feature = new FeatureClass(); | |
| 22 feature->AddFilter( | |
| 23 scoped_ptr<SimpleFeatureFilter>(new ChromeChannelFeatureFilter(feature))); | |
| 24 return feature; | |
| 25 } | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 29 TEST(BaseFeatureProviderTest, ManifestFeatures) { | |
| 30 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); | 22 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); |
| 23 // NOTE: This feature cannot have multiple rules, otherwise it is not a | |
| 24 // SimpleFeature. | |
| 31 SimpleFeature* feature = | 25 SimpleFeature* feature = |
| 32 static_cast<SimpleFeature*>(provider->GetFeature("description")); | 26 static_cast<SimpleFeature*>(provider->GetFeature("description")); |
| 33 ASSERT_TRUE(feature); | 27 ASSERT_TRUE(feature); |
| 34 EXPECT_EQ(6u, feature->extension_types()->size()); | 28 std::set<Manifest::Type>* extension_types = feature->extension_types(); |
| 35 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); | 29 EXPECT_EQ(6u, extension_types->size()); |
| 36 EXPECT_EQ(1u, | 30 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); |
| 37 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); | 31 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); |
| 38 EXPECT_EQ(1u, | 32 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); |
| 39 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); | 33 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_HOSTED_APP)); |
| 40 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_HOSTED_APP)); | 34 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_THEME)); |
| 41 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_THEME)); | 35 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_SHARED_MODULE)); |
| 42 EXPECT_EQ(1u, | |
| 43 feature->extension_types()->count(Manifest::TYPE_SHARED_MODULE)); | |
| 44 | |
| 45 base::DictionaryValue manifest; | |
| 46 manifest.SetString("name", "test extension"); | |
| 47 manifest.SetString("version", "1"); | |
| 48 manifest.SetString("description", "hello there"); | |
| 49 | |
| 50 std::string error; | |
| 51 scoped_refptr<const Extension> extension(Extension::Create( | |
| 52 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, | |
| 53 &error)); | |
| 54 | |
| 55 ASSERT_TRUE(extension.get()); | |
| 56 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( | |
| 57 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 58 | |
| 59 feature = | |
| 60 static_cast<SimpleFeature*>(provider->GetFeature("theme")); | |
| 61 ASSERT_TRUE(feature); | |
| 62 EXPECT_EQ(Feature::INVALID_TYPE, feature->IsAvailableToContext( | |
| 63 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 64 | |
| 65 feature = | |
| 66 static_cast<SimpleFeature*>(provider->GetFeature("devtools_page")); | |
| 67 ASSERT_TRUE(feature); | |
| 68 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( | |
| 69 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 70 } | 36 } |
| 71 | 37 |
| 72 TEST(BaseFeatureProviderTest, PermissionFeatures) { | 38 // Tests that real manifest features have the correct availability for an |
| 39 // extension. | |
| 40 TEST(BaseFeatureProviderTest, ManifestFeatureAvailability) { | |
|
James Cook
2014/09/11 23:32:31
The important changes here are switching to descri
| |
| 41 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); | |
| 42 | |
| 43 scoped_refptr<const Extension> extension = | |
| 44 ExtensionBuilder() | |
| 45 .SetManifest(DictionaryBuilder() | |
| 46 .Set("name", "test extension") | |
| 47 .Set("version", "1") | |
| 48 .Set("description", "hello there")) | |
| 49 .Build(); | |
| 50 ASSERT_TRUE(extension.get()); | |
| 51 | |
| 52 Feature* feature = provider->GetFeature("description"); | |
| 53 EXPECT_EQ(Feature::IS_AVAILABLE, | |
| 54 feature->IsAvailableToContext(extension.get(), | |
| 55 Feature::UNSPECIFIED_CONTEXT, | |
| 56 GURL()).result()); | |
| 57 | |
| 58 // This is a generic extension, so an app-only feature isn't allowed. | |
| 59 feature = provider->GetFeature("app.background"); | |
| 60 ASSERT_TRUE(feature); | |
| 61 EXPECT_EQ(Feature::INVALID_TYPE, | |
| 62 feature->IsAvailableToContext(extension.get(), | |
| 63 Feature::UNSPECIFIED_CONTEXT, | |
| 64 GURL()).result()); | |
| 65 | |
| 66 // A feature not listed in the manifest isn't allowed. | |
| 67 feature = provider->GetFeature("background"); | |
| 68 ASSERT_TRUE(feature); | |
| 69 EXPECT_EQ(Feature::NOT_PRESENT, | |
| 70 feature->IsAvailableToContext(extension.get(), | |
| 71 Feature::UNSPECIFIED_CONTEXT, | |
| 72 GURL()).result()); | |
| 73 } | |
| 74 | |
| 75 // Tests that a real permission feature is available for the correct types of | |
| 76 // extensions and apps. | |
| 77 TEST(BaseFeatureProviderTest, PermissionFeatureTypes) { | |
| 73 const FeatureProvider* provider = | 78 const FeatureProvider* provider = |
| 74 BaseFeatureProvider::GetByName("permission"); | 79 BaseFeatureProvider::GetByName("permission"); |
| 80 // NOTE: This feature cannot have multiple rules, otherwise it is not a | |
| 81 // SimpleFeature. | |
| 75 SimpleFeature* feature = | 82 SimpleFeature* feature = |
| 76 static_cast<SimpleFeature*>(provider->GetFeature("contextMenus")); | 83 static_cast<SimpleFeature*>(provider->GetFeature("power")); |
| 77 ASSERT_TRUE(feature); | 84 ASSERT_TRUE(feature); |
| 78 EXPECT_EQ(3u, feature->extension_types()->size()); | 85 std::set<Manifest::Type>* extension_types = feature->extension_types(); |
| 79 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); | 86 EXPECT_EQ(3u, extension_types->size()); |
| 80 EXPECT_EQ(1u, | 87 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); |
| 81 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); | 88 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); |
| 82 EXPECT_EQ(1u, | 89 EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); |
| 83 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); | |
| 84 | |
| 85 base::DictionaryValue manifest; | |
| 86 manifest.SetString("name", "test extension"); | |
| 87 manifest.SetString("version", "1"); | |
| 88 base::ListValue* permissions = new base::ListValue(); | |
| 89 manifest.Set("permissions", permissions); | |
| 90 permissions->Append(new base::StringValue("contextMenus")); | |
| 91 | |
| 92 std::string error; | |
| 93 scoped_refptr<const Extension> extension(Extension::Create( | |
| 94 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, | |
| 95 &error)); | |
| 96 | |
| 97 ASSERT_TRUE(extension.get()); | |
| 98 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( | |
| 99 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 100 | |
| 101 feature = | |
| 102 static_cast<SimpleFeature*>(provider->GetFeature("chromePrivate")); | |
| 103 ASSERT_TRUE(feature); | |
| 104 EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature->IsAvailableToContext( | |
| 105 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 106 | |
| 107 feature = | |
| 108 static_cast<SimpleFeature*>(provider->GetFeature("clipboardWrite")); | |
| 109 ASSERT_TRUE(feature); | |
| 110 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( | |
| 111 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); | |
| 112 } | 90 } |
| 113 | 91 |
| 114 TEST(BaseFeatureProviderTest, Validation) { | 92 // Tests that real permission features have the correct availability for an app. |
| 115 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); | 93 TEST(BaseFeatureProviderTest, PermissionFeatureAvailability) { |
|
James Cook
2014/09/11 23:32:31
Same thing here:
* SimpleFeature -> Feature
* cont
| |
| 94 const FeatureProvider* provider = | |
| 95 BaseFeatureProvider::GetByName("permission"); | |
| 116 | 96 |
| 117 base::DictionaryValue* feature1 = new base::DictionaryValue(); | 97 scoped_refptr<const Extension> app = |
| 118 feature1->SetString("channel", "trunk"); | 98 ExtensionBuilder() |
| 119 value->Set("feature1", feature1); | 99 .SetManifest(DictionaryBuilder() |
| 100 .Set("name", "test app") | |
| 101 .Set("version", "1") | |
| 102 .Set("app", | |
| 103 DictionaryBuilder().Set( | |
| 104 "background", | |
| 105 DictionaryBuilder().Set( | |
| 106 "scripts", | |
| 107 ListBuilder().Append("background.js")))) | |
| 108 .Set("permissions", ListBuilder().Append("power"))) | |
| 109 .Build(); | |
| 110 ASSERT_TRUE(app.get()); | |
| 111 ASSERT_TRUE(app->is_platform_app()); | |
| 120 | 112 |
| 121 base::DictionaryValue* feature2 = new base::DictionaryValue(); | 113 // A permission requested in the manifest is available. |
| 122 feature2->SetString("channel", "trunk"); | 114 Feature* feature = provider->GetFeature("power"); |
| 123 base::ListValue* extension_types = new base::ListValue(); | 115 EXPECT_EQ( |
| 124 extension_types->Append(new base::StringValue("extension")); | 116 Feature::IS_AVAILABLE, |
| 125 feature2->Set("extension_types", extension_types); | 117 feature->IsAvailableToContext( |
| 126 base::ListValue* contexts = new base::ListValue(); | 118 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); |
| 127 contexts->Append(new base::StringValue("blessed_extension")); | |
| 128 feature2->Set("contexts", contexts); | |
| 129 value->Set("feature2", feature2); | |
| 130 | 119 |
| 131 scoped_ptr<BaseFeatureProvider> provider( | 120 // A permission only available to whitelisted extensions returns availability |
| 132 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | 121 // NOT_FOUND_IN_WHITELIST. |
| 122 feature = provider->GetFeature("bluetoothPrivate"); | |
| 123 ASSERT_TRUE(feature); | |
| 124 EXPECT_EQ( | |
| 125 Feature::NOT_FOUND_IN_WHITELIST, | |
| 126 feature->IsAvailableToContext( | |
| 127 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); | |
| 133 | 128 |
| 134 // feature1 won't validate because it lacks an extension type. | 129 // A permission that isn't part of the manifest returns NOT_PRESENT. |
| 135 EXPECT_FALSE(provider->GetFeature("feature1")); | 130 feature = provider->GetFeature("serial"); |
| 136 | 131 ASSERT_TRUE(feature); |
| 137 // If we add one, it works. | 132 EXPECT_EQ( |
| 138 feature1->Set("extension_types", extension_types->DeepCopy()); | 133 Feature::NOT_PRESENT, |
| 139 provider.reset( | 134 feature->IsAvailableToContext( |
| 140 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | 135 app.get(), Feature::UNSPECIFIED_CONTEXT, GURL()).result()); |
| 141 EXPECT_TRUE(provider->GetFeature("feature1")); | |
| 142 | |
| 143 // Remove the channel, and feature1 won't validate. | |
| 144 feature1->Remove("channel", NULL); | |
| 145 provider.reset( | |
| 146 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | |
| 147 EXPECT_FALSE(provider->GetFeature("feature1")); | |
| 148 | |
| 149 // feature2 won't validate because of the presence of "contexts". | |
| 150 EXPECT_FALSE(provider->GetFeature("feature2")); | |
| 151 | |
| 152 // If we remove it, it works. | |
| 153 feature2->Remove("contexts", NULL); | |
| 154 provider.reset( | |
| 155 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); | |
| 156 EXPECT_TRUE(provider->GetFeature("feature2")); | |
| 157 } | |
| 158 | |
| 159 TEST(BaseFeatureProviderTest, ComplexFeatures) { | |
| 160 scoped_ptr<base::DictionaryValue> rule( | |
| 161 DictionaryBuilder() | |
| 162 .Set("feature1", ListBuilder() | |
| 163 .Append(DictionaryBuilder() | |
| 164 .Set("channel", "beta") | |
| 165 .Set("extension_types", ListBuilder() | |
| 166 .Append("extension"))) | |
| 167 .Append(DictionaryBuilder() | |
| 168 .Set("channel", "beta") | |
| 169 .Set("extension_types", ListBuilder() | |
| 170 .Append("legacy_packaged_app")))) | |
| 171 .Build()); | |
| 172 | |
| 173 scoped_ptr<BaseFeatureProvider> provider( | |
| 174 new BaseFeatureProvider(*rule, CreateFeature<SimpleFeature>)); | |
| 175 | |
| 176 Feature* feature = provider->GetFeature("feature1"); | |
| 177 EXPECT_TRUE(feature); | |
| 178 | |
| 179 // Make sure both rules are applied correctly. | |
| 180 { | |
| 181 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); | |
| 182 EXPECT_EQ( | |
| 183 Feature::IS_AVAILABLE, | |
| 184 feature->IsAvailableToManifest("1", | |
| 185 Manifest::TYPE_EXTENSION, | |
| 186 Manifest::INVALID_LOCATION, | |
| 187 Feature::UNSPECIFIED_PLATFORM).result()); | |
| 188 EXPECT_EQ( | |
| 189 Feature::IS_AVAILABLE, | |
| 190 feature->IsAvailableToManifest("2", | |
| 191 Manifest::TYPE_LEGACY_PACKAGED_APP, | |
| 192 Manifest::INVALID_LOCATION, | |
| 193 Feature::UNSPECIFIED_PLATFORM).result()); | |
| 194 } | |
| 195 { | |
| 196 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_STABLE); | |
| 197 EXPECT_NE( | |
| 198 Feature::IS_AVAILABLE, | |
| 199 feature->IsAvailableToManifest("1", | |
| 200 Manifest::TYPE_EXTENSION, | |
| 201 Manifest::INVALID_LOCATION, | |
| 202 Feature::UNSPECIFIED_PLATFORM).result()); | |
| 203 EXPECT_NE( | |
| 204 Feature::IS_AVAILABLE, | |
| 205 feature->IsAvailableToManifest("2", | |
| 206 Manifest::TYPE_LEGACY_PACKAGED_APP, | |
| 207 Manifest::INVALID_LOCATION, | |
| 208 Feature::UNSPECIFIED_PLATFORM).result()); | |
| 209 } | |
| 210 } | 136 } |
| 211 | 137 |
| 212 } // namespace extensions | 138 } // namespace extensions |
| OLD | NEW |