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