diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-10 02:29:54 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-10 02:29:54 +0000 |
commit | 5f6f354f50e4db2fb3facde9b66b5c0fa90754a3 (patch) | |
tree | 382eeb9c5dbf0e352a32710007d200e8ae84179f | |
parent | f9dd9de78f41349caab59649fa33664e594537f3 (diff) | |
download | chromium_src-5f6f354f50e4db2fb3facde9b66b5c0fa90754a3.zip chromium_src-5f6f354f50e4db2fb3facde9b66b5c0fa90754a3.tar.gz chromium_src-5f6f354f50e4db2fb3facde9b66b5c0fa90754a3.tar.bz2 |
Revert 125979 - Re-land 125247: Better error messages when using unsupported manifest features.
BUG=112620
Review URL: https://chromiumcodereview.appspot.com/9616052
TBR=aa@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9665034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125982 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/common/extensions/extension_constants.cc | 2 | ||||
-rw-r--r-- | chrome/common/extensions/feature.cc | 56 | ||||
-rw-r--r-- | chrome/common/extensions/feature.h | 32 | ||||
-rw-r--r-- | chrome/common/extensions/feature_unittest.cc | 71 | ||||
-rw-r--r-- | chrome/common/extensions/manifest.cc | 38 | ||||
-rw-r--r-- | chrome/common/extensions/manifest.h | 2 | ||||
-rw-r--r-- | chrome/common/extensions/manifest_unittest.cc | 10 |
7 files changed, 75 insertions, 136 deletions
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index dfb61d4..0065870 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc @@ -176,7 +176,7 @@ const char kExperimentalFlagRequired[] = "default. You can enable 'Experimental Extension APIs' " "by visiting chrome://flags."; const char kFeatureNotAllowed[] = - "Feature '*' is not accessible. *"; + "Feature '*' is not allowed in this type of manifest."; const char kInvalidAllFrames[] = "Invalid value for 'content_scripts[*].all_frames'."; const char kInvalidBackground[] = diff --git a/chrome/common/extensions/feature.cc b/chrome/common/extensions/feature.cc index 8ee35d90..aad4d01 100644 --- a/chrome/common/extensions/feature.cc +++ b/chrome/common/extensions/feature.cc @@ -7,7 +7,6 @@ #include <map> #include "base/lazy_instance.h" -#include "base/stringprintf.h" namespace { @@ -152,67 +151,40 @@ Feature::Location Feature::ConvertLocation(Extension::Location location) { return UNSPECIFIED_LOCATION; } -std::string Feature::GetErrorMessage(Feature::Availability result) { - switch (result) { - case IS_AVAILABLE: - return ""; - case NOT_FOUND_IN_WHITELIST: - return "Not allowed for specified extension ID."; - case INVALID_TYPE: - return "Not allowed for specified package type (theme, app, etc.)."; - case INVALID_CONTEXT: - return "Not allowed for specified context type content script, extension " - "page, web page, etc.)."; - case INVALID_LOCATION: - return "Not allowed for specified install location."; - case INVALID_PLATFORM: - return "Not allowed for specified platform."; - case INVALID_MIN_MANIFEST_VERSION: - return base::StringPrintf("Requires manifest version of at least %d.", - min_manifest_version_); - case INVALID_MAX_MANIFEST_VERSION: - return base::StringPrintf("Requires manifest version of %d or lower.", - max_manifest_version_); - default: - CHECK(false); - return ""; - } -} - -Feature::Availability Feature::IsAvailable(const std::string& extension_id, - Extension::Type type, - Location location, - Context context, - Platform platform, - int manifest_version) { +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 NOT_FOUND_IN_WHITELIST; + return false; } if (!extension_types_.empty() && extension_types_.find(type) == extension_types_.end()) { - return INVALID_TYPE; + return false; } if (!contexts_.empty() && contexts_.find(context) == contexts_.end()) { - return INVALID_CONTEXT; + return false; } if (location_ != UNSPECIFIED_LOCATION && location_ != location) - return INVALID_LOCATION; + return false; if (platform_ != UNSPECIFIED_PLATFORM && platform_ != platform) - return INVALID_PLATFORM; + return false; if (min_manifest_version_ != 0 && manifest_version < min_manifest_version_) - return INVALID_MIN_MANIFEST_VERSION; + return false; if (max_manifest_version_ != 0 && manifest_version > max_manifest_version_) - return INVALID_MAX_MANIFEST_VERSION; + return false; - return IS_AVAILABLE; + return true; } } // namespace diff --git a/chrome/common/extensions/feature.h b/chrome/common/extensions/feature.h index 61a96a5..0a95689 100644 --- a/chrome/common/extensions/feature.h +++ b/chrome/common/extensions/feature.h @@ -41,19 +41,6 @@ class Feature { CHROMEOS_PLATFORM }; - // Whether a feature is available in a given situation or not, and if not, - // why not. - enum Availability { - IS_AVAILABLE, - NOT_FOUND_IN_WHITELIST, - INVALID_TYPE, - INVALID_CONTEXT, - INVALID_LOCATION, - INVALID_PLATFORM, - INVALID_MIN_MANIFEST_VERSION, - INVALID_MAX_MANIFEST_VERSION - }; - Feature(); ~Feature(); @@ -88,13 +75,13 @@ class Feature { // Returns true if the feature is available to the specified extension. Use // this overload for features that are not associated with a specific context. - Availability IsAvailable(const Extension* extension) { + 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. - Availability IsAvailable(const Extension* extension, Context context) { + bool IsAvailable(const Extension* extension, Context context) { return IsAvailable(extension->id(), extension->GetType(), ConvertLocation(extension->location()), context, GetCurrentPlatform(), @@ -104,9 +91,8 @@ class Feature { // 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. - Availability IsAvailable(const std::string& extension_id, - Extension::Type type, Location location, - int manifest_version) { + 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); } @@ -114,13 +100,9 @@ class Feature { // 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. - Availability IsAvailable(const std::string& extension_id, - Extension::Type type, Location location, - Context context, Platform platform, - int manifest_version); - - // Returns an error message for an Availability code. - std::string GetErrorMessage(Availability result); + 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 diff --git a/chrome/common/extensions/feature_unittest.cc b/chrome/common/extensions/feature_unittest.cc index 9d71b73..0ebaaa9 100644 --- a/chrome/common/extensions/feature_unittest.cc +++ b/chrome/common/extensions/feature_unittest.cc @@ -17,7 +17,7 @@ struct IsAvailableTestData { Feature::Location location; Feature::Platform platform; int manifest_version; - Feature::Availability expected_result; + bool expected_result; }; } // namespace @@ -25,26 +25,19 @@ struct IsAvailableTestData { TEST(ExtensionFeatureTest, IsAvailableNullCase) { const IsAvailableTestData tests[] = { { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true }, { "random-extension", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true }, { "", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true }, { "", Extension::TYPE_UNKNOWN, Feature::PRIVILEGED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true }, { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT, - Feature::COMPONENT_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::COMPONENT_LOCATION, Feature::UNSPECIFIED_PLATFORM, -1, true }, { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::CHROMEOS_PLATFORM, -1, - Feature::IS_AVAILABLE }, + Feature::UNSPECIFIED_LOCATION, Feature::CHROMEOS_PLATFORM, -1, true }, { "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_CONTEXT, - Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, 25, - Feature::IS_AVAILABLE } + Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_PLATFORM, 25, true } }; Feature feature; @@ -62,22 +55,22 @@ TEST(ExtensionFeatureTest, Whitelist) { feature.whitelist()->insert("foo"); feature.whitelist()->insert("bar"); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "foo", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "bar", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "baz", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature.IsAvailable( + 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_EQ(Feature::NOT_FOUND_IN_WHITELIST, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "baz", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); } @@ -87,17 +80,17 @@ TEST(ExtensionFeatureTest, PackageType) { feature.extension_types()->insert(Extension::TYPE_EXTENSION); feature.extension_types()->insert(Extension::TYPE_PACKAGED_APP); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_EXTENSION, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_PACKAGED_APP, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_TYPE, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_TYPE, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_THEME, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); } @@ -107,17 +100,17 @@ TEST(ExtensionFeatureTest, Context) { feature.contexts()->insert(Feature::PRIVILEGED_CONTEXT); feature.contexts()->insert(Feature::CONTENT_SCRIPT_CONTEXT); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::PRIVILEGED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::CONTENT_SCRIPT_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_CONTEXT, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNPRIVILEGED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_CONTEXT, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); } @@ -125,10 +118,10 @@ TEST(ExtensionFeatureTest, Context) { TEST(ExtensionFeatureTest, Location) { Feature feature; feature.set_location(Feature::COMPONENT_LOCATION); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::COMPONENT_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_LOCATION, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); } @@ -136,10 +129,10 @@ TEST(ExtensionFeatureTest, Location) { TEST(ExtensionFeatureTest, Platform) { Feature feature; feature.set_platform(Feature::CHROMEOS_PLATFORM); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::CHROMEOS_PLATFORM, -1)); - EXPECT_EQ(Feature::INVALID_PLATFORM, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, -1)); } @@ -148,29 +141,29 @@ TEST(ExtensionFeatureTest, Version) { Feature feature; feature.set_min_manifest_version(5); - EXPECT_EQ(Feature::INVALID_MIN_MANIFEST_VERSION, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 0)); - EXPECT_EQ(Feature::INVALID_MIN_MANIFEST_VERSION, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 4)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 5)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 10)); feature.set_max_manifest_version(8); - EXPECT_EQ(Feature::INVALID_MAX_MANIFEST_VERSION, feature.IsAvailable( + EXPECT_FALSE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 10)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 8)); - EXPECT_EQ(Feature::IS_AVAILABLE, feature.IsAvailable( + EXPECT_TRUE(feature.IsAvailable( "", Extension::TYPE_UNKNOWN, Feature::UNSPECIFIED_LOCATION, Feature::UNSPECIFIED_CONTEXT, Feature::UNSPECIFIED_PLATFORM, 7)); } diff --git a/chrome/common/extensions/manifest.cc b/chrome/common/extensions/manifest.cc index 0cf2ef2..d462bb8 100644 --- a/chrome/common/extensions/manifest.cc +++ b/chrome/common/extensions/manifest.cc @@ -28,24 +28,18 @@ Manifest::~Manifest() { bool Manifest::ValidateManifest(string16* error) const { for (DictionaryValue::key_iterator key = value_->begin_keys(); key != value_->end_keys(); ++key) { - scoped_ptr<Feature> feature = - ManifestFeatureProvider::GetDefaultInstance()->GetFeature(*key); - if (!feature.get()) { + bool was_known = false; + if (!CanAccessKey(*key, &was_known)) { // When validating the extension manifests, we ignore keys that are not // recognized for forward compatibility. - // TODO(aa): Consider having an error here in the case of strict error - // checking to let developers know when they screw up. - continue; - } + if (!was_known) { + // TODO(aa): Consider having an error here in the case of strict error + // checking to let developers know when they screw up. + continue; + } - Feature::Availability result = feature->IsAvailable( - extension_id_, GetType(), Feature::ConvertLocation(location_), - GetManifestVersion()); - if (result != Feature::IS_AVAILABLE) { *error = ExtensionErrorUtils::FormatErrorMessageUTF16( - errors::kFeatureNotAllowed, - *key, - feature->GetErrorMessage(result)); + errors::kFeatureNotAllowed, *key); return false; } } @@ -54,7 +48,7 @@ bool Manifest::ValidateManifest(string16* error) const { } bool Manifest::HasKey(const std::string& key) const { - return CanAccessKey(key) && value_->HasKey(key); + return CanAccessKey(key, NULL) && value_->HasKey(key); } bool Manifest::Get( @@ -146,18 +140,22 @@ bool Manifest::IsHostedApp() const { bool Manifest::CanAccessPath(const std::string& path) const { std::vector<std::string> components; base::SplitString(path, '.', &components); - return CanAccessKey(components[0]); + return CanAccessKey(components[0], NULL); } -bool Manifest::CanAccessKey(const std::string& key) const { +bool Manifest::CanAccessKey(const std::string& key, bool *was_known) const { scoped_ptr<Feature> feature = ManifestFeatureProvider::GetDefaultInstance()->GetFeature(key); if (!feature.get()) return false; - return Feature::IS_AVAILABLE == feature->IsAvailable( - extension_id_, GetType(), Feature::ConvertLocation(location_), - GetManifestVersion()); + if (was_known) + *was_known = true; + + return feature->IsAvailable(extension_id_, + GetType(), + Feature::ConvertLocation(location_), + GetManifestVersion()); } } // namespace extensions diff --git a/chrome/common/extensions/manifest.h b/chrome/common/extensions/manifest.h index 43e2caa..9645589 100644 --- a/chrome/common/extensions/manifest.h +++ b/chrome/common/extensions/manifest.h @@ -82,7 +82,7 @@ class Manifest { private: // Returns true if the extension can specify the given |path|. bool CanAccessPath(const std::string& path) const; - bool CanAccessKey(const std::string& key) const; + bool CanAccessKey(const std::string& key, bool* was_known) const; // A persistent, globally unique ID. An extension's ID is used in things // like directory structures and URLs, and is expected to not change across diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc index 0d45982..7ca6ac5 100644 --- a/chrome/common/extensions/manifest_unittest.cc +++ b/chrome/common/extensions/manifest_unittest.cc @@ -72,14 +72,8 @@ TEST_F(ManifestTest, Extension) { // Validate should also stop working. error.clear(); EXPECT_FALSE(manifest->ValidateManifest(&error)); - { - Feature feature; - feature.set_max_manifest_version(1); - EXPECT_EQ(ExtensionErrorUtils::FormatErrorMessageUTF16( - errors::kFeatureNotAllowed, - "background_page", - feature.GetErrorMessage(Feature::INVALID_MAX_MANIFEST_VERSION)), error); - } + EXPECT_EQ(ExtensionErrorUtils::FormatErrorMessageUTF16( + errors::kFeatureNotAllowed, "background_page"), error); // Test DeepCopy and Equals. scoped_ptr<Manifest> manifest2(manifest->DeepCopy()); |