| // Copyright 2018 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 "extensions/common/extension.h" |
| |
| #include "base/command_line.h" |
| #include "base/optional.h" |
| #include "base/test/scoped_command_line.h" |
| #include "extensions/common/switches.h" |
| #include "extensions/common/value_builder.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace extensions { |
| namespace { |
| |
| testing::AssertionResult RunManifestVersionSuccess( |
| std::unique_ptr<base::DictionaryValue> manifest, |
| Manifest::Type expected_type, |
| int expected_manifest_version, |
| Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) { |
| std::string error; |
| scoped_refptr<const Extension> extension = Extension::Create( |
| base::FilePath(), Manifest::INTERNAL, *manifest, custom_flag, &error); |
| if (!extension) { |
| return testing::AssertionFailure() |
| << "Extension creation failed: " << error; |
| } |
| |
| if (extension->GetType() != expected_type) { |
| return testing::AssertionFailure() |
| << "Wrong type: " << extension->GetType(); |
| } |
| |
| if (extension->manifest_version() != expected_manifest_version) { |
| return testing::AssertionFailure() |
| << "Wrong manifest version: " << extension->manifest_version(); |
| } |
| |
| return testing::AssertionSuccess(); |
| } |
| |
| testing::AssertionResult RunManifestVersionFailure( |
| std::unique_ptr<base::DictionaryValue> manifest, |
| Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) { |
| std::string error; |
| scoped_refptr<const Extension> extension = Extension::Create( |
| base::FilePath(), Manifest::INTERNAL, *manifest, custom_flag, &error); |
| if (extension) |
| return testing::AssertionFailure() << "Extension creation succeeded."; |
| |
| return testing::AssertionSuccess(); |
| } |
| |
| } // namespace |
| |
| // TODO(devlin): Move tests from chrome/common/extensions/extension_unittest.cc |
| // that don't depend on //chrome into here. |
| |
| TEST(ExtensionTest, ExtensionManifestVersions) { |
| auto get_manifest = [](base::Optional<int> manifest_version) { |
| DictionaryBuilder builder; |
| builder.Set("name", "My Extension") |
| .Set("version", "0.1") |
| .Set("description", "An awesome extension"); |
| if (manifest_version) |
| builder.Set("manifest_version", *manifest_version); |
| return builder.Build(); |
| }; |
| |
| const Manifest::Type kType = Manifest::TYPE_EXTENSION; |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2)); |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3)); |
| |
| // Manifest v1 is deprecated, and should not load. |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1))); |
| // Omitting the key defaults to v1 for extensions. |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(base::nullopt))); |
| |
| // '0' and '-1' are invalid values. |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(0))); |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(-1))); |
| |
| { |
| // Manifest v1 should only load if a command line switch is used. |
| base::test::ScopedCommandLine command_line; |
| command_line.GetProcessCommandLine()->AppendSwitch( |
| switches::kAllowLegacyExtensionManifests); |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1)); |
| EXPECT_TRUE( |
| RunManifestVersionSuccess(get_manifest(base::nullopt), kType, 1)); |
| } |
| } |
| |
| TEST(ExtensionTest, PlatformAppManifestVersions) { |
| auto get_manifest = [](base::Optional<int> manifest_version) { |
| DictionaryBuilder background; |
| background.Set("scripts", ListBuilder().Append("background.js").Build()); |
| DictionaryBuilder builder; |
| builder.Set("name", "My Platform App") |
| .Set("version", "0.1") |
| .Set("description", "A platform app") |
| .Set("app", |
| DictionaryBuilder().Set("background", background.Build()).Build()); |
| if (manifest_version) |
| builder.Set("manifest_version", *manifest_version); |
| return builder.Build(); |
| }; |
| |
| const Manifest::Type kType = Manifest::TYPE_PLATFORM_APP; |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2)); |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3)); |
| // Omitting the key defaults to v2 for platform apps. |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(base::nullopt), kType, 2)); |
| |
| // Manifest v1 is deprecated, and should not load. |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1))); |
| |
| // '0' and '-1' are invalid values. |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(0))); |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(-1))); |
| |
| { |
| // Manifest v1 should not load for platform apps, even with the command line |
| // switch. |
| base::test::ScopedCommandLine command_line; |
| command_line.GetProcessCommandLine()->AppendSwitch( |
| switches::kAllowLegacyExtensionManifests); |
| EXPECT_TRUE(RunManifestVersionFailure(get_manifest(1))); |
| } |
| } |
| |
| TEST(ExtensionTest, HostedAppManifestVersions) { |
| auto get_manifest = [](base::Optional<int> manifest_version) { |
| DictionaryBuilder builder; |
| DictionaryBuilder app; |
| app.Set("urls", ListBuilder().Append("http://example.com").Build()); |
| builder.Set("name", "My Hosted App") |
| .Set("version", "0.1") |
| .Set("description", "A hosted app") |
| .Set("app", app.Build()); |
| if (manifest_version) |
| builder.Set("manifest_version", *manifest_version); |
| return builder.Build(); |
| }; |
| |
| const Manifest::Type kType = Manifest::TYPE_HOSTED_APP; |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2)); |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3)); |
| |
| // Manifest v1 is deprecated, but should still load for hosted apps. |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1)); |
| // Omitting the key defaults to v1 for hosted apps, and v1 is still allowed. |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(base::nullopt), kType, 1)); |
| |
| // Requiring the modern manifest version should make hosted apps require v2. |
| EXPECT_TRUE(RunManifestVersionFailure( |
| get_manifest(1), Extension::REQUIRE_MODERN_MANIFEST_VERSION)); |
| } |
| |
| TEST(ExtensionTest, UserScriptManifestVersions) { |
| auto get_manifest = [](base::Optional<int> manifest_version) { |
| DictionaryBuilder builder; |
| builder.Set("name", "My Extension") |
| .Set("version", "0.1") |
| .Set("description", "An awesome extension") |
| .Set("converted_from_user_script", true); |
| if (manifest_version) |
| builder.Set("manifest_version", *manifest_version); |
| return builder.Build(); |
| }; |
| |
| const Manifest::Type kType = Manifest::TYPE_USER_SCRIPT; |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(2), kType, 2)); |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(3), kType, 3)); |
| |
| // Manifest v1 is deprecated, but should still load for user scripts. |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(1), kType, 1)); |
| // Omitting the key defaults to v1 for user scripts, but v1 is still allowed. |
| EXPECT_TRUE(RunManifestVersionSuccess(get_manifest(base::nullopt), kType, 1)); |
| |
| // Requiring the modern manifest version should make user scripts require v2. |
| EXPECT_TRUE(RunManifestVersionFailure( |
| get_manifest(1), Extension::REQUIRE_MODERN_MANIFEST_VERSION)); |
| } |
| |
| } // namespace extensions |