summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/feature.cc187
-rw-r--r--chrome/common/extensions/feature.h125
-rw-r--r--chrome/common/extensions/feature_unittest.cc258
5 files changed, 573 insertions, 0 deletions
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 08362d0..b6af34d 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -137,6 +137,8 @@
'common/extensions/extension_set.h',
'common/extensions/extension_unpacker.cc',
'common/extensions/extension_unpacker.h',
+ 'common/extensions/feature.cc',
+ 'common/extensions/feature.h',
'common/extensions/file_browser_handler.cc',
'common/extensions/file_browser_handler.h',
'common/extensions/manifest.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 19d8288..d97b136 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2030,6 +2030,7 @@
'common/extensions/extension_test_util.cc',
'common/extensions/extension_unittest.cc',
'common/extensions/extension_unpacker_unittest.cc',
+ 'common/extensions/feature_unittest.cc',
'common/extensions/manifest_unittest.cc',
'common/extensions/update_manifest_unittest.cc',
'common/extensions/url_pattern_set_unittest.cc',
diff --git a/chrome/common/extensions/feature.cc b/chrome/common/extensions/feature.cc
new file mode 100644
index 0000000..6556eb5
--- /dev/null
+++ b/chrome/common/extensions/feature.cc
@@ -0,0 +1,187 @@
+// 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/feature.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+
+namespace {
+
+struct Mappings {
+ Mappings() {
+ extension_types["extension"] = Extension::TYPE_EXTENSION;
+ extension_types["theme"] = Extension::TYPE_THEME;
+ extension_types["packaged_app"] = Extension::TYPE_PACKAGED_APP;
+ extension_types["hosted_app"] = Extension::TYPE_HOSTED_APP;
+ extension_types["platform_app"] = Extension::TYPE_PLATFORM_APP;
+
+ contexts["privileged"] = extensions::Feature::PRIVILEGED_CONTEXT;
+ contexts["unprivileged"] = extensions::Feature::UNPRIVILEGED_CONTEXT;
+ contexts["content_script"] = extensions::Feature::CONTENT_SCRIPT_CONTEXT;
+
+ locations["component"] = extensions::Feature::COMPONENT_LOCATION;
+
+ platforms["chromeos"] = extensions::Feature::CHROMEOS_PLATFORM;
+ }
+
+ std::map<std::string, Extension::Type> extension_types;
+ std::map<std::string, extensions::Feature::Context> contexts;
+ std::map<std::string, extensions::Feature::Location> locations;
+ std::map<std::string, extensions::Feature::Platform> platforms;
+};
+
+static base::LazyInstance<Mappings> g_mappings =
+ LAZY_INSTANCE_INITIALIZER;
+
+// TODO(aa): Can we replace all this manual parsing with JSON schema stuff?
+
+void ParseSet(const DictionaryValue* value,
+ const std::string& property,
+ std::set<std::string>* set) {
+ ListValue* list_value = NULL;
+ if (!value->GetList(property, &list_value))
+ return;
+
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ std::string str_val;
+ CHECK(list_value->GetString(i, &str_val)) << property << " " << i;
+ set->insert(str_val);
+ }
+}
+
+template<typename T>
+void ParseEnum(const std::string& string_value,
+ T* enum_value,
+ const std::map<std::string, T>& mapping) {
+ typename std::map<std::string, T>::const_iterator iter =
+ mapping.find(string_value);
+ CHECK(iter != mapping.end()) << string_value;
+ *enum_value = iter->second;
+}
+
+template<typename T>
+void ParseEnum(const DictionaryValue* value,
+ const std::string& property,
+ T* enum_value,
+ const std::map<std::string, T>& mapping) {
+ std::string string_value;
+ if (!value->GetString(property, &string_value))
+ return;
+ ParseEnum(string_value, enum_value, mapping);
+}
+
+template<typename T>
+void ParseEnumSet(const DictionaryValue* value,
+ const std::string& property,
+ std::set<T>* enum_set,
+ const std::map<std::string, T>& mapping) {
+ std::set<std::string> string_set;
+ ParseSet(value, property, &string_set);
+ for (std::set<std::string>::iterator iter = string_set.begin();
+ iter != string_set.end(); ++iter) {
+ if (*iter == "all") {
+ for (typename std::map<std::string, T>::const_iterator j =
+ mapping.begin(); j != mapping.end(); ++j) {
+ enum_set->insert(j->second);
+ }
+ return;
+ }
+
+ T enum_value = static_cast<T>(0);
+ ParseEnum(*iter, &enum_value, mapping);
+ enum_set->insert(enum_value);
+ }
+}
+
+} // namespace
+
+namespace extensions {
+
+Feature::Feature()
+ : location_(UNSPECIFIED_LOCATION),
+ platform_(UNSPECIFIED_PLATFORM),
+ min_manifest_version_(0),
+ max_manifest_version_(0) {
+}
+
+Feature::~Feature() {
+}
+
+// static
+scoped_ptr<Feature> Feature::Parse(const DictionaryValue* value) {
+ scoped_ptr<Feature> feature(new Feature());
+
+ ParseSet(value, "whitelist", feature->whitelist());
+ ParseEnumSet<Extension::Type>(value, "package_type",
+ feature->extension_types(),
+ g_mappings.Get().extension_types);
+ ParseEnumSet<Context>(value, "contexts", feature->contexts(),
+ g_mappings.Get().contexts);
+ ParseEnum<Location>(value, "location", &feature->location_,
+ g_mappings.Get().locations);
+ ParseEnum<Platform>(value, "platform", &feature->platform_,
+ g_mappings.Get().platforms);
+
+ value->GetInteger("min_manifest_version", &feature->min_manifest_version_);
+ value->GetInteger("max_manifest_version", &feature->max_manifest_version_);
+
+ return feature.Pass();
+}
+
+// static
+Feature::Platform Feature::GetCurrentPlatform() {
+#if defined(OS_CHROMEOS)
+ return CHROMEOS_PLATFORM;
+#else
+ return UNSPECIFIED_PLATFORM;
+#endif
+}
+
+// static
+Feature::Location Feature::ConvertLocation(Extension::Location location) {
+ if (location == Extension::COMPONENT)
+ return COMPONENT_LOCATION;
+ else
+ return UNSPECIFIED_LOCATION;
+}
+
+bool Feature::IsAvailable(const std::string& extension_id,
+ Extension::Type type,
+ Location location,
+ Context context,
+ Platform platform,
+ int manifest_version) {
+ if (!whitelist_.empty() &&
+ whitelist_.find(extension_id) == whitelist_.end()) {
+ return false;
+ }
+
+ if (!extension_types_.empty() &&
+ extension_types_.find(type) == extension_types_.end()) {
+ return false;
+ }
+
+ if (!contexts_.empty() &&
+ contexts_.find(context) == contexts_.end()) {
+ return false;
+ }
+
+ if (location_ != UNSPECIFIED_LOCATION && location_ != location)
+ return false;
+
+ if (platform_ != UNSPECIFIED_PLATFORM && platform_ != platform)
+ return false;
+
+ if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_)
+ return false;
+
+ if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_)
+ return false;
+
+ return true;
+}
+
+} // namespace
diff --git a/chrome/common/extensions/feature.h b/chrome/common/extensions/feature.h
new file mode 100644
index 0000000..0a95689
--- /dev/null
+++ b/chrome/common/extensions/feature.h
@@ -0,0 +1,125 @@
+// 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.
+
+#ifndef CHROME_COMMON_EXTENSIONS_FEATURE_H_
+#define CHROME_COMMON_EXTENSIONS_FEATURE_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+
+namespace extensions {
+
+// Represents a single feature accessible to an extension developer, such as a
+// top-level manifest key, a permission, or a programmatic API. A feature can
+// express requirements for where it can be accessed, and supports testing
+// support for those requirements.
+class Feature {
+ public:
+ // The JavaScript contexts the feature is supported in.
+ enum Context {
+ UNSPECIFIED_CONTEXT,
+ PRIVILEGED_CONTEXT, // A context in a privileged extension process.
+ UNPRIVILEGED_CONTEXT, // A context in a normal, unprivileged renderer.
+ CONTENT_SCRIPT_CONTEXT // A context from a content script.
+ };
+
+ // The location required of extensions the feature is supported in.
+ enum Location {
+ UNSPECIFIED_LOCATION,
+ COMPONENT_LOCATION
+ };
+
+ // The platforms the feature is supported in.
+ enum Platform {
+ UNSPECIFIED_PLATFORM,
+ CHROMEOS_PLATFORM
+ };
+
+ Feature();
+ ~Feature();
+
+ // Parses a feature from its JSON representation.
+ static scoped_ptr<Feature> Parse(const DictionaryValue* value);
+
+ // Gets the platform the code is currently running on.
+ static Platform GetCurrentPlatform();
+
+ // Gets the Feature::Location value for the specified Extension::Location.
+ static Location ConvertLocation(Extension::Location extension_location);
+
+ std::set<std::string>* whitelist() { return &whitelist_; }
+ std::set<Extension::Type>* extension_types() { return &extension_types_; }
+ std::set<Context>* contexts() { return &contexts_; }
+
+ Location location() const { return location_; }
+ void set_location(Location location) { location_ = location; }
+
+ Platform platform() const { return platform_; }
+ void set_platform(Platform platform) { platform_ = platform; }
+
+ int min_manifest_version() const { return min_manifest_version_; }
+ void set_min_manifest_version(int min_manifest_version) {
+ min_manifest_version_ = min_manifest_version;
+ }
+
+ int max_manifest_version() const { return max_manifest_version_; }
+ void set_max_manifest_version(int max_manifest_version) {
+ max_manifest_version_ = max_manifest_version;
+ }
+
+ // Returns true if the feature is available to the specified extension. Use
+ // this overload for features that are not associated with a specific context.
+ bool IsAvailable(const Extension* extension) {
+ return IsAvailable(extension, UNSPECIFIED_CONTEXT);
+ }
+
+ // Returns true if the feature is available to the specified extension, in the
+ // specified context type.
+ bool IsAvailable(const Extension* extension, Context context) {
+ return IsAvailable(extension->id(), extension->GetType(),
+ ConvertLocation(extension->location()), context,
+ GetCurrentPlatform(),
+ extension->manifest_version());
+ }
+
+ // Returns true if the feature is available to extensions with the specified
+ // properties. Use this overload for features that are not associated with a
+ // specific context, and when a full Extension object is not available.
+ bool IsAvailable(const std::string& extension_id, Extension::Type type,
+ Location location, int manifest_version) {
+ return IsAvailable(extension_id, type, location, UNSPECIFIED_CONTEXT,
+ GetCurrentPlatform(), manifest_version);
+ }
+
+ // Returns true if the feature is available to extensions with the specified
+ // properties, in the specified context type, and on the specified platform.
+ // This overload is mainly used for testing.
+ bool IsAvailable(const std::string& extension_id, Extension::Type type,
+ Location location, Context context,
+ Platform platform, int manifest_version);
+
+ private:
+ // For clarify and consistency, we handle the default value of each of these
+ // members the same way: it matches everything. It is up to the higher level
+ // code that reads Features out of static data to validate that data and set
+ // sensible defaults.
+ std::set<std::string> whitelist_;
+ std::set<Extension::Type> extension_types_;
+ std::set<Context> contexts_;
+ Location location_; // we only care about component/not-component now
+ Platform platform_; // we only care about chromeos/not-chromeos now
+ int min_manifest_version_;
+ int max_manifest_version_;
+
+ DISALLOW_COPY_AND_ASSIGN(Feature);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_FEATURE_H_
diff --git a/chrome/common/extensions/feature_unittest.cc b/chrome/common/extensions/feature_unittest.cc
new file mode 100644
index 0000000..9fb2df9
--- /dev/null
+++ b/chrome/common/extensions/feature_unittest.cc
@@ -0,0 +1,258 @@
+// 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/feature.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::Feature;
+
+namespace {
+
+struct IsAvailableTestData {
+ std::string extension_id;
+ Extension::Type extension_type;
+ Feature::Context context;
+ Feature::Location location;
+ Feature::Platform platform;
+ int manifest_version;
+ bool expected_result;
+};
+
+} // namespace
+
+TEST(ExtensionFeatureTest, IsAvailableNullCase) {
+ const IsAvailableTestData tests[] = {
+ { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true },
+ { "random-extension", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true },
+ { "", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true },
+ { "", Extension::TYPE_UNKNOWN, Feature::PRIVILEGED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true },
+ { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT,
+ Feature::COMPONENT_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true },
+ { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::CHROMEOS_PLATFORM, -1, true },
+ { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT,
+ Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, 25, true }
+ };
+
+ Feature feature;
+ for (size_t i = 0; i < arraysize(tests); ++i) {
+ const IsAvailableTestData& test = tests[i];
+ EXPECT_EQ(test.expected_result,
+ feature.IsAvailable(test.extension_id, test.extension_type,
+ test.location, test.context, test.platform,
+ test.manifest_version));
+ }
+}
+
+TEST(ExtensionFeatureTest, Whitelist) {
+ Feature feature;
+ feature.whitelist()->insert("foo");
+ feature.whitelist()->insert("bar");
+
+ EXPECT_TRUE(feature.IsAvailable(
+ "foo", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_TRUE(feature.IsAvailable(
+ "bar", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+
+ EXPECT_FALSE(feature.IsAvailable(
+ "baz", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+
+ feature.extension_types()->insert(Extension::TYPE_PACKAGED_APP);
+ EXPECT_FALSE(feature.IsAvailable(
+ "baz", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+}
+
+TEST(ExtensionFeatureTest, PackageType) {
+ Feature feature;
+ feature.extension_types()->insert(Extension::TYPE_EXTENSION);
+ feature.extension_types()->insert(Extension::TYPE_PACKAGED_APP);
+
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_EXTENSION, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_THEME, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+}
+
+TEST(ExtensionFeatureTest, Context) {
+ Feature feature;
+ feature.contexts()->insert(Feature::PRIVILEGED_CONTEXT);
+ feature.contexts()->insert(Feature::CONTENT_SCRIPT_CONTEXT);
+
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::PRIVILEGED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::CONTENT_SCRIPT_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNPRIVILEGED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+}
+
+TEST(ExtensionFeatureTest, Location) {
+ Feature feature;
+ feature.set_location(Feature::COMPONENT_LOCATION);
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::COMPONENT_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+}
+
+TEST(ExtensionFeatureTest, Platform) {
+ Feature feature;
+ feature.set_platform(Feature::CHROMEOS_PLATFORM);
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::CHROMEOS_PLATFORM, -1));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1));
+}
+
+TEST(ExtensionFeatureTest, Version) {
+ Feature feature;
+ feature.set_min_manifest_version(5);
+
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 0));
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 4));
+
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 5));
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 10));
+
+ feature.set_max_manifest_version(8);
+
+ EXPECT_FALSE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 10));
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 8));
+ EXPECT_TRUE(feature.IsAvailable(
+ "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION,
+ Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 7));
+}
+
+TEST(ExtensionFeatureTest, ParseNull) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_TRUE(feature->whitelist()->empty());
+ EXPECT_TRUE(feature->extension_types()->empty());
+ EXPECT_TRUE(feature->contexts()->empty());
+ EXPECT_EQ(Feature::UNSPECIFIED_LOCATION, feature->location());
+ EXPECT_EQ(Feature::UNSPECIFIED_PLATFORM, feature->platform());
+ EXPECT_EQ(0, feature->min_manifest_version());
+ EXPECT_EQ(0, feature->max_manifest_version());
+}
+
+TEST(ExtensionFeatureTest, ParseWhitelist) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ ListValue* whitelist = new ListValue();
+ whitelist->Append(Value::CreateStringValue("foo"));
+ whitelist->Append(Value::CreateStringValue("bar"));
+ value->Set("whitelist", whitelist);
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(2u, feature->whitelist()->size());
+ EXPECT_TRUE(feature->whitelist()->count("foo"));
+ EXPECT_TRUE(feature->whitelist()->count("bar"));
+}
+
+TEST(ExtensionFeatureTest, ParsePackageTypes) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ ListValue* extension_types = new ListValue();
+ extension_types->Append(Value::CreateStringValue("extension"));
+ extension_types->Append(Value::CreateStringValue("theme"));
+ extension_types->Append(Value::CreateStringValue("packaged_app"));
+ extension_types->Append(Value::CreateStringValue("hosted_app"));
+ extension_types->Append(Value::CreateStringValue("platform_app"));
+ value->Set("package_type", extension_types);
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(5u, feature->extension_types()->size());
+ EXPECT_TRUE(feature->extension_types()->count(Extension::TYPE_EXTENSION));
+ EXPECT_TRUE(feature->extension_types()->count(Extension::TYPE_THEME));
+ EXPECT_TRUE(feature->extension_types()->count(Extension::TYPE_PACKAGED_APP));
+ EXPECT_TRUE(feature->extension_types()->count(Extension::TYPE_HOSTED_APP));
+ EXPECT_TRUE(feature->extension_types()->count(Extension::TYPE_PLATFORM_APP));
+
+ extension_types->Clear();
+ extension_types->Append(Value::CreateStringValue("all"));
+ scoped_ptr<Feature> feature2(Feature::Parse(value.get()));
+ EXPECT_EQ(*(feature->extension_types()), *(feature2->extension_types()));
+}
+
+TEST(ExtensionFeatureTest, ParseContexts) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ ListValue* contexts = new ListValue();
+ contexts->Append(Value::CreateStringValue("privileged"));
+ contexts->Append(Value::CreateStringValue("unprivileged"));
+ contexts->Append(Value::CreateStringValue("content_script"));
+ value->Set("contexts", contexts);
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(3u, feature->contexts()->size());
+ EXPECT_TRUE(feature->contexts()->count(Feature::PRIVILEGED_CONTEXT));
+ EXPECT_TRUE(feature->contexts()->count(Feature::UNPRIVILEGED_CONTEXT));
+ EXPECT_TRUE(feature->contexts()->count(Feature::CONTENT_SCRIPT_CONTEXT));
+
+ contexts->Clear();
+ contexts->Append(Value::CreateStringValue("all"));
+ scoped_ptr<Feature> feature2(Feature::Parse(value.get()));
+ EXPECT_EQ(*(feature->contexts()), *(feature2->contexts()));
+}
+
+TEST(ExtensionFeatureTest, ParseLocation) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->SetString("location", "component");
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(Feature::COMPONENT_LOCATION, feature->location());
+}
+
+TEST(ExtensionFeatureTest, ParsePlatform) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->SetString("platform", "chromeos");
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(Feature::CHROMEOS_PLATFORM, feature->platform());
+}
+
+TEST(ExtensionFeatureTest, ManifestVersion) {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->SetInteger("min_manifest_version", 1);
+ value->SetInteger("max_manifest_version", 5);
+ scoped_ptr<Feature> feature(Feature::Parse(value.get()));
+ EXPECT_EQ(1, feature->min_manifest_version());
+ EXPECT_EQ(5, feature->max_manifest_version());
+}