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 "chrome/common/extensions/features/base_feature_provider.h" 6 7 #include "chrome/common/extensions/features/feature_channel.h" 8 #include "chrome/common/extensions/features/permission_feature.h" 9 #include "chrome/common/extensions/value_builder.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 using chrome::VersionInfo; 13 14 namespace extensions { 15 16 TEST(BaseFeatureProviderTest, ManifestFeatures) { 17 FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest"); 18 SimpleFeature* feature = 19 static_cast<SimpleFeature*>(provider->GetFeature("description")); 20 ASSERT_TRUE(feature); 21 EXPECT_EQ(6u, feature->extension_types()->size()); 22 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); 23 EXPECT_EQ(1u, 24 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); 25 EXPECT_EQ(1u, 26 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); 27 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_HOSTED_APP)); 28 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_THEME)); 29 EXPECT_EQ(1u, 30 feature->extension_types()->count(Manifest::TYPE_SHARED_MODULE)); 31 32 base::DictionaryValue manifest; 33 manifest.SetString("name", "test extension"); 34 manifest.SetString("version", "1"); 35 manifest.SetString("description", "hello there"); 36 37 std::string error; 38 scoped_refptr<const Extension> extension(Extension::Create( 39 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, 40 &error)); 41 42 ASSERT_TRUE(extension.get()); 43 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( 44 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 45 46 feature = 47 static_cast<SimpleFeature*>(provider->GetFeature("theme")); 48 ASSERT_TRUE(feature); 49 EXPECT_EQ(Feature::INVALID_TYPE, feature->IsAvailableToContext( 50 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 51 52 feature = 53 static_cast<SimpleFeature*>(provider->GetFeature("devtools_page")); 54 ASSERT_TRUE(feature); 55 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( 56 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 57 } 58 59 TEST(BaseFeatureProviderTest, PermissionFeatures) { 60 FeatureProvider* provider = BaseFeatureProvider::GetByName("permission"); 61 SimpleFeature* feature = 62 static_cast<SimpleFeature*>(provider->GetFeature("contextMenus")); 63 ASSERT_TRUE(feature); 64 EXPECT_EQ(3u, feature->extension_types()->size()); 65 EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION)); 66 EXPECT_EQ(1u, 67 feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); 68 EXPECT_EQ(1u, 69 feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); 70 71 base::DictionaryValue manifest; 72 manifest.SetString("name", "test extension"); 73 manifest.SetString("version", "1"); 74 base::ListValue* permissions = new base::ListValue(); 75 manifest.Set("permissions", permissions); 76 permissions->Append(new base::StringValue("contextMenus")); 77 78 std::string error; 79 scoped_refptr<const Extension> extension(Extension::Create( 80 base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS, 81 &error)); 82 83 ASSERT_TRUE(extension.get()); 84 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext( 85 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 86 87 feature = 88 static_cast<SimpleFeature*>(provider->GetFeature("chromePrivate")); 89 ASSERT_TRUE(feature); 90 EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature->IsAvailableToContext( 91 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 92 93 feature = 94 static_cast<SimpleFeature*>(provider->GetFeature("clipboardWrite")); 95 ASSERT_TRUE(feature); 96 EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext( 97 extension.get(), Feature::UNSPECIFIED_CONTEXT).result()); 98 } 99 100 SimpleFeature* CreatePermissionFeature() { 101 return new PermissionFeature(); 102 } 103 104 TEST(BaseFeatureProviderTest, Validation) { 105 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 106 107 base::DictionaryValue* feature1 = new base::DictionaryValue(); 108 feature1->SetString("channel", "trunk"); 109 value->Set("feature1", feature1); 110 111 base::DictionaryValue* feature2 = new base::DictionaryValue(); 112 feature2->SetString("channel", "trunk"); 113 base::ListValue* extension_types = new base::ListValue(); 114 extension_types->Append(new base::StringValue("extension")); 115 feature2->Set("extension_types", extension_types); 116 base::ListValue* contexts = new base::ListValue(); 117 contexts->Append(new base::StringValue("blessed_extension")); 118 feature2->Set("contexts", contexts); 119 value->Set("feature2", feature2); 120 121 scoped_ptr<BaseFeatureProvider> provider( 122 new BaseFeatureProvider(*value, CreatePermissionFeature)); 123 124 // feature1 won't validate because it lacks an extension type. 125 EXPECT_FALSE(provider->GetFeature("feature1")); 126 127 // If we add one, it works. 128 feature1->Set("extension_types", extension_types->DeepCopy()); 129 provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature)); 130 EXPECT_TRUE(provider->GetFeature("feature1")); 131 132 // Remove the channel, and feature1 won't validate. 133 feature1->Remove("channel", NULL); 134 provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature)); 135 EXPECT_FALSE(provider->GetFeature("feature1")); 136 137 // feature2 won't validate because of the presence of "contexts". 138 EXPECT_FALSE(provider->GetFeature("feature2")); 139 140 // If we remove it, it works. 141 feature2->Remove("contexts", NULL); 142 provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature)); 143 EXPECT_TRUE(provider->GetFeature("feature2")); 144 } 145 146 TEST(BaseFeatureProviderTest, ComplexFeatures) { 147 scoped_ptr<base::DictionaryValue> rule( 148 DictionaryBuilder() 149 .Set("feature1", 150 ListBuilder().Append(DictionaryBuilder() 151 .Set("channel", "beta") 152 .Set("extension_types", 153 ListBuilder().Append("extension"))) 154 .Append(DictionaryBuilder() 155 .Set("channel", "beta") 156 .Set("extension_types", 157 ListBuilder().Append("packaged_app")))) 158 .Build()); 159 160 scoped_ptr<BaseFeatureProvider> provider( 161 new BaseFeatureProvider(*rule, NULL)); 162 163 Feature* feature = provider->GetFeature("feature1"); 164 EXPECT_TRUE(feature); 165 166 // Make sure both rules are applied correctly. 167 { 168 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA); 169 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToManifest( 170 "1", 171 Manifest::TYPE_EXTENSION, 172 Feature::UNSPECIFIED_LOCATION, 173 Feature::UNSPECIFIED_PLATFORM).result()); 174 EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToManifest( 175 "2", 176 Manifest::TYPE_LEGACY_PACKAGED_APP, 177 Feature::UNSPECIFIED_LOCATION, 178 Feature::UNSPECIFIED_PLATFORM).result()); 179 } 180 { 181 ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_STABLE); 182 EXPECT_NE(Feature::IS_AVAILABLE, feature->IsAvailableToManifest( 183 "1", 184 Manifest::TYPE_EXTENSION, 185 Feature::UNSPECIFIED_LOCATION, 186 Feature::UNSPECIFIED_PLATFORM).result()); 187 EXPECT_NE(Feature::IS_AVAILABLE, feature->IsAvailableToManifest( 188 "2", 189 Manifest::TYPE_LEGACY_PACKAGED_APP, 190 Feature::UNSPECIFIED_LOCATION, 191 Feature::UNSPECIFIED_PLATFORM).result()); 192 } 193 } 194 195 } // namespace extensions 196