Home | History | Annotate | Download | only in features
      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 
     13 using chrome::VersionInfo;
     14 
     15 namespace extensions {
     16 
     17 namespace {
     18 
     19 template <class FeatureClass>
     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");
     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 
     72 TEST(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 
    114 TEST(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 
    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 }
    211 
    212 }  // namespace extensions
    213