1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <memory>
6 #include <utility>
7 
8 #include "base/strings/stringprintf.h"
9 #include "base/test/values_test_util.h"
10 #include "components/version_info/version_info.h"
11 #include "extensions/common/features/feature_channel.h"
12 #include "extensions/common/manifest_constants.h"
13 #include "extensions/common/manifest_handlers/replacement_apps.h"
14 #include "extensions/common/manifest_test.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace extensions {
18 
19 namespace {
20 
21 class ReplacementAppsManifestTest : public ManifestTest {
22  public:
ReplacementAppsManifestTest()23   ReplacementAppsManifestTest() : channel_(version_info::Channel::UNKNOWN) {}
24 
25  protected:
CreateManifest(const char * replacement_web_app,const char * replacement_android_app)26   ManifestData CreateManifest(const char* replacement_web_app,
27                               const char* replacement_android_app) {
28     if (replacement_web_app != nullptr && replacement_android_app != nullptr) {
29       // both replacement apps are specified
30       constexpr char kManifest[] =
31           R"({
32              "name": "test",
33              "version": "1",
34              "manifest_version": 2,
35              "app": {
36                "background": {
37                  "scripts": ["background.js"]
38                }
39              },
40              "replacement_web_app": %s,
41              "replacement_android_app": %s
42            })";
43       base::Value manifest = base::test::ParseJson(base::StringPrintf(
44           kManifest, replacement_web_app, replacement_android_app));
45       return ManifestData(std::move(manifest), "test");
46     } else if (replacement_web_app != nullptr) {
47       // only web replacement app specified
48       constexpr char kManifest[] =
49           R"({
50              "name": "test",
51              "version": "1",
52              "manifest_version": 2,
53              "replacement_web_app": %s
54            })";
55       base::Value manifest = base::test::ParseJson(
56           base::StringPrintf(kManifest, replacement_web_app));
57       return ManifestData(std::move(manifest), "test");
58     } else if (replacement_android_app != nullptr) {
59       // only Android replacement app specified
60       constexpr char kManifest[] =
61           R"({
62             "name": "test",
63             "version": "1",
64             "manifest_version": 2,
65             "app": {
66               "background": {
67                 "scripts": ["background.js"]
68               }
69             },
70             "replacement_android_app": %s
71             })";
72       base::Value manifest = base::test::ParseJson(
73           base::StringPrintf(kManifest, replacement_android_app));
74       return ManifestData(std::move(manifest), "test");
75     }
76 
77     base::Value manifest = base::test::ParseJson(
78         R"({
79              "name": "test",
80              "version": "1",
81              "manifest_version": 2
82            })");
83     return ManifestData(std::move(manifest), "test");
84   }
85 
86  private:
87   ScopedCurrentChannel channel_;
88 };
89 
90 }  // namespace
91 
TEST_F(ReplacementAppsManifestTest,InvalidAndroidAppType)92 TEST_F(ReplacementAppsManifestTest, InvalidAndroidAppType) {
93   LoadAndExpectError(CreateManifest(nullptr, "123"),
94                      manifest_errors::kInvalidReplacementAndroidApp);
95   LoadAndExpectError(CreateManifest(nullptr, "true"),
96                      manifest_errors::kInvalidReplacementAndroidApp);
97   LoadAndExpectError(CreateManifest(nullptr, "{}"),
98                      manifest_errors::kInvalidReplacementAndroidApp);
99   LoadAndExpectError(CreateManifest(nullptr, R"({"foo": false})"),
100                      manifest_errors::kInvalidReplacementAndroidApp);
101   LoadAndExpectError(CreateManifest(nullptr, R"(["com.company.app"])"),
102                      manifest_errors::kInvalidReplacementAndroidApp);
103 }
104 
TEST_F(ReplacementAppsManifestTest,InvalidWebAppType)105 TEST_F(ReplacementAppsManifestTest, InvalidWebAppType) {
106   LoadAndExpectError(CreateManifest("32", nullptr),
107                      manifest_errors::kInvalidReplacementWebApp);
108   LoadAndExpectError(CreateManifest("true", nullptr),
109                      manifest_errors::kInvalidReplacementWebApp);
110   LoadAndExpectError(CreateManifest(R"("not_a_valid_url")", nullptr),
111                      manifest_errors::kInvalidReplacementWebApp);
112   LoadAndExpectError(CreateManifest("{}", nullptr),
113                      manifest_errors::kInvalidReplacementWebApp);
114   LoadAndExpectError(CreateManifest(R"({"foo": false})", nullptr),
115                      manifest_errors::kInvalidReplacementWebApp);
116   LoadAndExpectError(CreateManifest(R"("http://not_secure.com")", nullptr),
117                      manifest_errors::kInvalidReplacementWebApp);
118   LoadAndExpectError(CreateManifest(R"(["https://secure.com"])", nullptr),
119                      manifest_errors::kInvalidReplacementWebApp);
120   LoadAndExpectError(
121       CreateManifest(R"(["https://www.google.com", "not_a_valid_url"])",
122                      nullptr),
123       manifest_errors::kInvalidReplacementWebApp);
124 }
125 
TEST_F(ReplacementAppsManifestTest,VerifyParse)126 TEST_F(ReplacementAppsManifestTest, VerifyParse) {
127   scoped_refptr<Extension> good = LoadAndExpectSuccess(
128       CreateManifest(R"("https://www.google.com")", R"("com.company.app")"));
129   EXPECT_TRUE(ReplacementAppsInfo::HasReplacementWebApp(good.get()));
130   EXPECT_EQ(ReplacementAppsInfo::GetReplacementWebApp(good.get()),
131             GURL("https://www.google.com"));
132   EXPECT_TRUE(ReplacementAppsInfo::HasReplacementAndroidApp(good.get()));
133   EXPECT_EQ(ReplacementAppsInfo::GetReplacementAndroidApp(good.get()),
134             "com.company.app");
135 }
136 
137 }  // namespace extensions
138