OLD | NEW |
(Empty) | |
| 1 // Copyright 2012 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 #import <UIKit/UIKit.h> |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/callback.h" |
| 10 #include "base/ios/block_types.h" |
| 11 #include "base/mac/scoped_nsobject.h" |
| 12 #include "base/memory/ptr_util.h" |
| 13 #include "base/memory/ref_counted.h" |
| 14 #include "base/run_loop.h" |
| 15 #include "base/strings/stringprintf.h" |
| 16 #include "base/strings/sys_string_conversions.h" |
| 17 #include "components/bookmarks/test/bookmark_test_helpers.h" |
| 18 #include "components/history/core/browser/history_service.h" |
| 19 #include "components/keyed_service/core/service_access_type.h" |
| 20 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" |
| 21 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" |
| 22 #import "ios/chrome/browser/chrome_url_util.h" |
| 23 #include "ios/chrome/browser/history/history_service_factory.h" |
| 24 #import "ios/chrome/browser/tabs/tab.h" |
| 25 #import "ios/chrome/browser/tabs/tab_model.h" |
| 26 #import "ios/chrome/browser/tabs/tab_private.h" |
| 27 #import "ios/chrome/browser/ui/open_in_controller.h" |
| 28 #import "ios/chrome/browser/ui/open_in_controller_testing.h" |
| 29 #import "ios/chrome/browser/web/external_app_launcher.h" |
| 30 #include "ios/chrome/test/block_cleanup_test.h" |
| 31 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h" |
| 32 #include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" |
| 33 #import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_
metadata.h" |
| 34 #import "ios/public/provider/chrome/browser/native_app_launcher/fake_native_app_
whitelist_manager.h" |
| 35 #include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h" |
| 36 #import "ios/testing/ocmock_complex_type_helper.h" |
| 37 #import "ios/web/navigation/crw_session_controller.h" |
| 38 #import "ios/web/navigation/navigation_manager_impl.h" |
| 39 #include "ios/web/public/navigation_item.h" |
| 40 #import "ios/web/public/navigation_manager.h" |
| 41 #include "ios/web/public/referrer.h" |
| 42 #include "ios/web/public/test/test_web_thread_bundle.h" |
| 43 #import "ios/web/web_state/ui/crw_web_controller.h" |
| 44 #import "ios/web/web_state/web_state_impl.h" |
| 45 #import "net/base/mac/url_conversions.h" |
| 46 #include "net/http/http_response_headers.h" |
| 47 #include "testing/gtest/include/gtest/gtest.h" |
| 48 #include "testing/gtest_mac.h" |
| 49 #import "third_party/ocmock/OCMock/OCMock.h" |
| 50 |
| 51 using web::WebStateImpl; |
| 52 |
| 53 static const char kNewTabUrl[] = "chrome://newtab/"; |
| 54 static NSString* const kNewTabTitle = @"New Tab"; |
| 55 static const char kGoogleUserUrl[] = "http://google.com"; |
| 56 static const char kGoogleRedirectUrl[] = "http://www.google.fr/"; |
| 57 static NSString* const kGoogleTitle = @"Google"; |
| 58 static const char kOtherUserUrl[] = "http://other.com"; |
| 59 static const char kOtherRedirectUrl[] = "http://other.fr/"; |
| 60 static NSString* const kOtherTitle = @"Other"; |
| 61 const char kContentDispositionWithFilename[] = |
| 62 "attachment; filename=\"suggested_filename.pdf\""; |
| 63 const char kContentDispositionWithoutFilename[] = |
| 64 "attachment; parameter=parameter_value"; |
| 65 const char kInvalidFilenameUrl[] = "http://www.hostname.com/"; |
| 66 const char kValidFilenameUrl[] = "http://www.hostname.com/filename.pdf"; |
| 67 |
| 68 @interface ArrayTabModel : TabModel { |
| 69 @private |
| 70 base::scoped_nsobject<NSMutableArray> tabsForTesting_; |
| 71 } |
| 72 @end |
| 73 |
| 74 @implementation ArrayTabModel |
| 75 - (id)init { |
| 76 if ((self = [super init])) |
| 77 tabsForTesting_.reset([[NSMutableArray alloc] initWithCapacity:1]); |
| 78 return self; |
| 79 } |
| 80 |
| 81 - (void)addTabForTesting:(Tab*)tab { |
| 82 [tabsForTesting_ addObject:tab]; |
| 83 } |
| 84 |
| 85 - (NSUInteger)indexOfTab:(Tab*)tab { |
| 86 return [tabsForTesting_ indexOfObject:tab]; |
| 87 } |
| 88 |
| 89 - (NSUInteger)count { |
| 90 return [tabsForTesting_ count]; |
| 91 } |
| 92 |
| 93 - (void)closeTabAtIndex:(NSUInteger)index { |
| 94 [tabsForTesting_ removeObjectAtIndex:index]; |
| 95 } |
| 96 |
| 97 - (void)didCloseTab:(Tab*)closedTab { |
| 98 } |
| 99 @end |
| 100 |
| 101 @interface ExternalAppLauncherMock : OCMockComplexTypeHelper |
| 102 @end |
| 103 |
| 104 @implementation ExternalAppLauncherMock |
| 105 typedef BOOL (^openURLBlockType)(const GURL&, BOOL); |
| 106 |
| 107 - (BOOL)openURL:(const GURL&)url linkClicked:(BOOL)linkClicked { |
| 108 return static_cast<openURLBlockType>([self blockForSelector:_cmd])( |
| 109 url, linkClicked); |
| 110 } |
| 111 @end |
| 112 |
| 113 namespace { |
| 114 |
| 115 const web::LoadPhase kLoadRequested = web::LOAD_REQUESTED; |
| 116 const web::LoadPhase kPageLoading = web::PAGE_LOADING; |
| 117 const web::LoadPhase kPageLoaded = web::PAGE_LOADED; |
| 118 |
| 119 // Observer of a QueryHistory request. |
| 120 class HistoryQueryResultsObserver |
| 121 : public base::RefCountedThreadSafe<HistoryQueryResultsObserver> { |
| 122 public: |
| 123 HistoryQueryResultsObserver(base::RunLoop* run_loop) : run_loop_(run_loop) {} |
| 124 |
| 125 // Stores |results| and stops the current message loop. |
| 126 void ProcessResults(history::QueryResults* results) { |
| 127 results_.Swap(results); |
| 128 run_loop_->QuitWhenIdle(); |
| 129 } |
| 130 history::QueryResults* results() { return &results_; } |
| 131 |
| 132 protected: |
| 133 friend base::RefCountedThreadSafe<HistoryQueryResultsObserver>; |
| 134 virtual ~HistoryQueryResultsObserver(); |
| 135 |
| 136 private: |
| 137 history::QueryResults results_; |
| 138 base::RunLoop* run_loop_; |
| 139 }; |
| 140 |
| 141 HistoryQueryResultsObserver::~HistoryQueryResultsObserver() {} |
| 142 |
| 143 class FakeChromeBrowserProvider : public ios::TestChromeBrowserProvider { |
| 144 public: |
| 145 FakeChromeBrowserProvider(id<NativeAppMetadata> metadata) { |
| 146 FakeNativeAppWhitelistManager* fakeManager = |
| 147 [[[FakeNativeAppWhitelistManager alloc] init] autorelease]; |
| 148 fakeManager.metadata = metadata; |
| 149 manager_.reset([fakeManager retain]); |
| 150 } |
| 151 ~FakeChromeBrowserProvider() override {} |
| 152 |
| 153 id<NativeAppWhitelistManager> GetNativeAppWhitelistManager() const override { |
| 154 return manager_; |
| 155 } |
| 156 |
| 157 private: |
| 158 base::scoped_nsprotocol<id<NativeAppWhitelistManager>> manager_; |
| 159 }; |
| 160 |
| 161 class TabTest : public BlockCleanupTest { |
| 162 public: |
| 163 TabTest() : thread_bundle_(web::TestWebThreadBundle::REAL_FILE_THREAD) {} |
| 164 |
| 165 void SetUp() override { |
| 166 BlockCleanupTest::SetUp(); |
| 167 |
| 168 [[ChromeAppConstants sharedInstance] |
| 169 setCallbackSchemeForTesting:@"chromium"]; |
| 170 |
| 171 // Set up the testing profiles. |
| 172 TestChromeBrowserState::Builder test_cbs_builder; |
| 173 chrome_browser_state_ = test_cbs_builder.Build(); |
| 174 chrome_browser_state_->CreateBookmarkModel(false); |
| 175 bookmarks::test::WaitForBookmarkModelToLoad( |
| 176 ios::BookmarkModelFactory::GetForBrowserState( |
| 177 chrome_browser_state_.get())); |
| 178 ASSERT_TRUE(chrome_browser_state_->CreateHistoryService(true)); |
| 179 history_service_ = ios::HistoryServiceFactory::GetForBrowserState( |
| 180 chrome_browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS); |
| 181 |
| 182 ios::ChromeBrowserState* browser_state = chrome_browser_state_.get(); |
| 183 if (UseOffTheRecordBrowserState()) |
| 184 browser_state = browser_state->GetOffTheRecordChromeBrowserState(); |
| 185 |
| 186 mock_web_controller_ = |
| 187 [OCMockObject niceMockForClass:[CRWWebController class]]; |
| 188 std::unique_ptr<WebStateImpl> web_state_impl; |
| 189 web_state_impl.reset(new WebStateImpl(browser_state)); |
| 190 web_state_impl->SetWebController(mock_web_controller_); |
| 191 web_state_impl->GetNavigationManagerImpl().InitializeSession( |
| 192 @"window1", @"opener", NO, 0); |
| 193 WebStateImpl* web_state = web_state_impl.get(); |
| 194 [[[(OCMockObject*)mock_web_controller_ stub] |
| 195 andReturnValue:OCMOCK_VALUE(web_state)] webStateImpl]; |
| 196 web_controller_view_.reset([[UIView alloc] init]); |
| 197 [[[(OCMockObject*)mock_web_controller_ stub] |
| 198 andReturn:web_controller_view_.get()] view]; |
| 199 tab_.reset([[Tab alloc] initWithWindowName:nil |
| 200 opener:nullptr |
| 201 openedByDOM:NO |
| 202 model:nil |
| 203 browserState:browser_state]); |
| 204 web::NavigationManager::WebLoadParams params(GURL("chrome://version/")); |
| 205 [[tab_ webController] loadWithParams:params]; |
| 206 [tab_ replaceWebStateImpl:std::move(web_state_impl)]; |
| 207 |
| 208 // There should be no entries in the history at this point. |
| 209 history::QueryResults results; |
| 210 QueryAllHistory(&results); |
| 211 EXPECT_EQ(0UL, results.size()); |
| 212 mock_external_app_launcher_.reset([[ExternalAppLauncherMock alloc] |
| 213 initWithRepresentedObject: |
| 214 [OCMockObject mockForClass:[ExternalAppLauncher class]]]); |
| 215 [tab_ replaceExternalAppLauncher:mock_external_app_launcher_]; |
| 216 } |
| 217 |
| 218 void TearDown() override { |
| 219 [tab_ close]; |
| 220 |
| 221 BlockCleanupTest::TearDown(); |
| 222 } |
| 223 |
| 224 void BrowseTo(const GURL& userUrl, const GURL& redirectUrl, NSString* title) { |
| 225 [[[(id)mock_web_controller_ expect] |
| 226 andReturnValue:OCMOCK_VALUE(kLoadRequested)] loadPhase]; |
| 227 web::Referrer empty_referrer; |
| 228 [tab_ webWillAddPendingURL:userUrl transition:ui::PAGE_TRANSITION_TYPED]; |
| 229 [tab_ webDidAddPendingURL]; |
| 230 [tab_ webWillAddPendingURL:redirectUrl |
| 231 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT]; |
| 232 [[tab_ navigationManager]->GetSessionController() |
| 233 addPendingEntry:redirectUrl |
| 234 referrer:empty_referrer |
| 235 transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT |
| 236 rendererInitiated:YES]; |
| 237 [tab_ webDidAddPendingURL]; |
| 238 [[[(id)mock_web_controller_ expect] |
| 239 andReturnValue:OCMOCK_VALUE(kPageLoading)] loadPhase]; |
| 240 [[tab_ navigationManager]->GetSessionController() commitPendingEntry]; |
| 241 [[tab_ webController] webStateImpl]->OnNavigationCommitted(redirectUrl); |
| 242 [tab_ webDidStartLoadingURL:redirectUrl shouldUpdateHistory:YES]; |
| 243 [tab_ webController:mock_web_controller_ titleDidChange:title]; |
| 244 [[[(id)mock_web_controller_ expect] |
| 245 andReturnValue:OCMOCK_VALUE(kPageLoaded)] loadPhase]; |
| 246 [[tab_ webController] webStateImpl]->OnPageLoaded(redirectUrl, true); |
| 247 [tab_ webDidFinishWithURL:redirectUrl loadSuccess:YES]; |
| 248 } |
| 249 |
| 250 void BrowseToNewTab() { |
| 251 const GURL url(kNewTabUrl); |
| 252 // TODO(crbug.com/661992): This will not work with a mock CRWWebController. |
| 253 // The only test that uses it is currently disabled. |
| 254 web::NavigationManager::WebLoadParams params(url); |
| 255 params.transition_type = ui::PAGE_TRANSITION_TYPED; |
| 256 [[tab_ webController] loadWithParams:params]; |
| 257 [[[(id)mock_web_controller_ expect] |
| 258 andReturnValue:OCMOCK_VALUE(kPageLoading)] loadPhase]; |
| 259 [tab_ webDidStartLoadingURL:url shouldUpdateHistory:YES]; |
| 260 [[[(id)mock_web_controller_ expect] |
| 261 andReturnValue:OCMOCK_VALUE(kPageLoaded)] loadPhase]; |
| 262 [tab_ webDidFinishWithURL:url loadSuccess:YES]; |
| 263 [tab_ webController:mock_web_controller_ titleDidChange:kNewTabTitle]; |
| 264 } |
| 265 |
| 266 void QueryAllHistory(history::QueryResults* results) { |
| 267 base::CancelableTaskTracker tracker; |
| 268 base::RunLoop run_loop; |
| 269 scoped_refptr<HistoryQueryResultsObserver> observer( |
| 270 new HistoryQueryResultsObserver(&run_loop)); |
| 271 history_service_->QueryHistory( |
| 272 base::string16(), history::QueryOptions(), |
| 273 base::Bind(&HistoryQueryResultsObserver::ProcessResults, observer), |
| 274 &tracker); |
| 275 run_loop.Run(); |
| 276 results->Swap(observer->results()); |
| 277 } |
| 278 |
| 279 void CheckHistoryResult(const history::URLResult& historyResult, |
| 280 const GURL& expectedUrl, |
| 281 NSString* expectedTitle) { |
| 282 EXPECT_EQ(expectedUrl, historyResult.url()); |
| 283 EXPECT_EQ(base::SysNSStringToUTF16(expectedTitle), historyResult.title()); |
| 284 } |
| 285 |
| 286 void CheckCurrentItem(const GURL& expectedUrl, NSString* expectedTitle) { |
| 287 web::NavigationItem* item = [tab_ navigationManager]->GetVisibleItem(); |
| 288 EXPECT_EQ(expectedUrl, item->GetURL()); |
| 289 EXPECT_EQ(base::SysNSStringToUTF16(expectedTitle), item->GetTitle()); |
| 290 } |
| 291 |
| 292 void CheckCurrentItem(const history::URLResult& historyResult) { |
| 293 web::NavigationItem* item = [tab_ navigationManager]->GetVisibleItem(); |
| 294 CheckHistoryResult(historyResult, item->GetURL(), |
| 295 base::SysUTF16ToNSString(item->GetTitle())); |
| 296 } |
| 297 |
| 298 #ifndef NDEBUG |
| 299 // Method useful when debugging. |
| 300 void LogHistoryQueryResult(const history::QueryResults* results) { |
| 301 typedef history::QueryResults::URLResultVector::const_iterator iterator; |
| 302 for (iterator i = results->begin(); i != results->end(); ++i) { |
| 303 history::URLResult* result = *i; |
| 304 NSLog(@"title = %@; url = %@", base::SysUTF16ToNSString(result->title()), |
| 305 base::SysUTF8ToNSString(result->url().spec())); |
| 306 } |
| 307 } |
| 308 #endif |
| 309 |
| 310 virtual bool UseOffTheRecordBrowserState() const { return false; } |
| 311 |
| 312 protected: |
| 313 web::TestWebThreadBundle thread_bundle_; |
| 314 IOSChromeScopedTestingLocalState local_state_; |
| 315 std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; |
| 316 base::scoped_nsobject<Tab> tab_; |
| 317 history::HistoryService* history_service_; // weak |
| 318 CRWWebController* mock_web_controller_; // weak |
| 319 base::scoped_nsobject<UIView> web_controller_view_; |
| 320 base::scoped_nsobject<ArrayTabModel> tabModel_; |
| 321 base::scoped_nsobject<id> mock_external_app_launcher_; |
| 322 }; |
| 323 |
| 324 TEST_F(TabTest, AddToHistoryWithRedirect) { |
| 325 BrowseTo(GURL(kGoogleUserUrl), GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 326 history::QueryResults results; |
| 327 QueryAllHistory(&results); |
| 328 EXPECT_EQ(1U, results.size()); |
| 329 CheckHistoryResult(results[0], GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 330 CheckCurrentItem(results[0]); |
| 331 } |
| 332 |
| 333 // TODO(crbug.com/378098): Disabled because forward/back is now implemented in |
| 334 // CRWWebController, so this test cannot function with a mock CRWWebController. |
| 335 // Rewrite and re-enable this test when it becomes a CRWWebController or |
| 336 // NavigationManager test. |
| 337 TEST_F(TabTest, DISABLED_BackAndForward) { |
| 338 BrowseTo(GURL(kGoogleUserUrl), GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 339 BrowseTo(GURL(kOtherUserUrl), GURL(kOtherRedirectUrl), kOtherTitle); |
| 340 |
| 341 history::QueryResults results; |
| 342 QueryAllHistory(&results); |
| 343 EXPECT_EQ(2U, results.size()); |
| 344 CheckHistoryResult(results[0], GURL(kOtherRedirectUrl), kOtherTitle); |
| 345 CheckHistoryResult(results[1], GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 346 CheckCurrentItem(results[0]); |
| 347 } |
| 348 |
| 349 // TODO(crbug.com/378098): Disabled because navigation is no longer |
| 350 // possible with a mock |
| 351 // CRWWebController. Rewrite and re-enable this test when it becomes a |
| 352 // CRWWebController test. |
| 353 TEST_F(TabTest, DISABLED_NewTabInMiddleOfNavigation) { |
| 354 BrowseTo(GURL(kGoogleUserUrl), GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 355 BrowseToNewTab(); |
| 356 BrowseTo(GURL(kOtherUserUrl), GURL(kOtherRedirectUrl), kOtherTitle); |
| 357 |
| 358 // NOTE: NTP is not stored in the history. |
| 359 history::QueryResults results; |
| 360 QueryAllHistory(&results); |
| 361 EXPECT_EQ(2U, results.size()); |
| 362 CheckHistoryResult(results[0], GURL(kOtherRedirectUrl), kOtherTitle); |
| 363 CheckHistoryResult(results[1], GURL(kGoogleRedirectUrl), kGoogleTitle); |
| 364 } |
| 365 |
| 366 TEST_F(TabTest, GetSuggestedFilenameFromContentDisposition) { |
| 367 // If possible, the filename should be generated from the content-disposition |
| 368 // header. |
| 369 GURL url(kValidFilenameUrl); |
| 370 scoped_refptr<net::HttpResponseHeaders> headers = |
| 371 new net::HttpResponseHeaders("HTTP 1.1 200 OK"); |
| 372 headers->AddHeader(base::StringPrintf("Content-Type: application/pdf")); |
| 373 headers->AddHeader(base::StringPrintf("Content-Disposition: %s", |
| 374 kContentDispositionWithFilename)); |
| 375 [[tab_ webController] webStateImpl]->OnHttpResponseHeadersReceived( |
| 376 headers.get(), url); |
| 377 BrowseTo(url, url, [NSString string]); |
| 378 EXPECT_NSEQ(@"suggested_filename.pdf", |
| 379 [[tab_ openInController] suggestedFilename]); |
| 380 } |
| 381 |
| 382 TEST_F(TabTest, GetSuggestedFilenameFromURL) { |
| 383 // If the content-disposition header does not specify a filename, this should |
| 384 // be extracted from the last component of the url. |
| 385 GURL url(kValidFilenameUrl); |
| 386 scoped_refptr<net::HttpResponseHeaders> headers = |
| 387 new net::HttpResponseHeaders("HTTP 1.1 200 OK"); |
| 388 headers->AddHeader(base::StringPrintf("Content-Type: application/pdf")); |
| 389 headers->AddHeader(base::StringPrintf("Content-Disposition: %s", |
| 390 kContentDispositionWithoutFilename)); |
| 391 [[tab_ webController] webStateImpl]->OnHttpResponseHeadersReceived( |
| 392 headers.get(), url); |
| 393 BrowseTo(url, url, [NSString string]); |
| 394 EXPECT_NSEQ(@"filename.pdf", [[tab_ openInController] suggestedFilename]); |
| 395 } |
| 396 |
| 397 TEST_F(TabTest, GetSuggestedFilenameFromDefaultName) { |
| 398 // If the filename cannot be extracted from the content disposition or from |
| 399 // the url, the default filename "Document.pdf" should be used. |
| 400 GURL url(kInvalidFilenameUrl); |
| 401 scoped_refptr<net::HttpResponseHeaders> headers = |
| 402 new net::HttpResponseHeaders("HTTP 1.1 200 OK"); |
| 403 headers->AddHeader(base::StringPrintf("Content-Type: application/pdf")); |
| 404 [[tab_ webController] webStateImpl]->OnHttpResponseHeadersReceived( |
| 405 headers.get(), url); |
| 406 BrowseTo(url, url, [NSString string]); |
| 407 EXPECT_NSEQ(@"Document.pdf", [[tab_ openInController] suggestedFilename]); |
| 408 } |
| 409 |
| 410 // A separate test fixture is used to test opening external URLs using Google |
| 411 // App Launcher. In any of the tests for this feature, scenarios have to be |
| 412 // tested with the regular ChromeBrowserState AND the incognito |
| 413 // ChromeBrowserState. |
| 414 // In Incognito, -urlTriggersNativeAppLaunch:sourceURL should always return NO. |
| 415 class TabOpenAppTest : public TabTest { |
| 416 protected: |
| 417 // Tests that calling |urlTriggersNativeAppLaunch:sourceURL:linkClicked| calls |
| 418 // |openURL:| the expected number of times. |return_value| is the value to be |
| 419 // returned from |openURL:|. |expected_result| is the value that is checked |
| 420 // for from |urlTriggersNativeAppLaunch:sourceURL:linkClicked|. |
| 421 void TestOpenNativeAppURL(const GURL& url, |
| 422 BOOL return_value, |
| 423 NSUInteger expected_tab_call_count, |
| 424 BOOL expected_result) { |
| 425 ExpectWithMockedExternalAppLauncherOpenURL( |
| 426 return_value, expected_tab_call_count, ^{ |
| 427 EXPECT_EQ(expected_result, |
| 428 [tab_ urlTriggersNativeAppLaunch:url |
| 429 sourceURL:GURL("http://google.com") |
| 430 linkClicked:YES]); |
| 431 }); |
| 432 } |
| 433 |
| 434 // Stubs out |openURL:| and checks how many times it was called. |
| 435 void ExpectWithMockedExternalAppLauncherOpenURL( |
| 436 BOOL return_value, |
| 437 NSUInteger expected_tab_call_count, |
| 438 ProceduralBlock expectation_block) { |
| 439 __block NSUInteger counter = 0; |
| 440 [mock_external_app_launcher_ |
| 441 onSelector:@selector(openURL:linkClicked:) |
| 442 callBlockExpectation:(id) ^ (const GURL& url, BOOL linkClicked) { |
| 443 ++counter; |
| 444 return return_value; |
| 445 }]; |
| 446 expectation_block(); |
| 447 EXPECT_EQ(expected_tab_call_count, counter); |
| 448 [mock_external_app_launcher_ |
| 449 removeBlockExpectationOnSelector:@selector(openURL:linkClicked:)]; |
| 450 } |
| 451 }; |
| 452 |
| 453 // A version of TabOpenAppTests customized to use the off-the-record browser |
| 454 // state (instead of the non-incognito one). |
| 455 class TabOpenAppOffTheRecordTest : public TabOpenAppTest { |
| 456 private: |
| 457 bool UseOffTheRecordBrowserState() const override { return true; } |
| 458 }; |
| 459 |
| 460 // Tests the opening of matching native apps. |
| 461 TEST_F(TabOpenAppTest, testDummyURL) { |
| 462 EXPECT_FALSE([tab_ browserState]->IsOffTheRecord()); |
| 463 |
| 464 GURL no_native_app_url("dummy string"); |
| 465 TestOpenNativeAppURL(no_native_app_url, NO, 0, NO); |
| 466 } |
| 467 |
| 468 TEST_F(TabOpenAppTest, testURL) { |
| 469 EXPECT_FALSE([tab_ browserState]->IsOffTheRecord()); |
| 470 |
| 471 GURL testURL("http://www.youtube.com/"); |
| 472 // Fake metadata object to enable and disable autoopenlinks for testURL. |
| 473 base::scoped_nsobject<FakeNativeAppMetadata> metadata( |
| 474 [[FakeNativeAppMetadata alloc] init]); |
| 475 IOSChromeScopedTestingChromeBrowserProvider provider( |
| 476 base::MakeUnique<FakeChromeBrowserProvider>(metadata)); |
| 477 // Turn auto open on. |
| 478 int expectedCallCount = 1; |
| 479 [metadata setShouldAutoOpenLinks:YES]; |
| 480 TestOpenNativeAppURL(testURL, YES, expectedCallCount, YES); |
| 481 TestOpenNativeAppURL(testURL, NO, expectedCallCount, NO); |
| 482 |
| 483 // Turn auto open off. |
| 484 expectedCallCount = 0; |
| 485 [metadata setShouldAutoOpenLinks:NO]; |
| 486 TestOpenNativeAppURL(testURL, NO, expectedCallCount, NO); |
| 487 } |
| 488 |
| 489 // TODO(crbug.com/330189): This test fails if Google Maps is installed (usually |
| 490 // on device). |
| 491 TEST_F(TabOpenAppTest, DISABLED_testResetShouldAutoOpenOnFailure) { |
| 492 EXPECT_FALSE([tab_ browserState]->IsOffTheRecord()); |
| 493 |
| 494 // With a regular profile. |
| 495 GURL testURL("http://maps.google.com/"); |
| 496 // Fake metadata object |
| 497 base::scoped_nsobject<FakeNativeAppMetadata> metadata( |
| 498 [[FakeNativeAppMetadata alloc] init]); |
| 499 |
| 500 // Turn auto open on. |
| 501 [metadata setShouldAutoOpenLinks:YES]; |
| 502 int expectedCallCount = 2; |
| 503 TestOpenNativeAppURL(testURL, NO, expectedCallCount, NO); |
| 504 EXPECT_FALSE([metadata shouldAutoOpenLinks]); |
| 505 } |
| 506 |
| 507 // Tests the opening of matching native apps with off-the-record browser state. |
| 508 TEST_F(TabOpenAppOffTheRecordTest, testDummyURL) { |
| 509 EXPECT_TRUE([tab_ browserState]->IsOffTheRecord()); |
| 510 |
| 511 GURL no_native_app_url("dummy string"); |
| 512 TestOpenNativeAppURL(no_native_app_url, NO, 0, NO); |
| 513 } |
| 514 |
| 515 TEST_F(TabOpenAppOffTheRecordTest, testURL) { |
| 516 EXPECT_TRUE([tab_ browserState]->IsOffTheRecord()); |
| 517 |
| 518 // With a regular chrome browser state. |
| 519 GURL testURL("http://www.youtube.com/"); |
| 520 // Mock metadata object to enable and disable autoopenlinks for testURL. |
| 521 base::scoped_nsobject<FakeNativeAppMetadata> metadata( |
| 522 [[FakeNativeAppMetadata alloc] init]); |
| 523 IOSChromeScopedTestingChromeBrowserProvider provider( |
| 524 base::MakeUnique<FakeChromeBrowserProvider>(metadata)); |
| 525 |
| 526 // Turn auto open on. |
| 527 [metadata setShouldAutoOpenLinks:YES]; |
| 528 TestOpenNativeAppURL(testURL, NO, 0, NO); |
| 529 |
| 530 // Turn auto open off. |
| 531 [metadata setShouldAutoOpenLinks:NO]; |
| 532 TestOpenNativeAppURL(testURL, NO, 0, NO); |
| 533 } |
| 534 |
| 535 // TODO(crbug.com/330189): This test fails if Google Maps is installed (usually |
| 536 // on device). |
| 537 TEST_F(TabOpenAppOffTheRecordTest, DISABLED_testResetShouldAutoOpenOnFailure) { |
| 538 EXPECT_TRUE([tab_ browserState]->IsOffTheRecord()); |
| 539 |
| 540 // With a regular profile. |
| 541 GURL testURL("http://maps.google.com/"); |
| 542 // Fake metadata object. |
| 543 base::scoped_nsobject<FakeNativeAppMetadata> metadata( |
| 544 [[FakeNativeAppMetadata alloc] init]); |
| 545 |
| 546 // Turn auto open on. |
| 547 [metadata setShouldAutoOpenLinks:YES]; |
| 548 int expectedCallCount = 2; |
| 549 TestOpenNativeAppURL(testURL, NO, expectedCallCount, NO); |
| 550 EXPECT_FALSE([metadata shouldAutoOpenLinks]); |
| 551 } |
| 552 |
| 553 class TestRequestGroupID : public BlockCleanupTest { |
| 554 public: |
| 555 void SetUp() override { BlockCleanupTest::SetUp(); } |
| 556 void TearDown() override { BlockCleanupTest::TearDown(); } |
| 557 }; |
| 558 |
| 559 } // namespace |
OLD | NEW |