constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 1 | // Copyright 2016 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 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 5 | #include <map> |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 6 | #include <memory> |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 7 | #include <utility> |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 8 | |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 9 | #include "base/bind.h" |
| 10 | #include "base/callback.h" |
| 11 | #include "base/run_loop.h" |
constantina | e4c513e7 | 2017-02-07 02:14:10 | [diff] [blame] | 12 | #include "base/strings/utf_string_conversions.h" |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 13 | #include "chrome/browser/webshare/share_service_impl.h" |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 14 | #include "chrome/browser/webshare/webshare_target.h" |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 15 | #include "chrome/common/pref_names.h" |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 16 | #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 17 | #include "components/prefs/pref_registry_simple.h" |
| 18 | #include "components/prefs/scoped_user_pref_update.h" |
| 19 | #include "components/prefs/testing_pref_service.h" |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 20 | #include "mojo/public/cpp/bindings/interface_request.h" |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 21 | #include "mojo/public/cpp/bindings/strong_binding.h" |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 22 | #include "testing/gtest/include/gtest/gtest.h" |
| 23 | #include "url/gurl.h" |
| 24 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 25 | namespace { |
| 26 | |
| 27 | constexpr char kTitle[] = "My title"; |
| 28 | constexpr char kText[] = "My text"; |
| 29 | constexpr char kUrlSpec[] = "https://www.google.com/"; |
| 30 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 31 | constexpr char kTargetName[] = "Share Target"; |
| 32 | constexpr char kUrlTemplate[] = "share?title={title}&text={text}&url={url}"; |
| 33 | constexpr char kManifestUrlHigh[] = |
| 34 | "https://www.example-high.com/target/manifest.json"; |
| 35 | constexpr char kManifestUrlLow[] = |
| 36 | "https://www.example-low.com/target/manifest.json"; |
| 37 | constexpr char kManifestUrlMin[] = |
| 38 | "https://www.example-min.com/target/manifest.json"; |
| 39 | |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 40 | void DidShare(blink::mojom::ShareError expected_error, |
| 41 | blink::mojom::ShareError error) { |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 42 | EXPECT_EQ(expected_error, error); |
| 43 | } |
| 44 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 45 | class ShareServiceTestImpl : public ShareServiceImpl { |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 46 | public: |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 47 | explicit ShareServiceTestImpl(blink::mojom::ShareServiceRequest request) |
| 48 | : binding_(this) { |
| 49 | binding_.Bind(std::move(request)); |
| 50 | |
| 51 | pref_service_.reset(new TestingPrefServiceSimple()); |
| 52 | pref_service_->registry()->RegisterDictionaryPref( |
| 53 | prefs::kWebShareVisitedTargets); |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 54 | } |
| 55 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 56 | void AddShareTargetToPrefs(const std::string& manifest_url, |
| 57 | const std::string& name, |
| 58 | const std::string& url_template) { |
| 59 | constexpr char kUrlTemplateKey[] = "url_template"; |
| 60 | constexpr char kNameKey[] = "name"; |
| 61 | |
| 62 | DictionaryPrefUpdate update(GetPrefService(), |
| 63 | prefs::kWebShareVisitedTargets); |
| 64 | base::DictionaryValue* share_target_dict = update.Get(); |
| 65 | |
| 66 | std::unique_ptr<base::DictionaryValue> origin_dict( |
| 67 | new base::DictionaryValue); |
| 68 | |
jdoerrie | fbb03dd | 2017-08-17 14:43:26 | [diff] [blame] | 69 | origin_dict->SetKey(kUrlTemplateKey, base::Value(url_template)); |
| 70 | origin_dict->SetKey(kNameKey, base::Value(name)); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 71 | |
| 72 | share_target_dict->SetWithoutPathExpansion(manifest_url, |
| 73 | std::move(origin_dict)); |
| 74 | } |
| 75 | |
| 76 | void SetEngagementForTarget(const std::string& manifest_url, |
| 77 | blink::mojom::EngagementLevel level) { |
| 78 | engagement_map_[manifest_url] = level; |
| 79 | } |
| 80 | |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 81 | void set_run_loop(base::RunLoop* run_loop) { |
| 82 | quit_run_loop_ = run_loop->QuitClosure(); |
| 83 | } |
| 84 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 85 | const std::string& GetLastUsedTargetURL() { return last_used_target_url_; } |
| 86 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 87 | const std::vector<WebShareTarget>& GetTargetsInPicker() { |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 88 | return targets_in_picker_; |
| 89 | } |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 90 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 91 | void PickTarget(const std::string& target_url) { |
| 92 | const auto& it = |
| 93 | std::find_if(targets_in_picker_.begin(), targets_in_picker_.end(), |
| 94 | [&target_url](const WebShareTarget& target) { |
| 95 | return target.manifest_url().spec() == target_url; |
| 96 | }); |
| 97 | DCHECK(it != targets_in_picker_.end()); |
| 98 | std::move(picker_callback_).Run(&*it); |
| 99 | } |
| 100 | |
ortuno | 928d1410 | 2017-05-02 00:09:05 | [diff] [blame] | 101 | chrome::WebShareTargetPickerCallback picker_callback() { |
| 102 | return std::move(picker_callback_); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 103 | } |
| 104 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 105 | private: |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 106 | void ShowPickerDialog( |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 107 | std::vector<WebShareTarget> targets, |
ortuno | 928d1410 | 2017-05-02 00:09:05 | [diff] [blame] | 108 | chrome::WebShareTargetPickerCallback callback) override { |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 109 | // Store the arguments passed to the picker dialog. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 110 | targets_in_picker_ = std::move(targets); |
ortuno | 928d1410 | 2017-05-02 00:09:05 | [diff] [blame] | 111 | picker_callback_ = std::move(callback); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 112 | |
| 113 | // Quit the test's run loop. It is the test's responsibility to call the |
| 114 | // callback, to simulate the user's choice. |
| 115 | quit_run_loop_.Run(); |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 116 | } |
| 117 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 118 | void OpenTargetURL(const GURL& target_url) override { |
| 119 | last_used_target_url_ = target_url.spec(); |
| 120 | } |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 121 | |
| 122 | PrefService* GetPrefService() override { return pref_service_.get(); } |
| 123 | |
| 124 | blink::mojom::EngagementLevel GetEngagementLevel(const GURL& url) override { |
| 125 | return engagement_map_[url.spec()]; |
| 126 | } |
| 127 | |
| 128 | mojo::Binding<blink::mojom::ShareService> binding_; |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 129 | std::unique_ptr<TestingPrefServiceSimple> pref_service_; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 130 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 131 | std::map<std::string, blink::mojom::EngagementLevel> engagement_map_; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 132 | // Closure to quit the test's run loop. |
| 133 | base::Closure quit_run_loop_; |
| 134 | |
| 135 | // The last URL passed to OpenTargetURL. |
| 136 | std::string last_used_target_url_; |
| 137 | // The targets passed to ShowPickerDialog. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 138 | std::vector<WebShareTarget> targets_in_picker_; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 139 | // The callback passed to ShowPickerDialog (which is supposed to be called |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 140 | // with the user's chosen result, or nullptr if cancelled). |
ortuno | 928d1410 | 2017-05-02 00:09:05 | [diff] [blame] | 141 | chrome::WebShareTargetPickerCallback picker_callback_; |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 142 | }; |
| 143 | |
| 144 | class ShareServiceImplUnittest : public ChromeRenderViewHostTestHarness { |
| 145 | public: |
| 146 | ShareServiceImplUnittest() = default; |
| 147 | ~ShareServiceImplUnittest() override = default; |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 148 | |
| 149 | void SetUp() override { |
| 150 | ChromeRenderViewHostTestHarness::SetUp(); |
| 151 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 152 | share_service_helper_ = base::MakeUnique<ShareServiceTestImpl>( |
| 153 | mojo::MakeRequest(&share_service_)); |
| 154 | |
| 155 | share_service_helper_->SetEngagementForTarget( |
| 156 | kManifestUrlHigh, blink::mojom::EngagementLevel::HIGH); |
| 157 | share_service_helper_->SetEngagementForTarget( |
| 158 | kManifestUrlMin, blink::mojom::EngagementLevel::MINIMAL); |
| 159 | share_service_helper_->SetEngagementForTarget( |
| 160 | kManifestUrlLow, blink::mojom::EngagementLevel::LOW); |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 161 | } |
| 162 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 163 | void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); } |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 164 | |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 165 | blink::mojom::ShareService* share_service() const { |
| 166 | return share_service_.get(); |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 167 | } |
| 168 | |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 169 | ShareServiceTestImpl* share_service_helper() const { |
| 170 | return share_service_helper_.get(); |
| 171 | } |
| 172 | |
| 173 | void DeleteShareService() { share_service_helper_.reset(); } |
| 174 | |
| 175 | private: |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 176 | blink::mojom::ShareServicePtr share_service_; |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 177 | std::unique_ptr<ShareServiceTestImpl> share_service_helper_; |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 178 | }; |
| 179 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 180 | } // namespace |
| 181 | |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 182 | // Basic test to check the Share method calls the callback with the expected |
| 183 | // parameters. |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 184 | TEST_F(ShareServiceImplUnittest, ShareCallbackParams) { |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 185 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlLow, kTargetName, |
| 186 | kUrlTemplate); |
| 187 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlHigh, kTargetName, |
| 188 | kUrlTemplate); |
Matt Giuca | e0739ed0 | 2017-09-26 09:28:22 | [diff] [blame] | 189 | // Expect this invalid URL to be ignored (not crash); |
| 190 | // https://crbug.com/762388. |
| 191 | share_service_helper()->AddShareTargetToPrefs("", kTargetName, kUrlTemplate); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 192 | |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 193 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 194 | base::Bind(&DidShare, blink::mojom::ShareError::OK); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 195 | |
| 196 | base::RunLoop run_loop; |
| 197 | share_service_helper()->set_run_loop(&run_loop); |
| 198 | |
| 199 | const GURL url(kUrlSpec); |
| 200 | share_service()->Share(kTitle, kText, url, callback); |
| 201 | |
| 202 | run_loop.Run(); |
| 203 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 204 | std::vector<WebShareTarget> expected_targets; |
| 205 | expected_targets.emplace_back(GURL(kManifestUrlHigh), kTargetName, |
| 206 | kUrlTemplate); |
| 207 | expected_targets.emplace_back(GURL(kManifestUrlLow), kTargetName, |
| 208 | kUrlTemplate); |
| 209 | EXPECT_EQ(expected_targets, share_service_helper()->GetTargetsInPicker()); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 210 | |
| 211 | // Pick example-low.com. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 212 | share_service_helper()->PickTarget(kManifestUrlLow); |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 213 | |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 214 | const char kExpectedURL[] = |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 215 | "https://www.example-low.com/target/" |
| 216 | "share?title=My%20title&text=My%20text&url=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww." |
| 217 | "google.com%2F"; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 218 | EXPECT_EQ(kExpectedURL, share_service_helper()->GetLastUsedTargetURL()); |
constantina | c8b2173b | 2016-12-15 05:55:51 | [diff] [blame] | 219 | } |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 220 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 221 | // Tests the result of cancelling the share in the picker UI, that doesn't have |
| 222 | // any targets. |
| 223 | TEST_F(ShareServiceImplUnittest, ShareCancelNoTargets) { |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 224 | // Expect an error message in response. |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 225 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 226 | base::Bind(&DidShare, blink::mojom::ShareError::CANCELED); |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 227 | |
| 228 | base::RunLoop run_loop; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 229 | share_service_helper()->set_run_loop(&run_loop); |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 230 | |
| 231 | const GURL url(kUrlSpec); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 232 | share_service()->Share(kTitle, kText, url, callback); |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 233 | |
| 234 | run_loop.Run(); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 235 | |
| 236 | EXPECT_TRUE(share_service_helper()->GetTargetsInPicker().empty()); |
| 237 | |
| 238 | // Cancel the dialog. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 239 | share_service_helper()->picker_callback().Run(nullptr); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 240 | |
| 241 | EXPECT_TRUE(share_service_helper()->GetLastUsedTargetURL().empty()); |
mgiuca | 39e4067 | 2017-01-31 04:16:49 | [diff] [blame] | 242 | } |
| 243 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 244 | // Tests the result of cancelling the share in the picker UI, that has targets. |
| 245 | TEST_F(ShareServiceImplUnittest, ShareCancelWithTargets) { |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 246 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlHigh, kTargetName, |
| 247 | kUrlTemplate); |
| 248 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlLow, kTargetName, |
| 249 | kUrlTemplate); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 250 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 251 | // Expect an error message in response. |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 252 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 253 | base::Bind(&DidShare, blink::mojom::ShareError::CANCELED); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 254 | |
| 255 | base::RunLoop run_loop; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 256 | share_service_helper()->set_run_loop(&run_loop); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 257 | |
| 258 | const GURL url(kUrlSpec); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 259 | share_service()->Share(kTitle, kText, url, callback); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 260 | |
| 261 | run_loop.Run(); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 262 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 263 | std::vector<WebShareTarget> expected_targets; |
| 264 | expected_targets.emplace_back(GURL(kManifestUrlHigh), kTargetName, |
| 265 | kUrlTemplate); |
| 266 | expected_targets.emplace_back(GURL(kManifestUrlLow), kTargetName, |
| 267 | kUrlTemplate); |
| 268 | EXPECT_EQ(expected_targets, share_service_helper()->GetTargetsInPicker()); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 269 | |
| 270 | // Cancel the dialog. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 271 | share_service_helper()->picker_callback().Run(nullptr); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 272 | |
| 273 | EXPECT_TRUE(share_service_helper()->GetLastUsedTargetURL().empty()); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 274 | } |
| 275 | |
mgiuca | f3a4c63 | 2017-02-21 08:08:59 | [diff] [blame] | 276 | // Tests a target with a broken URL template (ReplacePlaceholders failure). |
| 277 | TEST_F(ShareServiceImplUnittest, ShareBrokenUrl) { |
| 278 | // Invalid placeholders. Detailed tests for broken templates are in the |
| 279 | // ReplacePlaceholders test; this just tests the share response. |
| 280 | constexpr char kBrokenUrlTemplate[] = "share?title={title"; |
| 281 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlHigh, kTargetName, |
| 282 | kBrokenUrlTemplate); |
| 283 | |
| 284 | // Expect an error message in response. |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 285 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 286 | base::Bind(&DidShare, blink::mojom::ShareError::INTERNAL_ERROR); |
mgiuca | f3a4c63 | 2017-02-21 08:08:59 | [diff] [blame] | 287 | |
| 288 | base::RunLoop run_loop; |
| 289 | share_service_helper()->set_run_loop(&run_loop); |
| 290 | |
| 291 | const GURL url(kUrlSpec); |
| 292 | share_service()->Share(kTitle, kText, url, callback); |
| 293 | |
| 294 | run_loop.Run(); |
| 295 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 296 | std::vector<WebShareTarget> expected_targets; |
| 297 | expected_targets.emplace_back(GURL(kManifestUrlHigh), kTargetName, |
| 298 | kBrokenUrlTemplate); |
| 299 | EXPECT_EQ(expected_targets, share_service_helper()->GetTargetsInPicker()); |
mgiuca | f3a4c63 | 2017-02-21 08:08:59 | [diff] [blame] | 300 | |
| 301 | // Pick example-high.com. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 302 | share_service_helper()->PickTarget(kManifestUrlHigh); |
mgiuca | f3a4c63 | 2017-02-21 08:08:59 | [diff] [blame] | 303 | |
| 304 | EXPECT_TRUE(share_service_helper()->GetLastUsedTargetURL().empty()); |
| 305 | } |
| 306 | |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 307 | // Test to check that only targets with enough engagement were in picker. |
| 308 | TEST_F(ShareServiceImplUnittest, ShareWithSomeInsufficientlyEngagedTargets) { |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 309 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlMin, kTargetName, |
| 310 | kUrlTemplate); |
| 311 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlLow, kTargetName, |
| 312 | kUrlTemplate); |
| 313 | |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 314 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 315 | base::Bind(&DidShare, blink::mojom::ShareError::OK); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 316 | |
| 317 | base::RunLoop run_loop; |
| 318 | share_service_helper()->set_run_loop(&run_loop); |
| 319 | |
| 320 | const GURL url(kUrlSpec); |
| 321 | share_service()->Share(kTitle, kText, url, callback); |
| 322 | |
| 323 | run_loop.Run(); |
| 324 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 325 | std::vector<WebShareTarget> expected_targets; |
| 326 | expected_targets.emplace_back(GURL(kManifestUrlLow), kTargetName, |
| 327 | kUrlTemplate); |
| 328 | EXPECT_EQ(expected_targets, share_service_helper()->GetTargetsInPicker()); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 329 | |
| 330 | // Pick example-low.com. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 331 | share_service_helper()->PickTarget(kManifestUrlLow); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 332 | |
| 333 | const char kExpectedURL[] = |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 334 | "https://www.example-low.com/target/" |
| 335 | "share?title=My%20title&text=My%20text&url=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww." |
| 336 | "google.com%2F"; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 337 | EXPECT_EQ(kExpectedURL, share_service_helper()->GetLastUsedTargetURL()); |
| 338 | } |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 339 | |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 340 | // Test that deleting the share service while the picker is open does not crash |
| 341 | // (https://crbug.com/690775). |
| 342 | TEST_F(ShareServiceImplUnittest, ShareServiceDeletion) { |
| 343 | share_service_helper()->AddShareTargetToPrefs(kManifestUrlLow, kTargetName, |
| 344 | kUrlTemplate); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 345 | |
| 346 | base::RunLoop run_loop; |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 347 | share_service_helper()->set_run_loop(&run_loop); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 348 | |
| 349 | const GURL url(kUrlSpec); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 350 | // Expect the callback to never be called (since the share service is |
| 351 | // destroyed before the picker is closed). |
| 352 | // TODO(mgiuca): This probably should still complete the share, if not |
| 353 | // cancelled, even if the underlying tab is closed. |
mgiuca | 17e725c | 2017-03-03 02:57:23 | [diff] [blame] | 354 | base::Callback<void(blink::mojom::ShareError)> callback = |
| 355 | base::Bind([](blink::mojom::ShareError error) { FAIL(); }); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 356 | share_service()->Share(kTitle, kText, url, callback); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 357 | |
| 358 | run_loop.Run(); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 359 | |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 360 | std::vector<WebShareTarget> expected_targets; |
| 361 | expected_targets.emplace_back(GURL(kManifestUrlLow), kTargetName, |
| 362 | kUrlTemplate); |
| 363 | EXPECT_EQ(expected_targets, share_service_helper()->GetTargetsInPicker()); |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 364 | |
ortuno | 928d1410 | 2017-05-02 00:09:05 | [diff] [blame] | 365 | chrome::WebShareTargetPickerCallback picker_callback = |
mgiuca | bd4b24d | 2017-02-17 01:40:57 | [diff] [blame] | 366 | share_service_helper()->picker_callback(); |
| 367 | |
| 368 | DeleteShareService(); |
| 369 | |
| 370 | // Pick example-low.com. |
Giovanni Ortuño Urquidi | 97f8bd52 | 2017-06-16 04:04:37 | [diff] [blame] | 371 | std::move(picker_callback).Run(&expected_targets[0]); |
constantina | 5558f3f3 | 2017-02-13 05:37:54 | [diff] [blame] | 372 | } |
| 373 | |
constantina | 2cfa55e | 2017-01-13 06:36:55 | [diff] [blame] | 374 | // Replace various numbers of placeholders in various orders. Placeholders are |
| 375 | // adjacent to eachother; there are no padding characters. |
| 376 | TEST_F(ShareServiceImplUnittest, ReplacePlaceholders) { |
| 377 | const GURL url(kUrlSpec); |
| 378 | std::string url_template_filled; |
| 379 | bool succeeded; |
| 380 | |
| 381 | // No placeholders |
| 382 | std::string url_template = "blank"; |
| 383 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 384 | url, &url_template_filled); |
| 385 | EXPECT_TRUE(succeeded); |
| 386 | EXPECT_EQ("blank", url_template_filled); |
| 387 | |
| 388 | // Empty |url_template| |
| 389 | url_template = ""; |
| 390 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 391 | url, &url_template_filled); |
| 392 | EXPECT_TRUE(succeeded); |
| 393 | EXPECT_EQ("", url_template_filled); |
| 394 | |
| 395 | // One title placeholder. |
| 396 | url_template = "{title}"; |
| 397 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 398 | url, &url_template_filled); |
| 399 | EXPECT_TRUE(succeeded); |
| 400 | EXPECT_EQ("My%20title", url_template_filled); |
| 401 | |
| 402 | // One text placeholder. |
| 403 | url_template = "{text}"; |
| 404 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 405 | url, &url_template_filled); |
| 406 | EXPECT_TRUE(succeeded); |
| 407 | EXPECT_EQ("My%20text", url_template_filled); |
| 408 | |
| 409 | // One url placeholder. |
| 410 | url_template = "{url}"; |
| 411 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 412 | url, &url_template_filled); |
| 413 | EXPECT_TRUE(succeeded); |
| 414 | EXPECT_EQ("https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2F", url_template_filled); |
| 415 | |
| 416 | // One of each placeholder, in title, text, url order. |
| 417 | url_template = "{title}{text}{url}"; |
| 418 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 419 | url, &url_template_filled); |
| 420 | EXPECT_TRUE(succeeded); |
| 421 | EXPECT_EQ("My%20titleMy%20texthttps%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2F", |
| 422 | url_template_filled); |
| 423 | |
| 424 | // One of each placeholder, in url, text, title order. |
| 425 | url_template = "{url}{text}{title}"; |
| 426 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 427 | url, &url_template_filled); |
| 428 | EXPECT_TRUE(succeeded); |
| 429 | EXPECT_EQ("https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2FMy%20textMy%20title", |
| 430 | url_template_filled); |
| 431 | |
| 432 | // Two of each placeholder, some next to each other, others not. |
| 433 | url_template = "{title}{url}{text}{text}{title}{url}"; |
| 434 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 435 | url, &url_template_filled); |
| 436 | EXPECT_TRUE(succeeded); |
| 437 | EXPECT_EQ( |
| 438 | "My%20titlehttps%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2FMy%20textMy%20textMy%20" |
| 439 | "titlehttps%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2F", |
| 440 | url_template_filled); |
| 441 | |
| 442 | // Placeholders are in a query string, as values. The expected use case. |
| 443 | // Two of each placeholder, some next to each other, others not. |
| 444 | url_template = |
| 445 | "?title={title}&url={url}&text={text}&text={text}&" |
| 446 | "title={title}&url={url}"; |
| 447 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 448 | url, &url_template_filled); |
| 449 | EXPECT_TRUE(succeeded); |
| 450 | EXPECT_EQ( |
| 451 | "?title=My%20title&url=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2F&text=My%20text&" |
| 452 | "text=My%20text&title=My%20title&url=https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttps%2Fwww.google.com%2F", |
| 453 | url_template_filled); |
| 454 | |
| 455 | // Badly nested placeholders. |
| 456 | url_template = "{"; |
| 457 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 458 | url, &url_template_filled); |
| 459 | EXPECT_FALSE(succeeded); |
| 460 | |
| 461 | url_template = "{title"; |
| 462 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 463 | url, &url_template_filled); |
| 464 | EXPECT_FALSE(succeeded); |
| 465 | |
| 466 | url_template = "{title{text}}"; |
| 467 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 468 | url, &url_template_filled); |
| 469 | EXPECT_FALSE(succeeded); |
| 470 | |
| 471 | url_template = "{title{}"; |
| 472 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 473 | url, &url_template_filled); |
| 474 | EXPECT_FALSE(succeeded); |
| 475 | |
| 476 | url_template = "{title}}"; |
| 477 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 478 | url, &url_template_filled); |
| 479 | EXPECT_FALSE(succeeded); |
| 480 | |
| 481 | // Placeholder with non-identifier character. |
| 482 | url_template = "{title?}"; |
| 483 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 484 | url, &url_template_filled); |
| 485 | EXPECT_FALSE(succeeded); |
| 486 | |
| 487 | // Placeholder with digit character. |
| 488 | url_template = "{title1}"; |
| 489 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 490 | url, &url_template_filled); |
| 491 | EXPECT_TRUE(succeeded); |
| 492 | EXPECT_EQ("", url_template_filled); |
| 493 | |
| 494 | // Empty placeholder. |
| 495 | url_template = "{}"; |
| 496 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 497 | url, &url_template_filled); |
| 498 | EXPECT_TRUE(succeeded); |
| 499 | EXPECT_EQ("", url_template_filled); |
| 500 | |
| 501 | // Unexpected placeholders. |
| 502 | url_template = "{nonexistentplaceholder}"; |
| 503 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 504 | url, &url_template_filled); |
| 505 | EXPECT_TRUE(succeeded); |
| 506 | EXPECT_EQ("", url_template_filled); |
| 507 | |
| 508 | // |url_template| with % escapes. |
| 509 | url_template = "%20{title}%20"; |
| 510 | succeeded = ShareServiceImpl::ReplacePlaceholders(url_template, kTitle, kText, |
| 511 | url, &url_template_filled); |
| 512 | EXPECT_TRUE(succeeded); |
| 513 | EXPECT_EQ("%20My%20title%20", url_template_filled); |
| 514 | |
| 515 | // Share data that contains percent escapes. |
| 516 | url_template = "{title}"; |
| 517 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 518 | url_template, "My%20title", kText, url, &url_template_filled); |
| 519 | EXPECT_TRUE(succeeded); |
| 520 | EXPECT_EQ("My%2520title", url_template_filled); |
| 521 | |
| 522 | // Share data that contains placeholders. These should not be replaced. |
| 523 | url_template = "{title}"; |
| 524 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 525 | url_template, "{title}", kText, url, &url_template_filled); |
| 526 | EXPECT_TRUE(succeeded); |
| 527 | EXPECT_EQ("%7Btitle%7D", url_template_filled); |
| 528 | |
| 529 | // All characters that shouldn't be escaped. |
| 530 | url_template = "{title}"; |
| 531 | succeeded = |
| 532 | ShareServiceImpl::ReplacePlaceholders(url_template, |
| 533 | "-_.!~*'()0123456789" |
| 534 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 535 | "abcdefghijklmnopqrstuvwxyz", |
| 536 | kText, url, &url_template_filled); |
| 537 | EXPECT_TRUE(succeeded); |
| 538 | EXPECT_EQ( |
| 539 | "-_.!~*'()0123456789" |
| 540 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 541 | "abcdefghijklmnopqrstuvwxyz", |
| 542 | url_template_filled); |
| 543 | |
| 544 | // All characters that should be escaped. |
| 545 | url_template = "{title}"; |
| 546 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 547 | url_template, " \"#$%&+,/:;<=>?@[\\]^`{|}", kText, url, |
| 548 | &url_template_filled); |
| 549 | EXPECT_TRUE(succeeded); |
| 550 | EXPECT_EQ( |
| 551 | "%20%22%23%24%25%26%2B%2C%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%60%7B%7C%" |
| 552 | "7D", |
| 553 | url_template_filled); |
| 554 | |
| 555 | // Unicode chars. |
| 556 | // U+263B |
| 557 | url_template = "{title}"; |
| 558 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 559 | url_template, "\xe2\x98\xbb", kText, url, &url_template_filled); |
| 560 | EXPECT_TRUE(succeeded); |
| 561 | EXPECT_EQ("%E2%98%BB", url_template_filled); |
| 562 | |
| 563 | // U+00E9 |
| 564 | url_template = "{title}"; |
| 565 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 566 | url_template, "\xc3\xa9", kText, url, &url_template_filled); |
| 567 | EXPECT_TRUE(succeeded); |
| 568 | EXPECT_EQ("%C3%A9", url_template_filled); |
| 569 | |
| 570 | // U+1F4A9 |
| 571 | url_template = "{title}"; |
| 572 | succeeded = ShareServiceImpl::ReplacePlaceholders( |
| 573 | url_template, "\xf0\x9f\x92\xa9", kText, url, &url_template_filled); |
| 574 | EXPECT_TRUE(succeeded); |
| 575 | EXPECT_EQ("%F0%9F%92%A9", url_template_filled); |
| 576 | } |