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 3// found in the LICENSE file. 4 5#include "extensions/common/features/base_feature_provider.h" 6 7#include "chrome/common/extensions/features/chrome_channel_feature_filter.h" 8#include "chrome/common/extensions/features/feature_channel.h" 9#include "extensions/common/features/permission_feature.h" 10#include "extensions/common/value_builder.h" 11#include "testing/gtest/include/gtest/gtest.h" 12 13using chrome::VersionInfo; 14 15namespace extensions { 16 17namespace { 18 19template <class FeatureClass> 20SimpleFeature* CreateFeature() { 21 SimpleFeature* feature = new FeatureClass(); 22 feature->AddFilter( 23 scoped_ptr<SimpleFeatureFilter>(new ChromeChannelFeatureFilter(feature))); 24 return feature; 25} 26 27} // namespace 28 29TEST(BaseFeatureProviderTest, ManifestFeatures) { 30 const FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); 31 SimpleFeature* feature = 32 static_cast<SimpleFeature*>(provider->GetFeature("description")); 33 ASSERT_TRUE(feature); 34 EXPECT_EQ(6u, feature->extension_types()->size()); 35 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); 36 EXPECT_EQ(1u, 37 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); 38 EXPECT_EQ(1u, 39 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); 40 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_HOSTED_APP)); 41 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_THEME)); 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} 71 72TEST(BaseFeatureProviderTest, PermissionFeatures) { 73 const FeatureProvider* provider = 74 BaseFeatureProvider::GetByName("permission"); 75 SimpleFeature* feature = 76 static_cast<SimpleFeature*>(provider->GetFeature("contextMenus")); 77 ASSERT_TRUE(feature); 78 EXPECT_EQ(3u, feature->extension_types()->size()); 79 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); 80 EXPECT_EQ(1u, 81 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); 82 EXPECT_EQ(1u, 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} 113 114TEST(BaseFeatureProviderTest, Validation) { 115 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 116 117 base::DictionaryValue* feature1 = new base::DictionaryValue(); 118 feature1->SetString("channel", "trunk"); 119 value->Set("feature1", feature1); 120 121 base::DictionaryValue* feature2 = new base::DictionaryValue(); 122 feature2->SetString("channel", "trunk"); 123 base::ListValue* extension_types = new base::ListValue(); 124 extension_types->Append(new base::StringValue("extension")); 125 feature2->Set("extension_types", extension_types); 126 base::ListValue* contexts = new base::ListValue(); 127 contexts->Append(new base::StringValue("blessed_extension")); 128 feature2->Set("contexts", contexts); 129 value->Set("feature2", feature2); 130 131 scoped_ptr<BaseFeatureProvider> provider( 132 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); 133 134 // feature1 won't validate because it lacks an extension type. 135 EXPECT_FALSE(provider->GetFeature("feature1")); 136 137 // If we add one, it works. 138 feature1->Set("extension_types", extension_types->DeepCopy()); 139 provider.reset( 140 new BaseFeatureProvider(*value, CreateFeature<PermissionFeature>)); 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 159TEST(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} 211 212} // namespace extensions 213