text: // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/common/extensions/features/base_feature_provider.h"
  
  #include "chrome/common/extensions/features/feature_channel.h"
  #include "chrome/common/extensions/features/permission_feature.h"
  #include "extensions/common/value_builder.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  using chrome::VersionInfo;
  
  namespace extensions {
  
  TEST(BaseFeatureProviderTest, ManifestFeatures) {
    FeatureProvider* provider = BaseFeatureProvider::GetByName("manifest");
    SimpleFeature* feature =
        static_cast<SimpleFeature*>(provider->GetFeature("description"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(6u, feature->extension_types()->size());
    EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION));
    EXPECT_EQ(1u,
        feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP));
    EXPECT_EQ(1u,
              feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP));
    EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_HOSTED_APP));
    EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_THEME));
    EXPECT_EQ(1u,
              feature->extension_types()->count(Manifest::TYPE_SHARED_MODULE));
  
    base::DictionaryValue manifest;
    manifest.SetString("name", "test extension");
    manifest.SetString("version", "1");
    manifest.SetString("description", "hello there");
  
    std::string error;
    scoped_refptr<const Extension> extension(Extension::Create(
        base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS,
        &error));
  
    ASSERT_TRUE(extension.get());
    EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  
    feature =
      static_cast<SimpleFeature*>(provider->GetFeature("theme"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(Feature::INVALID_TYPE, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  
    feature =
      static_cast<SimpleFeature*>(provider->GetFeature("devtools_page"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  }
  
  TEST(BaseFeatureProviderTest, PermissionFeatures) {
    FeatureProvider* provider = BaseFeatureProvider::GetByName("permission");
    SimpleFeature* feature =
        static_cast<SimpleFeature*>(provider->GetFeature("contextMenus"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(3u, feature->extension_types()->size());
    EXPECT_EQ(1u, feature->extension_types()->count(Manifest::TYPE_EXTENSION));
    EXPECT_EQ(1u,
        feature->extension_types()->count(Manifest::TYPE_LEGACY_PACKAGED_APP));
    EXPECT_EQ(1u,
              feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP));
  
    base::DictionaryValue manifest;
    manifest.SetString("name", "test extension");
    manifest.SetString("version", "1");
    base::ListValue* permissions = new base::ListValue();
    manifest.Set("permissions", permissions);
    permissions->Append(new base::StringValue("contextMenus"));
  
    std::string error;
    scoped_refptr<const Extension> extension(Extension::Create(
        base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS,
        &error));
  
    ASSERT_TRUE(extension.get());
    EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  
    feature =
      static_cast<SimpleFeature*>(provider->GetFeature("chromePrivate"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  
    feature =
      static_cast<SimpleFeature*>(provider->GetFeature("clipboardWrite"));
    ASSERT_TRUE(feature);
    EXPECT_EQ(Feature::NOT_PRESENT, feature->IsAvailableToContext(
        extension.get(), Feature::UNSPECIFIED_CONTEXT).result());
  }
  
  SimpleFeature* CreatePermissionFeature() {
    return new PermissionFeature();
  }
  
  TEST(BaseFeatureProviderTest, Validation) {
    scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
  
    base::DictionaryValue* feature1 = new base::DictionaryValue();
    feature1->SetString("channel", "trunk");
    value->Set("feature1", feature1);
  
    base::DictionaryValue* feature2 = new base::DictionaryValue();
    feature2->SetString("channel", "trunk");
    base::ListValue* extension_types = new base::ListValue();
    extension_types->Append(new base::StringValue("extension"));
    feature2->Set("extension_types", extension_types);
    base::ListValue* contexts = new base::ListValue();
    contexts->Append(new base::StringValue("blessed_extension"));
    feature2->Set("contexts", contexts);
    value->Set("feature2", feature2);
  
    scoped_ptr<BaseFeatureProvider> provider(
        new BaseFeatureProvider(*value, CreatePermissionFeature));
  
    // feature1 won't validate because it lacks an extension type.
    EXPECT_FALSE(provider->GetFeature("feature1"));
  
    // If we add one, it works.
    feature1->Set("extension_types", extension_types->DeepCopy());
    provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature));
    EXPECT_TRUE(provider->GetFeature("feature1"));
  
    // Remove the channel, and feature1 won't validate.
    feature1->Remove("channel", NULL);
    provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature));
    EXPECT_FALSE(provider->GetFeature("feature1"));
  
    // feature2 won't validate because of the presence of "contexts".
    EXPECT_FALSE(provider->GetFeature("feature2"));
  
    // If we remove it, it works.
    feature2->Remove("contexts", NULL);
    provider.reset(new BaseFeatureProvider(*value, CreatePermissionFeature));
    EXPECT_TRUE(provider->GetFeature("feature2"));
  }
  
  TEST(BaseFeatureProviderTest, ComplexFeatures) {
    scoped_ptr<base::DictionaryValue> rule(
        DictionaryBuilder()
        .Set("feature1", ListBuilder()
            .Append(DictionaryBuilder()
                .Set("channel", "beta")
                .Set("extension_types", ListBuilder()
                    .Append("extension")))
                    .Append(DictionaryBuilder()
                        .Set("channel", "beta")
                        .Set("extension_types", ListBuilder()
                            .Append("legacy_packaged_app"))))
        .Build());
  
    scoped_ptr<BaseFeatureProvider> provider(
        new BaseFeatureProvider(*rule, NULL));
  
    Feature* feature = provider->GetFeature("feature1");
    EXPECT_TRUE(feature);
  
    // Make sure both rules are applied correctly.
    {
      ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_BETA);
      EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToManifest(
          "1",
          Manifest::TYPE_EXTENSION,
          Feature::UNSPECIFIED_LOCATION,
          Feature::UNSPECIFIED_PLATFORM).result());
      EXPECT_EQ(Feature::IS_AVAILABLE, feature->IsAvailableToManifest(
          "2",
          Manifest::TYPE_LEGACY_PACKAGED_APP,
          Feature::UNSPECIFIED_LOCATION,
          Feature::UNSPECIFIED_PLATFORM).result());
    }
    {
      ScopedCurrentChannel current_channel(VersionInfo::CHANNEL_STABLE);
      EXPECT_NE(Feature::IS_AVAILABLE, feature->IsAvailableToManifest(
          "1",
          Manifest::TYPE_EXTENSION,
          Feature::UNSPECIFIED_LOCATION,
          Feature::UNSPECIFIED_PLATFORM).result());
      EXPECT_NE(Feature::IS_AVAILABLE, feature->IsAvailableToManifest(
          "2",
          Manifest::TYPE_LEGACY_PACKAGED_APP,
          Feature::UNSPECIFIED_LOCATION,
          Feature::UNSPECIFIED_PLATFORM).result());
    }
  }
  
  }  // namespace extensions
  