Commit 43eb02c2 authored by robliao's avatar robliao Committed by Commit bot

Refactor Uses of std::set to std::vector in SimpleFeature

Local profiling suggests that converting std::set to std::vector will save
around 10% of the overall startup time, likely due to the reduced allocs
involved with std::vector.

This change also reduces lookups by traversing the incoming dictionary
and iterating on the available values instead of looking through all
values for all features.

Finally, cleaned up and enforced the testing accessors via code and friend
declarations

BUG=460987

Review URL: https://codereview.chromium.org/1010973013

Cr-Commit-Position: refs/heads/master@{#322609}
parent ddde1d3e
...@@ -90,6 +90,14 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin, ...@@ -90,6 +90,14 @@ void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
} }
} }
// Counts the number of instances of val in a container.
template <typename Container, typename T>
typename std::iterator_traits<
typename Container::const_iterator>::difference_type
STLCount(const Container& container, const T& val) {
return std::count(container.begin(), container.end(), val);
}
// To treat a possibly-empty vector as an array, use these functions. // To treat a possibly-empty vector as an array, use these functions.
// If you know the array will never be empty, you can use &*v.begin() // If you know the array will never be empty, you can use &*v.begin()
// directly, but that is undefined behaviour if |v| is empty. // directly, but that is undefined behaviour if |v| is empty.
...@@ -195,6 +203,14 @@ bool ContainsKey(const Collection& collection, const Key& key) { ...@@ -195,6 +203,14 @@ bool ContainsKey(const Collection& collection, const Key& key) {
return collection.find(key) != collection.end(); return collection.find(key) != collection.end();
} }
// Test to see if a collection like a vector contains a particular value.
// Returns true if the value is in the collection.
template <typename Collection, typename Value>
bool ContainsValue(const Collection& collection, const Value& value) {
return std::find(collection.begin(), collection.end(), value) !=
collection.end();
}
namespace base { namespace base {
// Returns true if the container is sorted. // Returns true if the container is sorted.
......
...@@ -138,10 +138,10 @@ void InternalExtensionProvider::Observe( ...@@ -138,10 +138,10 @@ void InternalExtensionProvider::Observe(
"48CA541313139786F056DBCB504A1025CFF5D2E3", "48CA541313139786F056DBCB504A1025CFF5D2E3",
"05106136AE7F08A3C181D4648E5438350B1D2B4F" "05106136AE7F08A3C181D4648E5438350B1D2B4F"
}; };
if (extensions::SimpleFeature::IsIdInList( if (extensions::SimpleFeature::IsIdInArray(
host->extension()->id(), host->extension()->id(),
std::set<std::string>( kAppWhitelist,
kAppWhitelist, kAppWhitelist + arraysize(kAppWhitelist)))) { arraysize(kAppWhitelist))) {
SetContentSettingForExtensionAndResource( SetContentSettingForExtensionAndResource(
host->extension(), host->extension(),
ChromeContentClient::kRemotingViewerPluginPath, ChromeContentClient::kRemotingViewerPluginPath,
......
...@@ -91,10 +91,8 @@ bool TabCaptureCaptureFunction::RunSync() { ...@@ -91,10 +91,8 @@ bool TabCaptureCaptureFunction::RunSync() {
APIPermission::kTabCaptureForTab) && APIPermission::kTabCaptureForTab) &&
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kWhitelistedExtensionID) != extension_id && switches::kWhitelistedExtensionID) != extension_id &&
!SimpleFeature::IsIdInList( !SimpleFeature::IsIdInArray(
extension_id, extension_id, kWhitelist, arraysize(kWhitelist))) {
std::set<std::string>(kWhitelist,
kWhitelist + arraysize(kWhitelist)))) {
error_ = kGrantError; error_ = kGrantError;
return false; return false;
} }
......
...@@ -41,11 +41,8 @@ bool ExternalComponentLoader::IsModifiable(const Extension* extension) { ...@@ -41,11 +41,8 @@ bool ExternalComponentLoader::IsModifiable(const Extension* extension) {
"D57DE394F36DC1C3220E7604C575D29C51A6C495", // http://crbug.com/319444 "D57DE394F36DC1C3220E7604C575D29C51A6C495", // http://crbug.com/319444
"3F65507A3B39259B38C8173C6FFA3D12DF64CCE9" // http://crbug.com/371562 "3F65507A3B39259B38C8173C6FFA3D12DF64CCE9" // http://crbug.com/371562
}; };
return SimpleFeature::IsIdInList( return SimpleFeature::IsIdInArray(
extension->id(), extension->id(), kEnhancedExtensions, arraysize(kEnhancedExtensions));
std::set<std::string>(
kEnhancedExtensions,
kEnhancedExtensions + arraysize(kEnhancedExtensions)));
} }
return false; return false;
} }
......
...@@ -263,10 +263,8 @@ bool AppWindowCreateFunction::RunAsync() { ...@@ -263,10 +263,8 @@ bool AppWindowCreateFunction::RunAsync() {
"0F585FB1D0FDFBEBCE1FEB5E9DFFB6DA476B8C9B" "0F585FB1D0FDFBEBCE1FEB5E9DFFB6DA476B8C9B"
}; };
if (AppWindowClient::Get()->IsCurrentChannelOlderThanDev() && if (AppWindowClient::Get()->IsCurrentChannelOlderThanDev() &&
!SimpleFeature::IsIdInList( !SimpleFeature::IsIdInArray(
extension_id(), extension_id(), kWhitelist, arraysize(kWhitelist))) {
std::set<std::string>(kWhitelist,
kWhitelist + arraysize(kWhitelist)))) {
error_ = app_window_constants::kAlphaEnabledWrongChannel; error_ = app_window_constants::kAlphaEnabledWrongChannel;
return false; return false;
} }
......
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
#include "extensions/common/features/base_feature_provider.h" #include "extensions/common/features/base_feature_provider.h"
#include <algorithm>
#include <set> #include <set>
#include <string> #include <string>
#include "base/stl_util.h"
#include "extensions/common/extension_builder.h" #include "extensions/common/extension_builder.h"
#include "extensions/common/features/feature.h" #include "extensions/common/features/feature.h"
#include "extensions/common/features/simple_feature.h" #include "extensions/common/features/simple_feature.h"
...@@ -24,14 +26,16 @@ TEST(BaseFeatureProviderTest, ManifestFeatureTypes) { ...@@ -24,14 +26,16 @@ TEST(BaseFeatureProviderTest, ManifestFeatureTypes) {
const SimpleFeature* feature = static_cast<const SimpleFeature*>( const SimpleFeature* feature = static_cast<const SimpleFeature*>(
FeatureProvider::GetManifestFeature("description")); FeatureProvider::GetManifestFeature("description"));
ASSERT_TRUE(feature); ASSERT_TRUE(feature);
const std::set<Manifest::Type>* extension_types = feature->extension_types(); const std::vector<Manifest::Type>* extension_types =
feature->extension_types();
EXPECT_EQ(6u, extension_types->size()); EXPECT_EQ(6u, extension_types->size());
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_EXTENSION));
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); EXPECT_EQ(1,
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); STLCount(*(extension_types), Manifest::TYPE_LEGACY_PACKAGED_APP));
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_HOSTED_APP)); EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_PLATFORM_APP));
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_THEME)); EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_HOSTED_APP));
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_SHARED_MODULE)); EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_THEME));
EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_SHARED_MODULE));
} }
// Tests that real manifest features have the correct availability for an // Tests that real manifest features have the correct availability for an
...@@ -79,11 +83,13 @@ TEST(BaseFeatureProviderTest, PermissionFeatureTypes) { ...@@ -79,11 +83,13 @@ TEST(BaseFeatureProviderTest, PermissionFeatureTypes) {
const SimpleFeature* feature = static_cast<const SimpleFeature*>( const SimpleFeature* feature = static_cast<const SimpleFeature*>(
BaseFeatureProvider::GetPermissionFeature("power")); BaseFeatureProvider::GetPermissionFeature("power"));
ASSERT_TRUE(feature); ASSERT_TRUE(feature);
const std::set<Manifest::Type>* extension_types = feature->extension_types(); const std::vector<Manifest::Type>* extension_types =
feature->extension_types();
EXPECT_EQ(3u, extension_types->size()); EXPECT_EQ(3u, extension_types->size());
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_EXTENSION)); EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_EXTENSION));
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_LEGACY_PACKAGED_APP)); EXPECT_EQ(1,
EXPECT_EQ(1u, extension_types->count(Manifest::TYPE_PLATFORM_APP)); STLCount(*(extension_types), Manifest::TYPE_LEGACY_PACKAGED_APP));
EXPECT_EQ(1, STLCount(*(extension_types), Manifest::TYPE_PLATFORM_APP));
} }
// Tests that real permission features have the correct availability for an app. // Tests that real permission features have the correct availability for an app.
......
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
#include "extensions/common/features/simple_feature.h" #include "extensions/common/features/simple_feature.h"
#include <algorithm>
#include <map> #include <map>
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/lazy_instance.h"
#include "base/sha1.h" #include "base/sha1.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
...@@ -43,56 +43,23 @@ Feature::Availability IsAvailableToContextForBind(const Extension* extension, ...@@ -43,56 +43,23 @@ Feature::Availability IsAvailableToContextForBind(const Extension* extension,
return feature->IsAvailableToContext(extension, context, url, platform); return feature->IsAvailableToContext(extension, context, url, platform);
} }
struct Mappings {
Mappings() {
extension_types["extension"] = Manifest::TYPE_EXTENSION;
extension_types["theme"] = Manifest::TYPE_THEME;
extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP;
extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP;
extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP;
extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE;
contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT;
contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT;
contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT;
contexts["web_page"] = Feature::WEB_PAGE_CONTEXT;
contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT;
contexts["webui"] = Feature::WEBUI_CONTEXT;
locations["component"] = SimpleFeature::COMPONENT_LOCATION;
locations["external_component"] =
SimpleFeature::EXTERNAL_COMPONENT_LOCATION;
locations["policy"] = SimpleFeature::POLICY_LOCATION;
platforms["chromeos"] = Feature::CHROMEOS_PLATFORM;
platforms["linux"] = Feature::LINUX_PLATFORM;
platforms["mac"] = Feature::MACOSX_PLATFORM;
platforms["win"] = Feature::WIN_PLATFORM;
}
std::map<std::string, Manifest::Type> extension_types;
std::map<std::string, Feature::Context> contexts;
std::map<std::string, SimpleFeature::Location> locations;
std::map<std::string, Feature::Platform> platforms;
};
base::LazyInstance<Mappings> g_mappings = LAZY_INSTANCE_INITIALIZER;
// TODO(aa): Can we replace all this manual parsing with JSON schema stuff? // TODO(aa): Can we replace all this manual parsing with JSON schema stuff?
void ParseSet(const base::DictionaryValue* value, void ParseVector(const base::Value* value,
const std::string& property, std::vector<std::string>* vector) {
std::set<std::string>* set) {
const base::ListValue* list_value = NULL; const base::ListValue* list_value = NULL;
if (!value->GetList(property, &list_value)) if (!value->GetAsList(&list_value))
return; return;
set->clear(); vector->clear();
for (size_t i = 0; i < list_value->GetSize(); ++i) { size_t list_size = list_value->GetSize();
vector->reserve(list_size);
for (size_t i = 0; i < list_size; ++i) {
std::string str_val; std::string str_val;
CHECK(list_value->GetString(i, &str_val)) << property << " " << i; CHECK(list_value->GetString(i, &str_val));
set->insert(str_val); vector->push_back(str_val);
} }
std::sort(vector->begin(), vector->end());
} }
template<typename T> template<typename T>
...@@ -124,31 +91,30 @@ void ParseEnum(const base::DictionaryValue* value, ...@@ -124,31 +91,30 @@ void ParseEnum(const base::DictionaryValue* value,
} }
template<typename T> template<typename T>
void ParseEnumSet(const base::DictionaryValue* value, void ParseEnumVector(const base::Value* value,
const std::string& property, std::vector<T>* enum_vector,
std::set<T>* enum_set, const std::map<std::string, T>& mapping) {
const std::map<std::string, T>& mapping) { enum_vector->clear();
if (!value->HasKey(property))
return;
enum_set->clear();
std::string property_string; std::string property_string;
if (value->GetString(property, &property_string)) { if (value->GetAsString(&property_string)) {
if (property_string == "all") { if (property_string == "all") {
enum_vector->reserve(mapping.size());
for (const auto& it : mapping) for (const auto& it : mapping)
enum_set->insert(it.second); enum_vector->push_back(it.second);
} }
std::sort(enum_vector->begin(), enum_vector->end());
return; return;
} }
std::set<std::string> string_set; std::vector<std::string> string_vector;
ParseSet(value, property, &string_set); ParseVector(value, &string_vector);
for (const auto& str : string_set) { enum_vector->reserve(string_vector.size());
for (const auto& str : string_vector) {
T enum_value = static_cast<T>(0); T enum_value = static_cast<T>(0);
ParseEnum(str, &enum_value, mapping); ParseEnum(str, &enum_value, mapping);
enum_set->insert(enum_value); enum_vector->push_back(enum_value);
} }
std::sort(enum_vector->begin(), enum_vector->end());
} }
void ParseURLPatterns(const base::DictionaryValue* value, void ParseURLPatterns(const base::DictionaryValue* value,
...@@ -258,6 +224,39 @@ bool IsCommandLineSwitchEnabled(const std::string& switch_name) { ...@@ -258,6 +224,39 @@ bool IsCommandLineSwitchEnabled(const std::string& switch_name) {
} // namespace } // namespace
struct SimpleFeature::Mappings {
Mappings() {
extension_types["extension"] = Manifest::TYPE_EXTENSION;
extension_types["theme"] = Manifest::TYPE_THEME;
extension_types["legacy_packaged_app"] = Manifest::TYPE_LEGACY_PACKAGED_APP;
extension_types["hosted_app"] = Manifest::TYPE_HOSTED_APP;
extension_types["platform_app"] = Manifest::TYPE_PLATFORM_APP;
extension_types["shared_module"] = Manifest::TYPE_SHARED_MODULE;
contexts["blessed_extension"] = Feature::BLESSED_EXTENSION_CONTEXT;
contexts["unblessed_extension"] = Feature::UNBLESSED_EXTENSION_CONTEXT;
contexts["content_script"] = Feature::CONTENT_SCRIPT_CONTEXT;
contexts["web_page"] = Feature::WEB_PAGE_CONTEXT;
contexts["blessed_web_page"] = Feature::BLESSED_WEB_PAGE_CONTEXT;
contexts["webui"] = Feature::WEBUI_CONTEXT;
locations["component"] = SimpleFeature::COMPONENT_LOCATION;
locations["external_component"] =
SimpleFeature::EXTERNAL_COMPONENT_LOCATION;
locations["policy"] = SimpleFeature::POLICY_LOCATION;
platforms["chromeos"] = Feature::CHROMEOS_PLATFORM;
platforms["linux"] = Feature::LINUX_PLATFORM;
platforms["mac"] = Feature::MACOSX_PLATFORM;
platforms["win"] = Feature::WIN_PLATFORM;
}
std::map<std::string, Manifest::Type> extension_types;
std::map<std::string, Feature::Context> contexts;
std::map<std::string, SimpleFeature::Location> locations;
std::map<std::string, Feature::Platform> platforms;
};
SimpleFeature::SimpleFeature() SimpleFeature::SimpleFeature()
: location_(UNSPECIFIED_LOCATION), : location_(UNSPECIFIED_LOCATION),
min_manifest_version_(0), min_manifest_version_(0),
...@@ -274,29 +273,49 @@ void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) { ...@@ -274,29 +273,49 @@ void SimpleFeature::AddFilter(scoped_ptr<SimpleFeatureFilter> filter) {
filters_.push_back(filter.release()); filters_.push_back(filter.release());
} }
std::string SimpleFeature::Parse(const base::DictionaryValue* value) { std::string SimpleFeature::Parse(const base::DictionaryValue* dictionary) {
ParseURLPatterns(value, "matches", &matches_); static base::LazyInstance<SimpleFeature::Mappings> mappings =
ParseSet(value, "blacklist", &blacklist_); LAZY_INSTANCE_INITIALIZER;
ParseSet(value, "whitelist", &whitelist_);
ParseSet(value, "dependencies", &dependencies_);
ParseEnumSet<Manifest::Type>(value, "extension_types", &extension_types_,
g_mappings.Get().extension_types);
ParseEnumSet<Context>(value, "contexts", &contexts_,
g_mappings.Get().contexts);
ParseEnum<Location>(value, "location", &location_,
g_mappings.Get().locations);
ParseEnumSet<Platform>(value, "platforms", &platforms_,
g_mappings.Get().platforms);
value->GetInteger("min_manifest_version", &min_manifest_version_);
value->GetInteger("max_manifest_version", &max_manifest_version_);
no_parent_ = false; no_parent_ = false;
value->GetBoolean("noparent", &no_parent_); for (base::DictionaryValue::Iterator it(*dictionary);
!it.IsAtEnd();
value->GetBoolean("component_extensions_auto_granted", it.Advance()) {
&component_extensions_auto_granted_); std::string key = it.key();
const base::Value* value = &it.value();
value->GetString("command_line_switch", &command_line_switch_); if (key == "matches") {
ParseURLPatterns(dictionary, "matches", &matches_);
} else if (key == "blacklist") {
ParseVector(value, &blacklist_);
} else if (key == "whitelist") {
ParseVector(value, &whitelist_);
} else if (key == "dependencies") {
ParseVector(value, &dependencies_);
} else if (key == "extension_types") {
ParseEnumVector<Manifest::Type>(value, &extension_types_,
mappings.Get().extension_types);
} else if (key == "contexts") {
ParseEnumVector<Context>(value, &contexts_,
mappings.Get().contexts);
} else if (key == "location") {
ParseEnum<Location>(dictionary, "location", &location_,
mappings.Get().locations);
} else if (key == "platforms") {
ParseEnumVector<Platform>(value, &platforms_,
mappings.Get().platforms);
} else if (key == "min_manifest_version") {
dictionary->GetInteger("min_manifest_version", &min_manifest_version_);
} else if (key == "max_manifest_version") {
dictionary->GetInteger("max_manifest_version", &max_manifest_version_);
} else if (key == "noparent") {
dictionary->GetBoolean("noparent", &no_parent_);
} else if (key == "component_extensions_auto_granted") {
dictionary->GetBoolean("component_extensions_auto_granted",
&component_extensions_auto_granted_);
} else if (key == "command_line_switch") {
dictionary->GetString("command_line_switch", &command_line_switch_);
}
}
// NOTE: ideally we'd sanity check that "matches" can be specified if and // NOTE: ideally we'd sanity check that "matches" can be specified if and
// only if there's a "web_page" or "webui" context, but without // only if there's a "web_page" or "webui" context, but without
...@@ -309,7 +328,7 @@ std::string SimpleFeature::Parse(const base::DictionaryValue* value) { ...@@ -309,7 +328,7 @@ std::string SimpleFeature::Parse(const base::DictionaryValue* value) {
std::string result; std::string result;
for (const auto& filter : filters_) { for (const auto& filter : filters_) {
result = filter->Parse(value); result = filter->Parse(dictionary);
if (!result.empty()) if (!result.empty())
break; break;
} }
...@@ -330,7 +349,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( ...@@ -330,7 +349,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ? Manifest::Type type_to_check = (type == Manifest::TYPE_USER_SCRIPT) ?
Manifest::TYPE_EXTENSION : type; Manifest::TYPE_EXTENSION : type;
if (!extension_types_.empty() && if (!extension_types_.empty() &&
!ContainsKey(extension_types_, type_to_check)) { !ContainsValue(extension_types_, type_to_check)) {
return CreateAvailability(INVALID_TYPE, type); return CreateAvailability(INVALID_TYPE, type);
} }
...@@ -363,7 +382,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest( ...@@ -363,7 +382,7 @@ Feature::Availability SimpleFeature::IsAvailableToManifest(
if (!MatchesManifestLocation(location)) if (!MatchesManifestLocation(location))
return CreateAvailability(INVALID_LOCATION, type); return CreateAvailability(INVALID_LOCATION, type);
if (!platforms_.empty() && !ContainsKey(platforms_, platform)) if (!platforms_.empty() && !ContainsValue(platforms_, platform))
return CreateAvailability(INVALID_PLATFORM, type); return CreateAvailability(INVALID_PLATFORM, type);
if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_)
...@@ -407,7 +426,7 @@ Feature::Availability SimpleFeature::IsAvailableToContext( ...@@ -407,7 +426,7 @@ Feature::Availability SimpleFeature::IsAvailableToContext(
return result; return result;
} }
if (!contexts_.empty() && !ContainsKey(contexts_, context)) if (!contexts_.empty() && !ContainsValue(contexts_, context))
return CreateAvailability(INVALID_CONTEXT, context); return CreateAvailability(INVALID_CONTEXT, context);
// TODO(kalman): Consider checking |matches_| regardless of context type. // TODO(kalman): Consider checking |matches_| regardless of context type.
...@@ -538,18 +557,28 @@ bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const { ...@@ -538,18 +557,28 @@ bool SimpleFeature::IsIdInWhitelist(const std::string& extension_id) const {
return IsIdInList(extension_id, whitelist_); return IsIdInList(extension_id, whitelist_);
} }
// static
bool SimpleFeature::IsIdInArray(const std::string& extension_id,
const char* const array[],
size_t array_length) {
if (!IsValidExtensionId(extension_id))
return false;
const char* const* start = array;
const char* const* end = array + array_length;
return ((std::find(start, end, extension_id) != end) ||
(std::find(start, end, HashExtensionId(extension_id)) != end));
}
// static // static
bool SimpleFeature::IsIdInList(const std::string& extension_id, bool SimpleFeature::IsIdInList(const std::string& extension_id,
const std::set<std::string>& list) { const std::vector<std::string>& list) {
// Belt-and-suspenders philosophy here. We should be pretty confident by this if (!IsValidExtensionId(extension_id))
// point that we've validated the extension ID format, but in case something
// slips through, we avoid a class of attack where creative ID manipulation
// leads to hash collisions.
if (extension_id.length() != 32) // 128 bits / 4 = 32 mpdecimal characters
return false; return false;
return (ContainsKey(list, extension_id) || return (ContainsValue(list, extension_id) ||
ContainsKey(list, HashExtensionId(extension_id))); ContainsValue(list, HashExtensionId(extension_id)));
} }
bool SimpleFeature::MatchesManifestLocation( bool SimpleFeature::MatchesManifestLocation(
...@@ -583,4 +612,14 @@ Feature::Availability SimpleFeature::CheckDependencies( ...@@ -583,4 +612,14 @@ Feature::Availability SimpleFeature::CheckDependencies(
return CreateAvailability(IS_AVAILABLE); return CreateAvailability(IS_AVAILABLE);
} }
// static
bool SimpleFeature::IsValidExtensionId(const std::string& extension_id) {
// Belt-and-suspenders philosophy here. We should be pretty confident by this
// point that we've validated the extension ID format, but in case something
// slips through, we avoid a class of attack where creative ID manipulation
// leads to hash collisions.
// 128 bits / 4 = 32 mpdecimal characters
return (extension_id.length() == 32);
}
} // namespace extensions } // namespace extensions
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h" #include "base/memory/scoped_vector.h"
#include "base/values.h" #include "base/values.h"
...@@ -21,53 +22,16 @@ ...@@ -21,53 +22,16 @@
namespace extensions { namespace extensions {
class BaseFeatureProviderTest;
class ExtensionAPITest;
class ManifestUnitTest;
class SimpleFeatureTest;
class SimpleFeature : public Feature { class SimpleFeature : public Feature {
public: public:
SimpleFeature(); SimpleFeature();
~SimpleFeature() override; ~SimpleFeature() override;
// Similar to Manifest::Location, these are the classes of locations
// supported in feature files.
//
// This is only public for testing. Production code should never access it,
// nor should it really have any reason to access the SimpleFeature class
// directly, it should be dealing with the Feature interface.
enum Location {
UNSPECIFIED_LOCATION,
COMPONENT_LOCATION,
EXTERNAL_COMPONENT_LOCATION,
POLICY_LOCATION,
};
// Accessors defined for testing. See comment above about not directly using
// SimpleFeature in production code.
std::set<std::string>* blacklist() { return &blacklist_; }
const std::set<std::string>* blacklist() const { return &blacklist_; }
std::set<std::string>* whitelist() { return &whitelist_; }
const std::set<std::string>* whitelist() const { return &whitelist_; }
std::set<Manifest::Type>* extension_types() { return &extension_types_; }
const std::set<Manifest::Type>* extension_types() const {
return &extension_types_;
}
std::set<Context>* contexts() { return &contexts_; }
const std::set<Context>* contexts() const { return &contexts_; }
Location location() const { return location_; }
void set_location(Location location) { location_ = location; }
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;
}
const std::string& command_line_switch() const {
return command_line_switch_;
}
void set_command_line_switch(const std::string& command_line_switch) {
command_line_switch_ = command_line_switch;
}
// Dependency resolution is a property of Features that is preferrably // Dependency resolution is a property of Features that is preferrably
// handled internally to avoid temptation, but FeatureFilters may need // handled internally to avoid temptation, but FeatureFilters may need
// to know if there are any at all. // to know if there are any at all.
...@@ -80,9 +44,7 @@ class SimpleFeature : public Feature { ...@@ -80,9 +44,7 @@ class SimpleFeature : public Feature {
// Unspecified values in the JSON are not modified in the object. This allows // Unspecified values in the JSON are not modified in the object. This allows
// us to implement inheritance by parsing one value after another. Returns // us to implement inheritance by parsing one value after another. Returns
// the error found, or an empty string on success. // the error found, or an empty string on success.
virtual std::string Parse(const base::DictionaryValue* value); virtual std::string Parse(const base::DictionaryValue* dictionary);
std::set<Platform>* platforms() { return &platforms_; }
Availability IsAvailableToContext(const Extension* extension, Availability IsAvailableToContext(const Extension* extension,
Context context) const { Context context) const {
...@@ -120,10 +82,51 @@ class SimpleFeature : public Feature { ...@@ -120,10 +82,51 @@ class SimpleFeature : public Feature {
bool IsIdInBlacklist(const std::string& extension_id) const override; bool IsIdInBlacklist(const std::string& extension_id) const override;
bool IsIdInWhitelist(const std::string& extension_id) const override; bool IsIdInWhitelist(const std::string& extension_id) const override;
static bool IsIdInList(const std::string& extension_id,
const std::set<std::string>& list); static bool IsIdInArray(const std::string& extension_id,
const char* const array[],
size_t array_length);
protected: protected:
// Similar to Manifest::Location, these are the classes of locations
// supported in feature files. Production code should never directly access
// these.
enum Location {
UNSPECIFIED_LOCATION,
COMPONENT_LOCATION,
EXTERNAL_COMPONENT_LOCATION,
POLICY_LOCATION,
};
// Accessors defined for testing.
std::vector<std::string>* blacklist() { return &blacklist_; }
const std::vector<std::string>* blacklist() const { return &blacklist_; }
std::vector<std::string>* whitelist() { return &whitelist_; }
const std::vector<std::string>* whitelist() const { return &whitelist_; }
std::vector<Manifest::Type>* extension_types() { return &extension_types_; }
const std::vector<Manifest::Type>* extension_types() const {
return &extension_types_;
}
std::vector<Context>* contexts() { return &contexts_; }
const std::vector<Context>* contexts() const { return &contexts_; }
std::vector<Platform>* platforms() { return &platforms_; }
Location location() const { return location_; }
void set_location(Location location) { location_ = location; }
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;
}
const std::string& command_line_switch() const {
return command_line_switch_;
}
void set_command_line_switch(const std::string& command_line_switch) {
command_line_switch_ = command_line_switch;
}
// Handy utilities which construct the correct availability message. // Handy utilities which construct the correct availability message.
Availability CreateAvailability(AvailabilityResult result) const; Availability CreateAvailability(AvailabilityResult result) const;
Availability CreateAvailability(AvailabilityResult result, Availability CreateAvailability(AvailabilityResult result,
...@@ -134,23 +137,55 @@ class SimpleFeature : public Feature { ...@@ -134,23 +137,55 @@ class SimpleFeature : public Feature {
Context context) const; Context context) const;
private: private:
friend class SimpleFeatureTest;
FRIEND_TEST_ALL_PREFIXES(BaseFeatureProviderTest, ManifestFeatureTypes);
FRIEND_TEST_ALL_PREFIXES(BaseFeatureProviderTest, PermissionFeatureTypes);
FRIEND_TEST_ALL_PREFIXES(ExtensionAPITest, DefaultConfigurationFeatures);
FRIEND_TEST_ALL_PREFIXES(ManifestUnitTest, Extension);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Blacklist);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, CommandLineSwitch);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Context);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdBlacklist);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, HashedIdWhitelist);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Inheritance);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Location);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ManifestVersion);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, PackageType);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParseContexts);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParseLocation);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParseManifestVersion);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParseNull);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParsePackageTypes);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParsePlatforms);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, ParseWhitelist);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Platform);
FRIEND_TEST_ALL_PREFIXES(SimpleFeatureTest, Whitelist);
// Holds String to Enum value mappings.
struct Mappings;
static bool IsIdInList(const std::string& extension_id,
const std::vector<std::string>& list);
bool MatchesManifestLocation(Manifest::Location manifest_location) const; bool MatchesManifestLocation(Manifest::Location manifest_location) const;
Availability CheckDependencies( Availability CheckDependencies(
const base::Callback<Availability(const Feature*)>& checker) const; const base::Callback<Availability(const Feature*)>& checker) const;
static bool IsValidExtensionId(const std::string& extension_id);
// For clarity and consistency, we handle the default value of each of these // For clarity 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 // 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 // code that reads Features out of static data to validate that data and set
// sensible defaults. // sensible defaults.
std::set<std::string> blacklist_; std::vector<std::string> blacklist_;
std::set<std::string> whitelist_; std::vector<std::string> whitelist_;
std::set<std::string> dependencies_; std::vector<std::string> dependencies_;
std::set<Manifest::Type> extension_types_; std::vector<Manifest::Type> extension_types_;
std::set<Context> contexts_; std::vector<Context> contexts_;
std::vector<Platform> platforms_;
URLPatternSet matches_; URLPatternSet matches_;
Location location_; Location location_;
std::set<Platform> platforms_;
int min_manifest_version_; int min_manifest_version_;
int max_manifest_version_; int max_manifest_version_;
bool component_extensions_auto_granted_; bool component_extensions_auto_granted_;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <string> #include <string>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/stl_util.h"
#include "base/values.h" #include "base/values.h"
#include "extensions/common/manifest.h" #include "extensions/common/manifest.h"
#include "extensions/common/value_builder.h" #include "extensions/common/value_builder.h"
...@@ -25,19 +26,6 @@ struct IsAvailableTestData { ...@@ -25,19 +26,6 @@ struct IsAvailableTestData {
Feature::AvailabilityResult expected_result; Feature::AvailabilityResult expected_result;
}; };
bool LocationIsAvailable(SimpleFeature::Location feature_location,
Manifest::Location manifest_location) {
SimpleFeature feature;
feature.set_location(feature_location);
Feature::AvailabilityResult availability_result =
feature.IsAvailableToManifest(std::string(),
Manifest::TYPE_UNKNOWN,
manifest_location,
-1,
Feature::UNSPECIFIED_PLATFORM).result();
return availability_result == Feature::IS_AVAILABLE;
}
class ScopedCommandLineSwitch { class ScopedCommandLineSwitch {
public: public:
explicit ScopedCommandLineSwitch(const std::string& arg) explicit ScopedCommandLineSwitch(const std::string& arg)
...@@ -55,7 +43,23 @@ class ScopedCommandLineSwitch { ...@@ -55,7 +43,23 @@ class ScopedCommandLineSwitch {
} // namespace } // namespace
TEST(SimpleFeatureTest, IsAvailableNullCase) { class SimpleFeatureTest : public testing::Test {
protected:
bool LocationIsAvailable(SimpleFeature::Location feature_location,
Manifest::Location manifest_location) {
SimpleFeature feature;
feature.set_location(feature_location);
Feature::AvailabilityResult availability_result =
feature.IsAvailableToManifest(std::string(),
Manifest::TYPE_UNKNOWN,
manifest_location,
-1,
Feature::UNSPECIFIED_PLATFORM).result();
return availability_result == Feature::IS_AVAILABLE;
}
};
TEST_F(SimpleFeatureTest, IsAvailableNullCase) {
const IsAvailableTestData tests[] = { const IsAvailableTestData tests[] = {
{"", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION, {"", Manifest::TYPE_UNKNOWN, Manifest::INVALID_LOCATION,
Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE}, Feature::UNSPECIFIED_PLATFORM, -1, Feature::IS_AVAILABLE},
...@@ -84,13 +88,13 @@ TEST(SimpleFeatureTest, IsAvailableNullCase) { ...@@ -84,13 +88,13 @@ TEST(SimpleFeatureTest, IsAvailableNullCase) {
} }
} }
TEST(SimpleFeatureTest, Whitelist) { TEST_F(SimpleFeatureTest, Whitelist) {
const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh"); const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh");
const std::string kIdBar("barabbbbccccddddeeeeffffgggghhhh"); const std::string kIdBar("barabbbbccccddddeeeeffffgggghhhh");
const std::string kIdBaz("bazabbbbccccddddeeeeffffgggghhhh"); const std::string kIdBaz("bazabbbbccccddddeeeeffffgggghhhh");
SimpleFeature feature; SimpleFeature feature;
feature.whitelist()->insert(kIdFoo); feature.whitelist()->push_back(kIdFoo);
feature.whitelist()->insert(kIdBar); feature.whitelist()->push_back(kIdBar);
EXPECT_EQ( EXPECT_EQ(
Feature::IS_AVAILABLE, Feature::IS_AVAILABLE,
...@@ -122,7 +126,7 @@ TEST(SimpleFeatureTest, Whitelist) { ...@@ -122,7 +126,7 @@ TEST(SimpleFeatureTest, Whitelist) {
-1, -1,
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
feature.extension_types()->insert(Manifest::TYPE_LEGACY_PACKAGED_APP); feature.extension_types()->push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
EXPECT_EQ( EXPECT_EQ(
Feature::NOT_FOUND_IN_WHITELIST, Feature::NOT_FOUND_IN_WHITELIST,
feature.IsAvailableToManifest(kIdBaz, feature.IsAvailableToManifest(kIdBaz,
...@@ -132,14 +136,14 @@ TEST(SimpleFeatureTest, Whitelist) { ...@@ -132,14 +136,14 @@ TEST(SimpleFeatureTest, Whitelist) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, HashedIdWhitelist) { TEST_F(SimpleFeatureTest, HashedIdWhitelist) {
// echo -n "fooabbbbccccddddeeeeffffgggghhhh" | // echo -n "fooabbbbccccddddeeeeffffgggghhhh" |
// sha1sum | tr '[:lower:]' '[:upper:]' // sha1sum | tr '[:lower:]' '[:upper:]'
const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh"); const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh");
const std::string kIdFooHashed("55BC7228A0D502A2A48C9BB16B07062A01E62897"); const std::string kIdFooHashed("55BC7228A0D502A2A48C9BB16B07062A01E62897");
SimpleFeature feature; SimpleFeature feature;
feature.whitelist()->insert(kIdFooHashed); feature.whitelist()->push_back(kIdFooHashed);
EXPECT_EQ( EXPECT_EQ(
Feature::IS_AVAILABLE, Feature::IS_AVAILABLE,
...@@ -171,13 +175,13 @@ TEST(SimpleFeatureTest, HashedIdWhitelist) { ...@@ -171,13 +175,13 @@ TEST(SimpleFeatureTest, HashedIdWhitelist) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, Blacklist) { TEST_F(SimpleFeatureTest, Blacklist) {
const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh"); const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh");
const std::string kIdBar("barabbbbccccddddeeeeffffgggghhhh"); const std::string kIdBar("barabbbbccccddddeeeeffffgggghhhh");
const std::string kIdBaz("bazabbbbccccddddeeeeffffgggghhhh"); const std::string kIdBaz("bazabbbbccccddddeeeeffffgggghhhh");
SimpleFeature feature; SimpleFeature feature;
feature.blacklist()->insert(kIdFoo); feature.blacklist()->push_back(kIdFoo);
feature.blacklist()->insert(kIdBar); feature.blacklist()->push_back(kIdBar);
EXPECT_EQ( EXPECT_EQ(
Feature::FOUND_IN_BLACKLIST, Feature::FOUND_IN_BLACKLIST,
...@@ -210,14 +214,14 @@ TEST(SimpleFeatureTest, Blacklist) { ...@@ -210,14 +214,14 @@ TEST(SimpleFeatureTest, Blacklist) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, HashedIdBlacklist) { TEST_F(SimpleFeatureTest, HashedIdBlacklist) {
// echo -n "fooabbbbccccddddeeeeffffgggghhhh" | // echo -n "fooabbbbccccddddeeeeffffgggghhhh" |
// sha1sum | tr '[:lower:]' '[:upper:]' // sha1sum | tr '[:lower:]' '[:upper:]'
const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh"); const std::string kIdFoo("fooabbbbccccddddeeeeffffgggghhhh");
const std::string kIdFooHashed("55BC7228A0D502A2A48C9BB16B07062A01E62897"); const std::string kIdFooHashed("55BC7228A0D502A2A48C9BB16B07062A01E62897");
SimpleFeature feature; SimpleFeature feature;
feature.blacklist()->insert(kIdFooHashed); feature.blacklist()->push_back(kIdFooHashed);
EXPECT_EQ( EXPECT_EQ(
Feature::FOUND_IN_BLACKLIST, Feature::FOUND_IN_BLACKLIST,
...@@ -249,10 +253,10 @@ TEST(SimpleFeatureTest, HashedIdBlacklist) { ...@@ -249,10 +253,10 @@ TEST(SimpleFeatureTest, HashedIdBlacklist) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, PackageType) { TEST_F(SimpleFeatureTest, PackageType) {
SimpleFeature feature; SimpleFeature feature;
feature.extension_types()->insert(Manifest::TYPE_EXTENSION); feature.extension_types()->push_back(Manifest::TYPE_EXTENSION);
feature.extension_types()->insert(Manifest::TYPE_LEGACY_PACKAGED_APP); feature.extension_types()->push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
EXPECT_EQ( EXPECT_EQ(
Feature::IS_AVAILABLE, Feature::IS_AVAILABLE,
...@@ -285,12 +289,12 @@ TEST(SimpleFeatureTest, PackageType) { ...@@ -285,12 +289,12 @@ TEST(SimpleFeatureTest, PackageType) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, Context) { TEST_F(SimpleFeatureTest, Context) {
SimpleFeature feature; SimpleFeature feature;
feature.set_name("somefeature"); feature.set_name("somefeature");
feature.contexts()->insert(Feature::BLESSED_EXTENSION_CONTEXT); feature.contexts()->push_back(Feature::BLESSED_EXTENSION_CONTEXT);
feature.extension_types()->insert(Manifest::TYPE_LEGACY_PACKAGED_APP); feature.extension_types()->push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
feature.platforms()->insert(Feature::CHROMEOS_PLATFORM); feature.platforms()->push_back(Feature::CHROMEOS_PLATFORM);
feature.set_min_manifest_version(21); feature.set_min_manifest_version(21);
feature.set_max_manifest_version(25); feature.set_max_manifest_version(25);
...@@ -307,14 +311,14 @@ TEST(SimpleFeatureTest, Context) { ...@@ -307,14 +311,14 @@ TEST(SimpleFeatureTest, Context) {
EXPECT_EQ("", error); EXPECT_EQ("", error);
ASSERT_TRUE(extension.get()); ASSERT_TRUE(extension.get());
feature.whitelist()->insert("monkey"); feature.whitelist()->push_back("monkey");
EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature.IsAvailableToContext( EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature.IsAvailableToContext(
extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
Feature::CHROMEOS_PLATFORM).result()); Feature::CHROMEOS_PLATFORM).result());
feature.whitelist()->clear(); feature.whitelist()->clear();
feature.extension_types()->clear(); feature.extension_types()->clear();
feature.extension_types()->insert(Manifest::TYPE_THEME); feature.extension_types()->push_back(Manifest::TYPE_THEME);
{ {
Feature::Availability availability = feature.IsAvailableToContext( Feature::Availability availability = feature.IsAvailableToContext(
extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
...@@ -326,10 +330,10 @@ TEST(SimpleFeatureTest, Context) { ...@@ -326,10 +330,10 @@ TEST(SimpleFeatureTest, Context) {
} }
feature.extension_types()->clear(); feature.extension_types()->clear();
feature.extension_types()->insert(Manifest::TYPE_LEGACY_PACKAGED_APP); feature.extension_types()->push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
feature.contexts()->clear(); feature.contexts()->clear();
feature.contexts()->insert(Feature::UNBLESSED_EXTENSION_CONTEXT); feature.contexts()->push_back(Feature::UNBLESSED_EXTENSION_CONTEXT);
feature.contexts()->insert(Feature::CONTENT_SCRIPT_CONTEXT); feature.contexts()->push_back(Feature::CONTENT_SCRIPT_CONTEXT);
{ {
Feature::Availability availability = feature.IsAvailableToContext( Feature::Availability availability = feature.IsAvailableToContext(
extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
...@@ -340,7 +344,7 @@ TEST(SimpleFeatureTest, Context) { ...@@ -340,7 +344,7 @@ TEST(SimpleFeatureTest, Context) {
availability.message()); availability.message());
} }
feature.contexts()->insert(Feature::WEB_PAGE_CONTEXT); feature.contexts()->push_back(Feature::WEB_PAGE_CONTEXT);
{ {
Feature::Availability availability = feature.IsAvailableToContext( Feature::Availability availability = feature.IsAvailableToContext(
extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
...@@ -352,7 +356,7 @@ TEST(SimpleFeatureTest, Context) { ...@@ -352,7 +356,7 @@ TEST(SimpleFeatureTest, Context) {
} }
feature.contexts()->clear(); feature.contexts()->clear();
feature.contexts()->insert(Feature::BLESSED_EXTENSION_CONTEXT); feature.contexts()->push_back(Feature::BLESSED_EXTENSION_CONTEXT);
feature.set_location(SimpleFeature::COMPONENT_LOCATION); feature.set_location(SimpleFeature::COMPONENT_LOCATION);
EXPECT_EQ(Feature::INVALID_LOCATION, feature.IsAvailableToContext( EXPECT_EQ(Feature::INVALID_LOCATION, feature.IsAvailableToContext(
extension.get(), Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT,
...@@ -376,7 +380,7 @@ TEST(SimpleFeatureTest, Context) { ...@@ -376,7 +380,7 @@ TEST(SimpleFeatureTest, Context) {
feature.set_max_manifest_version(25); feature.set_max_manifest_version(25);
} }
TEST(SimpleFeatureTest, Location) { TEST_F(SimpleFeatureTest, Location) {
// Component extensions can access any location. // Component extensions can access any location.
EXPECT_TRUE(LocationIsAvailable(SimpleFeature::COMPONENT_LOCATION, EXPECT_TRUE(LocationIsAvailable(SimpleFeature::COMPONENT_LOCATION,
Manifest::COMPONENT)); Manifest::COMPONENT));
...@@ -423,9 +427,9 @@ TEST(SimpleFeatureTest, Location) { ...@@ -423,9 +427,9 @@ TEST(SimpleFeatureTest, Location) {
Manifest::EXTERNAL_COMPONENT)); Manifest::EXTERNAL_COMPONENT));
} }
TEST(SimpleFeatureTest, Platform) { TEST_F(SimpleFeatureTest, Platform) {
SimpleFeature feature; SimpleFeature feature;
feature.platforms()->insert(Feature::CHROMEOS_PLATFORM); feature.platforms()->push_back(Feature::CHROMEOS_PLATFORM);
EXPECT_EQ(Feature::IS_AVAILABLE, EXPECT_EQ(Feature::IS_AVAILABLE,
feature.IsAvailableToManifest(std::string(), feature.IsAvailableToManifest(std::string(),
Manifest::TYPE_UNKNOWN, Manifest::TYPE_UNKNOWN,
...@@ -441,7 +445,7 @@ TEST(SimpleFeatureTest, Platform) { ...@@ -441,7 +445,7 @@ TEST(SimpleFeatureTest, Platform) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, ManifestVersion) { TEST_F(SimpleFeatureTest, ManifestVersion) {
SimpleFeature feature; SimpleFeature feature;
feature.set_min_manifest_version(5); feature.set_min_manifest_version(5);
...@@ -500,7 +504,7 @@ TEST(SimpleFeatureTest, ManifestVersion) { ...@@ -500,7 +504,7 @@ TEST(SimpleFeatureTest, ManifestVersion) {
Feature::UNSPECIFIED_PLATFORM).result()); Feature::UNSPECIFIED_PLATFORM).result());
} }
TEST(SimpleFeatureTest, ParseNull) { TEST_F(SimpleFeatureTest, ParseNull) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
feature->Parse(value.get()); feature->Parse(value.get());
...@@ -513,7 +517,7 @@ TEST(SimpleFeatureTest, ParseNull) { ...@@ -513,7 +517,7 @@ TEST(SimpleFeatureTest, ParseNull) {
EXPECT_EQ(0, feature->max_manifest_version()); EXPECT_EQ(0, feature->max_manifest_version());
} }
TEST(SimpleFeatureTest, ParseWhitelist) { TEST_F(SimpleFeatureTest, ParseWhitelist) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
base::ListValue* whitelist = new base::ListValue(); base::ListValue* whitelist = new base::ListValue();
whitelist->Append(new base::StringValue("foo")); whitelist->Append(new base::StringValue("foo"));
...@@ -522,11 +526,11 @@ TEST(SimpleFeatureTest, ParseWhitelist) { ...@@ -522,11 +526,11 @@ TEST(SimpleFeatureTest, ParseWhitelist) {
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
feature->Parse(value.get()); feature->Parse(value.get());
EXPECT_EQ(2u, feature->whitelist()->size()); EXPECT_EQ(2u, feature->whitelist()->size());
EXPECT_TRUE(feature->whitelist()->count("foo")); EXPECT_TRUE(STLCount(*(feature->whitelist()), "foo"));
EXPECT_TRUE(feature->whitelist()->count("bar")); EXPECT_TRUE(STLCount(*(feature->whitelist()), "bar"));
} }
TEST(SimpleFeatureTest, ParsePackageTypes) { TEST_F(SimpleFeatureTest, ParsePackageTypes) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
base::ListValue* extension_types = new base::ListValue(); base::ListValue* extension_types = new base::ListValue();
extension_types->Append(new base::StringValue("extension")); extension_types->Append(new base::StringValue("extension"));
...@@ -539,13 +543,19 @@ TEST(SimpleFeatureTest, ParsePackageTypes) { ...@@ -539,13 +543,19 @@ TEST(SimpleFeatureTest, ParsePackageTypes) {
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
feature->Parse(value.get()); feature->Parse(value.get());
EXPECT_EQ(6u, feature->extension_types()->size()); EXPECT_EQ(6u, feature->extension_types()->size());
EXPECT_TRUE(feature->extension_types()->count(Manifest::TYPE_EXTENSION)); EXPECT_TRUE(
EXPECT_TRUE(feature->extension_types()->count(Manifest::TYPE_THEME)); STLCount(*(feature->extension_types()), Manifest::TYPE_EXTENSION));
EXPECT_TRUE(feature->extension_types()->count( EXPECT_TRUE(
Manifest::TYPE_LEGACY_PACKAGED_APP)); STLCount(*(feature->extension_types()), Manifest::TYPE_THEME));
EXPECT_TRUE(feature->extension_types()->count(Manifest::TYPE_HOSTED_APP)); EXPECT_TRUE(
EXPECT_TRUE(feature->extension_types()->count(Manifest::TYPE_PLATFORM_APP)); STLCount(
EXPECT_TRUE(feature->extension_types()->count(Manifest::TYPE_SHARED_MODULE)); *(feature->extension_types()), Manifest::TYPE_LEGACY_PACKAGED_APP));
EXPECT_TRUE(
STLCount(*(feature->extension_types()), Manifest::TYPE_HOSTED_APP));
EXPECT_TRUE(
STLCount(*(feature->extension_types()), Manifest::TYPE_PLATFORM_APP));
EXPECT_TRUE(
STLCount(*(feature->extension_types()), Manifest::TYPE_SHARED_MODULE));
value->SetString("extension_types", "all"); value->SetString("extension_types", "all");
scoped_ptr<SimpleFeature> feature2(new SimpleFeature()); scoped_ptr<SimpleFeature> feature2(new SimpleFeature());
...@@ -553,7 +563,7 @@ TEST(SimpleFeatureTest, ParsePackageTypes) { ...@@ -553,7 +563,7 @@ TEST(SimpleFeatureTest, ParsePackageTypes) {
EXPECT_EQ(*(feature->extension_types()), *(feature2->extension_types())); EXPECT_EQ(*(feature->extension_types()), *(feature2->extension_types()));
} }
TEST(SimpleFeatureTest, ParseContexts) { TEST_F(SimpleFeatureTest, ParseContexts) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
base::ListValue* contexts = new base::ListValue(); base::ListValue* contexts = new base::ListValue();
contexts->Append(new base::StringValue("blessed_extension")); contexts->Append(new base::StringValue("blessed_extension"));
...@@ -566,11 +576,16 @@ TEST(SimpleFeatureTest, ParseContexts) { ...@@ -566,11 +576,16 @@ TEST(SimpleFeatureTest, ParseContexts) {
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
feature->Parse(value.get()); feature->Parse(value.get());
EXPECT_EQ(6u, feature->contexts()->size()); EXPECT_EQ(6u, feature->contexts()->size());
EXPECT_TRUE(feature->contexts()->count(Feature::BLESSED_EXTENSION_CONTEXT)); EXPECT_TRUE(
EXPECT_TRUE(feature->contexts()->count(Feature::UNBLESSED_EXTENSION_CONTEXT)); STLCount(*(feature->contexts()), Feature::BLESSED_EXTENSION_CONTEXT));
EXPECT_TRUE(feature->contexts()->count(Feature::CONTENT_SCRIPT_CONTEXT)); EXPECT_TRUE(
EXPECT_TRUE(feature->contexts()->count(Feature::WEB_PAGE_CONTEXT)); STLCount(*(feature->contexts()), Feature::UNBLESSED_EXTENSION_CONTEXT));
EXPECT_TRUE(feature->contexts()->count(Feature::BLESSED_WEB_PAGE_CONTEXT)); EXPECT_TRUE(
STLCount(*(feature->contexts()), Feature::CONTENT_SCRIPT_CONTEXT));
EXPECT_TRUE(
STLCount(*(feature->contexts()), Feature::WEB_PAGE_CONTEXT));
EXPECT_TRUE(
STLCount(*(feature->contexts()), Feature::BLESSED_WEB_PAGE_CONTEXT));
value->SetString("contexts", "all"); value->SetString("contexts", "all");
scoped_ptr<SimpleFeature> feature2(new SimpleFeature()); scoped_ptr<SimpleFeature> feature2(new SimpleFeature());
...@@ -578,7 +593,7 @@ TEST(SimpleFeatureTest, ParseContexts) { ...@@ -578,7 +593,7 @@ TEST(SimpleFeatureTest, ParseContexts) {
EXPECT_EQ(*(feature->contexts()), *(feature2->contexts())); EXPECT_EQ(*(feature->contexts()), *(feature2->contexts()));
} }
TEST(SimpleFeatureTest, ParseLocation) { TEST_F(SimpleFeatureTest, ParseLocation) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
value->SetString("location", "component"); value->SetString("location", "component");
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
...@@ -586,7 +601,7 @@ TEST(SimpleFeatureTest, ParseLocation) { ...@@ -586,7 +601,7 @@ TEST(SimpleFeatureTest, ParseLocation) {
EXPECT_EQ(SimpleFeature::COMPONENT_LOCATION, feature->location()); EXPECT_EQ(SimpleFeature::COMPONENT_LOCATION, feature->location());
} }
TEST(SimpleFeatureTest, ParsePlatforms) { TEST_F(SimpleFeatureTest, ParsePlatforms) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
scoped_ptr<SimpleFeature> feature(new SimpleFeature()); scoped_ptr<SimpleFeature> feature(new SimpleFeature());
base::ListValue* platforms = new base::ListValue(); base::ListValue* platforms = new base::ListValue();
...@@ -609,15 +624,15 @@ TEST(SimpleFeatureTest, ParsePlatforms) { ...@@ -609,15 +624,15 @@ TEST(SimpleFeatureTest, ParsePlatforms) {
platforms->AppendString("win"); platforms->AppendString("win");
platforms->AppendString("chromeos"); platforms->AppendString("chromeos");
feature->Parse(value.get()); feature->Parse(value.get());
std::set<Feature::Platform> expected_platforms; std::vector<Feature::Platform> expected_platforms;
expected_platforms.insert(Feature::CHROMEOS_PLATFORM); expected_platforms.push_back(Feature::CHROMEOS_PLATFORM);
expected_platforms.insert(Feature::WIN_PLATFORM); expected_platforms.push_back(Feature::WIN_PLATFORM);
EXPECT_FALSE(feature->platforms()->empty()); EXPECT_FALSE(feature->platforms()->empty());
EXPECT_EQ(expected_platforms, *feature->platforms()); EXPECT_EQ(expected_platforms, *feature->platforms());
} }
TEST(SimpleFeatureTest, ParseManifestVersion) { TEST_F(SimpleFeatureTest, ParseManifestVersion) {
scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
value->SetInteger("min_manifest_version", 1); value->SetInteger("min_manifest_version", 1);
value->SetInteger("max_manifest_version", 5); value->SetInteger("max_manifest_version", 5);
...@@ -627,13 +642,13 @@ TEST(SimpleFeatureTest, ParseManifestVersion) { ...@@ -627,13 +642,13 @@ TEST(SimpleFeatureTest, ParseManifestVersion) {
EXPECT_EQ(5, feature->max_manifest_version()); EXPECT_EQ(5, feature->max_manifest_version());
} }
TEST(SimpleFeatureTest, Inheritance) { TEST_F(SimpleFeatureTest, Inheritance) {
SimpleFeature feature; SimpleFeature feature;
feature.whitelist()->insert("foo"); feature.whitelist()->push_back("foo");
feature.extension_types()->insert(Manifest::TYPE_THEME); feature.extension_types()->push_back(Manifest::TYPE_THEME);
feature.contexts()->insert(Feature::BLESSED_EXTENSION_CONTEXT); feature.contexts()->push_back(Feature::BLESSED_EXTENSION_CONTEXT);
feature.set_location(SimpleFeature::COMPONENT_LOCATION); feature.set_location(SimpleFeature::COMPONENT_LOCATION);
feature.platforms()->insert(Feature::CHROMEOS_PLATFORM); feature.platforms()->push_back(Feature::CHROMEOS_PLATFORM);
feature.set_min_manifest_version(1); feature.set_min_manifest_version(1);
feature.set_max_manifest_version(2); feature.set_max_manifest_version(2);
...@@ -644,10 +659,10 @@ TEST(SimpleFeatureTest, Inheritance) { ...@@ -644,10 +659,10 @@ TEST(SimpleFeatureTest, Inheritance) {
EXPECT_EQ(1u, feature.whitelist()->size()); EXPECT_EQ(1u, feature.whitelist()->size());
EXPECT_EQ(1u, feature.extension_types()->size()); EXPECT_EQ(1u, feature.extension_types()->size());
EXPECT_EQ(1u, feature.contexts()->size()); EXPECT_EQ(1u, feature.contexts()->size());
EXPECT_EQ(1u, feature.whitelist()->count("foo")); EXPECT_EQ(1, STLCount(*(feature.whitelist()), "foo"));
EXPECT_EQ(SimpleFeature::COMPONENT_LOCATION, feature.location()); EXPECT_EQ(SimpleFeature::COMPONENT_LOCATION, feature.location());
EXPECT_EQ(1u, feature.platforms()->size()); EXPECT_EQ(1u, feature.platforms()->size());
EXPECT_EQ(1u, feature.platforms()->count(Feature::CHROMEOS_PLATFORM)); EXPECT_EQ(1, STLCount(*(feature.platforms()), Feature::CHROMEOS_PLATFORM));
EXPECT_EQ(1, feature.min_manifest_version()); EXPECT_EQ(1, feature.min_manifest_version());
EXPECT_EQ(2, feature.max_manifest_version()); EXPECT_EQ(2, feature.max_manifest_version());
...@@ -668,15 +683,17 @@ TEST(SimpleFeatureTest, Inheritance) { ...@@ -668,15 +683,17 @@ TEST(SimpleFeatureTest, Inheritance) {
EXPECT_EQ(1u, feature.whitelist()->size()); EXPECT_EQ(1u, feature.whitelist()->size());
EXPECT_EQ(1u, feature.extension_types()->size()); EXPECT_EQ(1u, feature.extension_types()->size());
EXPECT_EQ(1u, feature.contexts()->size()); EXPECT_EQ(1u, feature.contexts()->size());
EXPECT_EQ(1u, feature.whitelist()->count("bar")); EXPECT_EQ(1, STLCount(*(feature.whitelist()), "bar"));
EXPECT_EQ(1u, feature.extension_types()->count(Manifest::TYPE_EXTENSION)); EXPECT_EQ(1,
EXPECT_EQ(1u, STLCount(*(feature.extension_types()), Manifest::TYPE_EXTENSION));
feature.contexts()->count(Feature::UNBLESSED_EXTENSION_CONTEXT)); EXPECT_EQ(1,
STLCount(
*(feature.contexts()), Feature::UNBLESSED_EXTENSION_CONTEXT));
EXPECT_EQ(2, feature.min_manifest_version()); EXPECT_EQ(2, feature.min_manifest_version());
EXPECT_EQ(3, feature.max_manifest_version()); EXPECT_EQ(3, feature.max_manifest_version());
} }
TEST(SimpleFeatureTest, CommandLineSwitch) { TEST_F(SimpleFeatureTest, CommandLineSwitch) {
SimpleFeature feature; SimpleFeature feature;
feature.set_command_line_switch("laser-beams"); feature.set_command_line_switch("laser-beams");
{ {
...@@ -710,4 +727,23 @@ TEST(SimpleFeatureTest, CommandLineSwitch) { ...@@ -710,4 +727,23 @@ TEST(SimpleFeatureTest, CommandLineSwitch) {
} }
} }
TEST_F(SimpleFeatureTest, IsIdInArray) {
EXPECT_FALSE(SimpleFeature::IsIdInArray("", {}, 0));
EXPECT_FALSE(SimpleFeature::IsIdInArray(
"bbbbccccdddddddddeeeeeeffffgghhh", {}, 0));
const char* const kIdArray[] = {
"bbbbccccdddddddddeeeeeeffffgghhh",
// aaaabbbbccccddddeeeeffffgggghhhh
"9A0417016F345C934A1A88F55CA17C05014EEEBA"
};
EXPECT_FALSE(SimpleFeature::IsIdInArray("", kIdArray, arraysize(kIdArray)));
EXPECT_FALSE(SimpleFeature::IsIdInArray(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", kIdArray, arraysize(kIdArray)));
EXPECT_TRUE(SimpleFeature::IsIdInArray(
"bbbbccccdddddddddeeeeeeffffgghhh", kIdArray, arraysize(kIdArray)));
EXPECT_TRUE(SimpleFeature::IsIdInArray(
"aaaabbbbccccddddeeeeffffgggghhhh", kIdArray, arraysize(kIdArray)));
}
} // namespace extensions } // namespace extensions
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment