Index: ios/chrome/app/application_delegate/app_state_unittest.mm |
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f04cc588137e0ef8890252c621423eb19885557a |
--- /dev/null |
+++ b/ios/chrome/app/application_delegate/app_state_unittest.mm |
@@ -0,0 +1,933 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#import "ios/chrome/app/application_delegate/app_state.h" |
+ |
+#import <QuartzCore/QuartzCore.h> |
+ |
+#include "base/ios/block_types.h" |
+#include "base/mac/scoped_block.h" |
+#import "base/mac/scoped_nsobject.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/synchronization/lock.h" |
+#import "ios/chrome/app/application_delegate/app_navigation.h" |
+#import "ios/chrome/app/application_delegate/app_state_testing.h" |
+#import "ios/chrome/app/application_delegate/browser_launcher.h" |
+#import "ios/chrome/app/application_delegate/fake_startup_information.h" |
+#import "ios/chrome/app/application_delegate/memory_warning_helper.h" |
+#import "ios/chrome/app/application_delegate/metrics_mediator.h" |
+#import "ios/chrome/app/application_delegate/mock_tab_opener.h" |
+#import "ios/chrome/app/application_delegate/startup_information.h" |
+#import "ios/chrome/app/application_delegate/tab_switching.h" |
+#import "ios/chrome/app/application_delegate/user_activity_handler.h" |
+#import "ios/chrome/app/main_application_delegate.h" |
+#import "ios/chrome/app/safe_mode/safe_mode_coordinator.h" |
+#import "ios/chrome/app/safe_mode_crashing_modules_config.h" |
+#import "ios/chrome/browser/app_startup_parameters.h" |
+#include "ios/chrome/browser/chrome_url_constants.h" |
+#import "ios/chrome/browser/device_sharing/device_sharing_manager.h" |
+#import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h" |
+#import "ios/chrome/browser/tabs/tab_model.h" |
+#import "ios/chrome/browser/ui/browser_view_controller.h" |
+#import "ios/chrome/browser/ui/main/browser_view_information.h" |
+#import "ios/chrome/browser/ui/settings/settings_navigation_controller.h" |
+#import "ios/chrome/test/base/scoped_block_swizzler.h" |
+#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h" |
+#include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h" |
+#include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h" |
+#include "ios/public/provider/chrome/browser/user_feedback/test_user_feedback_provider.h" |
+#import "ios/testing/ocmock_complex_type_helper.h" |
+#include "ios/web/net/request_tracker_impl.h" |
+#import "ios/web/public/test/test_web_thread_bundle.h" |
+#include "testing/platform_test.h" |
+#import "third_party/ocmock/OCMock/OCMock.h" |
+#include "third_party/ocmock/gtest_support.h" |
+ |
+#pragma mark - Class definition. |
+ |
+namespace { |
+ |
+// A block that takes self as argument and return a BOOL. |
+typedef BOOL (^DecisionBlock)(id self); |
+// A block that takes the arguments of UserActivityHandler's |
+// +handleStartupParametersWithTabOpener. |
+typedef void (^HandleStartupParam)( |
+ id self, |
+ id<TabOpening> tabOpener, |
+ id<StartupInformation> startupInformation, |
+ id<BrowserViewInformation> browserViewInformation); |
+ |
+class FakeAppDistributionProvider : public AppDistributionProvider { |
+ public: |
+ FakeAppDistributionProvider() : cancel_called_(false) {} |
+ ~FakeAppDistributionProvider() override {} |
+ |
+ void CancelDistributionNotifications() override { cancel_called_ = true; } |
+ bool cancel_called() { return cancel_called_; } |
+ |
+ private: |
+ bool cancel_called_; |
+ DISALLOW_COPY_AND_ASSIGN(FakeAppDistributionProvider); |
+}; |
+ |
+class FakeUserFeedbackProvider : public TestUserFeedbackProvider { |
+ public: |
+ FakeUserFeedbackProvider() : synchronize_called_(false) {} |
+ ~FakeUserFeedbackProvider() override {} |
+ void Synchronize() override { synchronize_called_ = true; } |
+ bool synchronize_called() { return synchronize_called_; } |
+ |
+ private: |
+ bool synchronize_called_; |
+ DISALLOW_COPY_AND_ASSIGN(FakeUserFeedbackProvider); |
+}; |
+ |
+class FakeChromeBrowserProvider : public ios::TestChromeBrowserProvider { |
+ public: |
+ FakeChromeBrowserProvider() |
+ : app_distribution_provider_( |
+ base::MakeUnique<FakeAppDistributionProvider>()), |
+ user_feedback_provider_(base::MakeUnique<FakeUserFeedbackProvider>()) {} |
+ ~FakeChromeBrowserProvider() override {} |
+ |
+ AppDistributionProvider* GetAppDistributionProvider() const override { |
+ return app_distribution_provider_.get(); |
+ } |
+ |
+ UserFeedbackProvider* GetUserFeedbackProvider() const override { |
+ return user_feedback_provider_.get(); |
+ } |
+ |
+ private: |
+ std::unique_ptr<FakeAppDistributionProvider> app_distribution_provider_; |
+ std::unique_ptr<FakeUserFeedbackProvider> user_feedback_provider_; |
+ DISALLOW_COPY_AND_ASSIGN(FakeChromeBrowserProvider); |
+}; |
+ |
+} // namespace |
+ |
+class AppStateTest : public PlatformTest { |
+ protected: |
+ AppStateTest() { |
+ browser_launcher_mock_ = |
+ [OCMockObject mockForProtocol:@protocol(BrowserLauncher)]; |
+ startup_information_mock_ = |
+ [OCMockObject mockForProtocol:@protocol(StartupInformation)]; |
+ main_application_delegate_ = |
+ [OCMockObject mockForClass:[MainApplicationDelegate class]]; |
+ window_ = [OCMockObject mockForClass:[UIWindow class]]; |
+ browser_view_information_ = |
+ [OCMockObject mockForProtocol:@protocol(BrowserViewInformation)]; |
+ } |
+ |
+ void initializeIncognitoBlocker(UIWindow* window) { |
+ id application = [OCMockObject niceMockForClass:[UIApplication class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id browserViewInformation = |
+ [OCMockObject mockForProtocol:@protocol(BrowserViewInformation)]; |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ |
+ [[startup_information_mock_ stub] expireFirstUserActionRecorder]; |
+ [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount]; |
+ [[[tabModel stub] andReturnValue:@NO] isEmpty]; |
+ [[[browser_view_information_ stub] andReturn:tabModel] otrTabModel]; |
+ stubNullCurrentBrowserState(browserViewInformation); |
+ [[[browser_view_information_ stub] andReturn:nil] currentBVC]; |
+ |
+ swizzleMetricsMediatorDisableReporting(); |
+ |
+ [app_state_ applicationDidEnterBackground:application |
+ memoryHelper:memoryHelper |
+ tabSwitcherIsActive:YES]; |
+ |
+ metrics_mediator_called_ = NO; |
+ } |
+ |
+ void stubNullCurrentBrowserState(id browserViewInformation) { |
+ [[[browserViewInformation stub] andDo:^(NSInvocation* invocation) { |
+ ios::ChromeBrowserState* browserState = nullptr; |
+ [invocation setReturnValue:&browserState]; |
+ }] currentBrowserState]; |
+ } |
+ |
+ void stubNullBrowserState(id BVC) { |
+ [[[BVC stub] andDo:^(NSInvocation* invocation) { |
+ ios::ChromeBrowserState* browserState = nullptr; |
+ [invocation setReturnValue:&browserState]; |
+ }] browserState]; |
+ } |
+ |
+ void swizzleSafeModeShouldStart(BOOL shouldStart) { |
+ safe_mode_swizzle_block_.reset([^BOOL(id self) { |
+ return shouldStart; |
+ } copy]); |
+ safe_mode_swizzler_.reset(new ScopedBlockSwizzler( |
+ [SafeModeCoordinator class], @selector(shouldStart), |
+ safe_mode_swizzle_block_)); |
+ } |
+ |
+ void swizzleMetricsMediatorDisableReporting() { |
+ metrics_mediator_called_ = NO; |
+ |
+ metrics_mediator_swizzle_block_.reset([^(id self) { |
+ metrics_mediator_called_ = YES; |
+ } copy]); |
+ |
+ metrics_mediator_swizzler_.reset(new ScopedBlockSwizzler( |
+ [MetricsMediator class], @selector(disableReporting), |
+ metrics_mediator_swizzle_block_)); |
+ } |
+ |
+ void swizzleHandleStartupParameters( |
+ id<TabOpening> expectedTabOpener, |
+ id<BrowserViewInformation> expectedBrowserViewInformation) { |
+ handle_startup_swizzle_block_.reset( |
+ ^(id self, id<TabOpening> tabOpener, |
+ id<StartupInformation> startupInformation, |
+ id<BrowserViewInformation> browserViewInformation) { |
+ ASSERT_EQ(startup_information_mock_, startupInformation); |
+ ASSERT_EQ(expectedTabOpener, tabOpener); |
+ ASSERT_EQ(expectedBrowserViewInformation, browserViewInformation); |
+ }, |
+ base::scoped_policy::RETAIN); |
+ |
+ handle_startup_swizzler_.reset(new ScopedBlockSwizzler( |
+ [UserActivityHandler class], |
+ @selector(handleStartupParametersWithTabOpener: |
+ startupInformation: |
+ browserViewInformation:), |
+ handle_startup_swizzle_block_)); |
+ } |
+ |
+ AppState* getAppStateWithOpenNTPAndIncognitoBlock(BOOL shouldOpenNTP, |
+ UIWindow* window) { |
+ AppState* appState = getAppStateWithRealWindow(window); |
+ |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id metricsMediator = [OCMockObject mockForClass:[MetricsMediator class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ |
+ [[[browser_view_information_ stub] andReturn:tabModel] currentTabModel]; |
+ [[metricsMediator stub] updateMetricsStateBasedOnPrefsUserTriggered:NO]; |
+ [[memoryHelper stub] resetForegroundMemoryWarningCount]; |
+ [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount]; |
+ [[[tabOpener stub] andReturnValue:@(shouldOpenNTP)] |
+ shouldOpenNTPTabOnActivationOfTabModel:tabModel]; |
+ |
+ stubNullCurrentBrowserState(browser_view_information_); |
+ |
+ void (^swizzleBlock)() = ^() { |
+ }; |
+ |
+ ScopedBlockSwizzler swizzler( |
+ [MetricsMediator class], |
+ @selector(logLaunchMetricsWithStartupInformation: |
+ browserViewInformation:), |
+ swizzleBlock); |
+ |
+ [appState applicationWillEnterForeground:application |
+ metricsMediator:metricsMediator |
+ memoryHelper:memoryHelper |
+ tabOpener:tabOpener |
+ appNavigation:appNavigation]; |
+ |
+ initializeIncognitoBlocker(window); |
+ |
+ return appState; |
+ } |
+ |
+ AppState* getAppStateWithMock() { |
+ if (!app_state_) { |
+ app_state_.reset([[AppState alloc] |
+ initWithBrowserLauncher:browser_launcher_mock_ |
+ startupInformation:startup_information_mock_ |
+ applicationDelegate:main_application_delegate_]); |
+ [app_state_ setWindow:window_]; |
+ } |
+ return app_state_; |
+ } |
+ |
+ AppState* getAppStateWithRealWindow(UIWindow* window) { |
+ if (!app_state_) { |
+ app_state_.reset([[AppState alloc] |
+ initWithBrowserLauncher:browser_launcher_mock_ |
+ startupInformation:startup_information_mock_ |
+ applicationDelegate:main_application_delegate_]); |
+ [app_state_ setWindow:window]; |
+ } |
+ return app_state_; |
+ } |
+ |
+ id getBrowserLauncherMock() { return browser_launcher_mock_; } |
+ id getStartupInformationMock() { return startup_information_mock_; } |
+ id getApplicationDelegateMock() { return main_application_delegate_; } |
+ id getWindowMock() { return window_; } |
+ id getBrowserViewInformationMock() { return browser_view_information_; } |
+ |
+ BOOL metricsMediatorHasBeenCalled() { return metrics_mediator_called_; } |
+ |
+ private: |
+ base::scoped_nsobject<AppState> app_state_; |
+ id browser_launcher_mock_; |
+ id startup_information_mock_; |
+ id main_application_delegate_; |
+ id window_; |
+ id browser_view_information_; |
+ base::mac::ScopedBlock<DecisionBlock> safe_mode_swizzle_block_; |
+ base::mac::ScopedBlock<HandleStartupParam> handle_startup_swizzle_block_; |
+ base::mac::ScopedBlock<ProceduralBlock> metrics_mediator_swizzle_block_; |
+ std::unique_ptr<ScopedBlockSwizzler> safe_mode_swizzler_; |
+ std::unique_ptr<ScopedBlockSwizzler> handle_startup_swizzler_; |
+ std::unique_ptr<ScopedBlockSwizzler> metrics_mediator_swizzler_; |
+ __block BOOL metrics_mediator_called_; |
+}; |
+ |
+// TODO(crbug.com/585700): remove this. |
+// Creates a requestTracker, needed for teardown. |
+void createTracker(BOOL* created, base::Lock* lock) { |
+ web::RequestTrackerImpl::GetTrackerForRequestGroupID(@"test"); |
+ base::AutoLock scoped_lock(*lock); |
+ *created = YES; |
+} |
+ |
+// Used to have a thread handling the closing of the IO threads. |
+class AppStateWithThreadTest : public PlatformTest { |
+ protected: |
+ AppStateWithThreadTest() |
+ : thread_bundle_(web::TestWebThreadBundle::REAL_IO_THREAD) { |
+ BOOL created = NO; |
+ base::Lock* lock = new base::Lock; |
+ |
+ web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, |
+ base::Bind(&createTracker, &created, lock)); |
+ |
+ CFTimeInterval start = CACurrentMediaTime(); |
+ |
+ // Poll for at most 1s, waiting for the Tracker creation. |
+ while (1) { |
+ base::AutoLock scoped_lock(*lock); |
+ if (created) |
+ return; |
+ if (CACurrentMediaTime() - start > 1.0) { |
+ trackerCreationFailed(); |
+ return; |
+ } |
+ // Ensure that other threads have a chance to run even on a single-core |
+ // devices. |
+ pthread_yield_np(); |
+ } |
+ } |
+ |
+ void trackerCreationFailed() { |
+ FAIL() << "Tracker creation took too much time."; |
+ } |
+ |
+ private: |
+ web::TestWebThreadBundle thread_bundle_; |
+}; |
+ |
+#pragma mark - Tests. |
+ |
+// Tests -isInSafeMode returns true if there is a SafeModeController. |
+TEST_F(AppStateTest, isInSafeModeTest) { |
+ // Setup. |
+ id safeModeContollerMock = |
+ [OCMockObject mockForClass:[SafeModeCoordinator class]]; |
+ |
+ AppState* appState = getAppStateWithMock(); |
+ |
+ appState.safeModeCoordinator = nil; |
+ ASSERT_FALSE([appState isInSafeMode]); |
+ [appState setSafeModeCoordinator:safeModeContollerMock]; |
+ |
+ // Action. |
+ BOOL result = [appState isInSafeMode]; |
+ |
+ // Test. |
+ EXPECT_TRUE(result); |
+} |
+ |
+// Tests that if the application is in background |
+// -requiresHandlingAfterLaunchWithOptions saves the launchOptions and returns |
+// YES (to handle the launch options later). |
+TEST_F(AppStateTest, requiresHandlingAfterLaunchWithOptionsBackground) { |
+ // Setup. |
+ NSString* sourceApplication = @"com.apple.mobilesafari"; |
+ NSDictionary* launchOptions = |
+ @{UIApplicationLaunchOptionsSourceApplicationKey : sourceApplication}; |
+ |
+ AppState* appState = getAppStateWithMock(); |
+ |
+ id browserLauncherMock = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stageBasic = INITIALIZATION_STAGE_BASIC; |
+ [[browserLauncherMock expect] startUpBrowserToStage:stageBasic]; |
+ [[browserLauncherMock expect] setLaunchOptions:launchOptions]; |
+ |
+ // Action. |
+ BOOL result = [appState requiresHandlingAfterLaunchWithOptions:launchOptions |
+ stateBackground:YES]; |
+ |
+ // Test. |
+ EXPECT_TRUE(result); |
+ EXPECT_OCMOCK_VERIFY(browserLauncherMock); |
+} |
+ |
+// Tests that if the application is active and Safe Mode should be activated |
+// -requiresHandlingAfterLaunchWithOptions save the launch options and activate |
+// the Safe Mode. |
+TEST_F(AppStateTest, requiresHandlingAfterLaunchWithOptionsForegroundSafeMode) { |
+ // Setup. |
+ NSString* sourceApplication = @"com.apple.mobilesafari"; |
+ NSDictionary* launchOptions = |
+ @{UIApplicationLaunchOptionsSourceApplicationKey : sourceApplication}; |
+ |
+ id windowMock = getWindowMock(); |
+ [[[windowMock stub] andReturn:nil] rootViewController]; |
+ [[windowMock expect] setRootViewController:[OCMArg any]]; |
+ [[windowMock expect] makeKeyAndVisible]; |
+ |
+ AppState* appState = getAppStateWithMock(); |
+ |
+ id browserLauncherMock = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stageBasic = INITIALIZATION_STAGE_BASIC; |
+ [[browserLauncherMock expect] startUpBrowserToStage:stageBasic]; |
+ [[browserLauncherMock expect] setLaunchOptions:launchOptions]; |
+ |
+ swizzleSafeModeShouldStart(YES); |
+ |
+ ASSERT_FALSE([appState isInSafeMode]); |
+ |
+ // Action. |
+ BOOL result = [appState requiresHandlingAfterLaunchWithOptions:launchOptions |
+ stateBackground:NO]; |
+ |
+ // Test. |
+ EXPECT_TRUE(result); |
+ EXPECT_TRUE([appState isInSafeMode]); |
+ EXPECT_OCMOCK_VERIFY(browserLauncherMock); |
+ EXPECT_OCMOCK_VERIFY(windowMock); |
+} |
+ |
+// Tests that if the application is active |
+// -requiresHandlingAfterLaunchWithOptions saves the launchOptions and start the |
+// application in foreground. |
+TEST_F(AppStateTest, requiresHandlingAfterLaunchWithOptionsForeground) { |
+ // Setup. |
+ NSString* sourceApplication = @"com.apple.mobilesafari"; |
+ NSDictionary* launchOptions = |
+ @{UIApplicationLaunchOptionsSourceApplicationKey : sourceApplication}; |
+ |
+ [[[getStartupInformationMock() stub] andReturnValue:@YES] isColdStart]; |
+ |
+ [[[getWindowMock() stub] andReturn:nil] rootViewController]; |
+ |
+ AppState* appState = getAppStateWithMock(); |
+ |
+ id browserLauncherMock = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stageBasic = INITIALIZATION_STAGE_BASIC; |
+ [[browserLauncherMock expect] startUpBrowserToStage:stageBasic]; |
+ BrowserInitializationStageType stageForeground = |
+ INITIALIZATION_STAGE_FOREGROUND; |
+ [[browserLauncherMock expect] startUpBrowserToStage:stageForeground]; |
+ [[browserLauncherMock expect] setLaunchOptions:launchOptions]; |
+ |
+ swizzleSafeModeShouldStart(NO); |
+ |
+ // Action. |
+ BOOL result = [appState requiresHandlingAfterLaunchWithOptions:launchOptions |
+ stateBackground:NO]; |
+ |
+ // Test. |
+ EXPECT_TRUE(result); |
+ EXPECT_OCMOCK_VERIFY(browserLauncherMock); |
+} |
+ |
+// Test that -willResignActive set cold start to NO and launch record. |
+TEST(AppStateNoFixtureTest, willResignActive) { |
+ // Setup. |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ [[tabModel expect] recordSessionMetrics]; |
+ |
+ id browserViewInformation = |
+ [OCMockObject mockForProtocol:@protocol(BrowserViewInformation)]; |
+ |
+ [[[browserViewInformation stub] andReturn:tabModel] mainTabModel]; |
+ |
+ id browserLauncher = |
+ [OCMockObject mockForProtocol:@protocol(BrowserLauncher)]; |
+ [[[browserLauncher stub] andReturnValue:@(INITIALIZATION_STAGE_FOREGROUND)] |
+ browserInitializationStage]; |
+ [[[browserLauncher stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ id applicationDelegate = |
+ [OCMockObject mockForClass:[MainApplicationDelegate class]]; |
+ id window = [OCMockObject mockForClass:[UIWindow class]]; |
+ |
+ base::scoped_nsobject<FakeStartupInformation> startupInformation( |
+ [[FakeStartupInformation alloc] init]); |
+ [startupInformation setIsColdStart:YES]; |
+ |
+ base::scoped_nsobject<AppState> appState([[AppState alloc] |
+ initWithBrowserLauncher:browserLauncher |
+ startupInformation:startupInformation |
+ applicationDelegate:applicationDelegate]); |
+ [appState setWindow:window]; |
+ |
+ ASSERT_TRUE([startupInformation isColdStart]); |
+ |
+ // Action. |
+ [appState willResignActiveTabModel]; |
+ |
+ // Test. |
+ EXPECT_FALSE([startupInformation isColdStart]); |
+ EXPECT_OCMOCK_VERIFY(tabModel); |
+} |
+ |
+// Test that -applicationWillTerminate clears everything. |
+TEST_F(AppStateWithThreadTest, willTerminate) { |
+ // Setup. |
+ IOSChromeScopedTestingChromeBrowserProvider provider_( |
+ base::MakeUnique<FakeChromeBrowserProvider>()); |
+ |
+ id browserLauncher = |
+ [OCMockObject mockForProtocol:@protocol(BrowserLauncher)]; |
+ id applicationDelegate = |
+ [OCMockObject mockForClass:[MainApplicationDelegate class]]; |
+ id window = [OCMockObject mockForClass:[UIWindow class]]; |
+ id browserViewInformation = |
+ [OCMockObject mockForProtocol:@protocol(BrowserViewInformation)]; |
+ [[[browserLauncher stub] andReturnValue:@(INITIALIZATION_STAGE_FOREGROUND)] |
+ browserInitializationStage]; |
+ [[[browserLauncher stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ id settingsNavigationController = |
+ [OCMockObject mockForClass:[SettingsNavigationController class]]; |
+ |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ [[[appNavigation stub] andReturn:settingsNavigationController] |
+ settingsNavigationController]; |
+ [[appNavigation expect] closeSettingsAnimated:NO completion:nil]; |
+ |
+ [[browserViewInformation expect] cleanDeviceSharingManager]; |
+ [[browserViewInformation expect] haltAllTabs]; |
+ |
+ id startupInformation = |
+ [OCMockObject mockForProtocol:@protocol(StartupInformation)]; |
+ [[startupInformation expect] stopChromeMain]; |
+ |
+ base::scoped_nsobject<AppState> appState([[AppState alloc] |
+ initWithBrowserLauncher:browserLauncher |
+ startupInformation:startupInformation |
+ applicationDelegate:applicationDelegate]); |
+ [appState setWindow:window]; |
+ |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ [[application expect] setMinimumBackgroundFetchInterval: |
+ UIApplicationBackgroundFetchIntervalNever]; |
+ |
+ // Action. |
+ [appState applicationWillTerminate:application |
+ applicationNavigation:appNavigation]; |
+ |
+ // Test. |
+ EXPECT_OCMOCK_VERIFY(startupInformation); |
+ EXPECT_OCMOCK_VERIFY(appNavigation); |
+ EXPECT_OCMOCK_VERIFY(browserViewInformation); |
+ EXPECT_OCMOCK_VERIFY(application); |
+ FakeAppDistributionProvider* provider = |
+ static_cast<FakeAppDistributionProvider*>( |
+ ios::GetChromeBrowserProvider()->GetAppDistributionProvider()); |
+ EXPECT_TRUE(provider->cancel_called()); |
+} |
+ |
+// Test that -resumeSessionWithTabOpener removes incognito blocker, |
+// restart metrics and launchs from StartupParameters if they exist. |
+TEST_F(AppStateTest, resumeSessionWithStartupParameters) { |
+ // Setup. |
+ |
+ // BrowserLauncher. |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ [[[getBrowserLauncherMock() stub] |
+ andReturnValue:@(INITIALIZATION_STAGE_FOREGROUND)] |
+ browserInitializationStage]; |
+ [[[getBrowserLauncherMock() stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ // StartupInformation. |
+ id appStartupParameters = |
+ [OCMockObject mockForClass:[AppStartupParameters class]]; |
+ [[[getStartupInformationMock() stub] andReturn:appStartupParameters] |
+ startupParameters]; |
+ [[[getStartupInformationMock() stub] andReturnValue:@NO] isColdStart]; |
+ |
+ // TabOpening. |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ // TabSwitcher. |
+ id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)]; |
+ |
+ // BrowserViewInformation. |
+ id mainTabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ [[mainTabModel expect] resetSessionMetrics]; |
+ [[[browserViewInformation stub] andReturn:mainTabModel] mainTabModel]; |
+ |
+ // Swizzle Startup Parameters. |
+ swizzleHandleStartupParameters(tabOpener, browserViewInformation); |
+ |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(NO, window); |
+ |
+ ASSERT_EQ(NSUInteger(1), [window subviews].count); |
+ |
+ // Action. |
+ [appState resumeSessionWithTabOpener:tabOpener tabSwitcher:tabSwitcher]; |
+ |
+ // Test. |
+ EXPECT_EQ(NSUInteger(0), [window subviews].count); |
+ EXPECT_OCMOCK_VERIFY(mainTabModel); |
+} |
+ |
+// Test that -resumeSessionWithTabOpener removes incognito blocker, |
+// restart metrics and creates a new tab from tab switcher if shouldOpenNTP is |
+// YES. |
+TEST_F(AppStateTest, resumeSessionShouldOpenNTPTabSwitcher) { |
+ // Setup. |
+ // BrowserLauncher. |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ [[[getBrowserLauncherMock() stub] |
+ andReturnValue:@(INITIALIZATION_STAGE_FOREGROUND)] |
+ browserInitializationStage]; |
+ [[[getBrowserLauncherMock() stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ // StartupInformation. |
+ [[[getStartupInformationMock() stub] andReturn:nil] startupParameters]; |
+ [[[getStartupInformationMock() stub] andReturnValue:@NO] isColdStart]; |
+ |
+ // TabOpening. |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ |
+ // BrowserViewInformation. |
+ id mainTabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ [[mainTabModel expect] resetSessionMetrics]; |
+ [[[browserViewInformation stub] andReturn:mainTabModel] mainTabModel]; |
+ |
+ // TabSwitcher. |
+ id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)]; |
+ [[[tabSwitcher stub] andReturnValue:@YES] openNewTabFromTabSwitcher]; |
+ |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(YES, window); |
+ |
+ ASSERT_EQ(NSUInteger(1), [window subviews].count); |
+ |
+ // Action. |
+ [appState resumeSessionWithTabOpener:tabOpener tabSwitcher:tabSwitcher]; |
+ |
+ // Test. |
+ EXPECT_EQ(NSUInteger(0), [window subviews].count); |
+ EXPECT_OCMOCK_VERIFY(mainTabModel); |
+} |
+ |
+// Test that -resumeSessionWithTabOpener removes incognito blocker, |
+// restart metrics and creates a new tab if shouldOpenNTP is YES. |
+TEST_F(AppStateTest, resumeSessionShouldOpenNTPNoTabSwitcher) { |
+ // Setup. |
+ // BrowserLauncher. |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ [[[getBrowserLauncherMock() stub] |
+ andReturnValue:@(INITIALIZATION_STAGE_FOREGROUND)] |
+ browserInitializationStage]; |
+ [[[getBrowserLauncherMock() stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ // StartupInformation. |
+ [[[getStartupInformationMock() stub] andReturn:nil] startupParameters]; |
+ [[[getStartupInformationMock() stub] andReturnValue:@NO] isColdStart]; |
+ |
+ // TabOpening. |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ |
+ // BrowserViewInformation. |
+ id mainTabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ [[mainTabModel expect] resetSessionMetrics]; |
+ |
+ id currentBVC = [OCMockObject mockForClass:[BrowserViewController class]]; |
+ [[currentBVC expect] newTab:nil]; |
+ stubNullBrowserState(currentBVC); |
+ |
+ [[[browserViewInformation stub] andReturn:mainTabModel] mainTabModel]; |
+ [[[browserViewInformation stub] andReturn:currentBVC] currentBVC]; |
+ |
+ // TabSwitcher. |
+ id tabSwitcher = [OCMockObject mockForProtocol:@protocol(TabSwitching)]; |
+ [[[tabSwitcher stub] andReturnValue:@NO] openNewTabFromTabSwitcher]; |
+ |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ AppState* appState = getAppStateWithOpenNTPAndIncognitoBlock(YES, window); |
+ |
+ // incognitoBlocker. |
+ ASSERT_EQ(NSUInteger(1), [window subviews].count); |
+ |
+ // Action. |
+ [appState resumeSessionWithTabOpener:tabOpener tabSwitcher:tabSwitcher]; |
+ |
+ // Test. |
+ EXPECT_EQ(NSUInteger(0), [window subviews].count); |
+ EXPECT_OCMOCK_VERIFY(mainTabModel); |
+ EXPECT_OCMOCK_VERIFY(currentBVC); |
+} |
+ |
+// Tests that -applicationWillEnterForeground resets components as needed. |
+TEST_F(AppStateTest, applicationWillEnterForeground) { |
+ // Setup. |
+ IOSChromeScopedTestingChromeBrowserProvider provider_( |
+ base::MakeUnique<FakeChromeBrowserProvider>()); |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id metricsMediator = [OCMockObject mockForClass:[MetricsMediator class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND; |
+ [[[getBrowserLauncherMock() stub] andReturnValue:@(stage)] |
+ browserInitializationStage]; |
+ [[[getBrowserLauncherMock() stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ [[[browserViewInformation stub] andReturn:tabModel] currentTabModel]; |
+ [[metricsMediator expect] updateMetricsStateBasedOnPrefsUserTriggered:NO]; |
+ [[memoryHelper expect] resetForegroundMemoryWarningCount]; |
+ [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount]; |
+ [[[tabOpener stub] andReturnValue:@YES] |
+ shouldOpenNTPTabOnActivationOfTabModel:tabModel]; |
+ |
+ stubNullCurrentBrowserState(browserViewInformation); |
+ |
+ void (^swizzleBlock)() = ^() { |
+ }; |
+ |
+ ScopedBlockSwizzler swizzler( |
+ [MetricsMediator class], |
+ @selector(logLaunchMetricsWithStartupInformation:browserViewInformation:), |
+ swizzleBlock); |
+ |
+ // Actions. |
+ [getAppStateWithMock() applicationWillEnterForeground:application |
+ metricsMediator:metricsMediator |
+ memoryHelper:memoryHelper |
+ tabOpener:tabOpener |
+ appNavigation:appNavigation]; |
+ |
+ // Tests. |
+ EXPECT_OCMOCK_VERIFY(metricsMediator); |
+ EXPECT_OCMOCK_VERIFY(memoryHelper); |
+ FakeUserFeedbackProvider* user_feedback_provider = |
+ static_cast<FakeUserFeedbackProvider*>( |
+ ios::GetChromeBrowserProvider()->GetUserFeedbackProvider()); |
+ EXPECT_TRUE(user_feedback_provider->synchronize_called()); |
+} |
+ |
+// Tests that -applicationWillEnterForeground starts the browser if the |
+// application is in background. |
+TEST_F(AppStateTest, applicationWillEnterForegroundFromBackground) { |
+ // Setup. |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id metricsMediator = [OCMockObject mockForClass:[MetricsMediator class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_BACKGROUND; |
+ [[[getBrowserLauncherMock() stub] andReturnValue:@(stage)] |
+ browserInitializationStage]; |
+ |
+ [[[getWindowMock() stub] andReturn:nil] rootViewController]; |
+ swizzleSafeModeShouldStart(NO); |
+ |
+ [[[getStartupInformationMock() stub] andReturnValue:@YES] isColdStart]; |
+ [[getBrowserLauncherMock() expect] |
+ startUpBrowserToStage:INITIALIZATION_STAGE_FOREGROUND]; |
+ |
+ // Actions. |
+ [getAppStateWithMock() applicationWillEnterForeground:application |
+ metricsMediator:metricsMediator |
+ memoryHelper:memoryHelper |
+ tabOpener:tabOpener |
+ appNavigation:appNavigation]; |
+ |
+ // Tests. |
+ EXPECT_OCMOCK_VERIFY(getBrowserLauncherMock()); |
+} |
+ |
+// Tests that -applicationWillEnterForeground starts the safe mode if the |
+// application is in background. |
+TEST_F(AppStateTest, |
+ applicationWillEnterForegroundFromBackgroundShouldStartSafeMode) { |
+ // Setup. |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id metricsMediator = [OCMockObject mockForClass:[MetricsMediator class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ |
+ id window = getWindowMock(); |
+ |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_BACKGROUND; |
+ [[[getBrowserLauncherMock() stub] andReturnValue:@(stage)] |
+ browserInitializationStage]; |
+ |
+ [[[window stub] andReturn:nil] rootViewController]; |
+ [[window expect] makeKeyAndVisible]; |
+ [[window stub] setRootViewController:[OCMArg any]]; |
+ swizzleSafeModeShouldStart(YES); |
+ |
+ // Actions. |
+ [getAppStateWithMock() applicationWillEnterForeground:application |
+ metricsMediator:metricsMediator |
+ memoryHelper:memoryHelper |
+ tabOpener:tabOpener |
+ appNavigation:appNavigation]; |
+ |
+ // Tests. |
+ EXPECT_OCMOCK_VERIFY(window); |
+ EXPECT_TRUE([getAppStateWithMock() isInSafeMode]); |
+} |
+ |
+// Tests that -applicationWillEnterForeground returns directly if the |
+// application is in safe mode and in foreground |
+TEST_F(AppStateTest, applicationWillEnterForegroundFromForegroundSafeMode) { |
+ // Setup. |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id metricsMediator = [OCMockObject mockForClass:[MetricsMediator class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id tabOpener = [OCMockObject mockForProtocol:@protocol(TabOpening)]; |
+ id appNavigation = [OCMockObject mockForProtocol:@protocol(AppNavigation)]; |
+ |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND; |
+ [[[getBrowserLauncherMock() stub] andReturnValue:@(stage)] |
+ browserInitializationStage]; |
+ |
+ AppState* appState = getAppStateWithMock(); |
+ |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ appState.safeModeCoordinator = |
+ [[[SafeModeCoordinator alloc] initWithWindow:window] autorelease]; |
+ |
+ ASSERT_TRUE([appState isInSafeMode]); |
+ |
+ // Actions. |
+ [appState applicationWillEnterForeground:application |
+ metricsMediator:metricsMediator |
+ memoryHelper:memoryHelper |
+ tabOpener:tabOpener |
+ appNavigation:appNavigation]; |
+} |
+ |
+// Tests that -applicationDidEnterBackground creates an incognito blocker. |
+TEST_F(AppStateTest, applicationDidEnterBackgroundIncognito) { |
+ // Setup. |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ id application = [OCMockObject niceMockForClass:[UIApplication class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ id startupInformation = getStartupInformationMock(); |
+ id browserLauncher = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND; |
+ |
+ AppState* appState = getAppStateWithRealWindow(window); |
+ |
+ [[startupInformation expect] expireFirstUserActionRecorder]; |
+ [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount]; |
+ [[[tabModel stub] andReturnValue:@NO] isEmpty]; |
+ [[[browserViewInformation stub] andReturn:tabModel] otrTabModel]; |
+ [[[browserViewInformation stub] andReturn:nil] currentBVC]; |
+ stubNullCurrentBrowserState(browserViewInformation); |
+ [[[browserLauncher stub] andReturnValue:@(stage)] browserInitializationStage]; |
+ [[[browserLauncher stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ swizzleMetricsMediatorDisableReporting(); |
+ |
+ ASSERT_EQ(NSUInteger(0), [window subviews].count); |
+ |
+ // Action. |
+ [appState applicationDidEnterBackground:application |
+ memoryHelper:memoryHelper |
+ tabSwitcherIsActive:YES]; |
+ |
+ // Tests. |
+ EXPECT_OCMOCK_VERIFY(startupInformation); |
+ EXPECT_TRUE(metricsMediatorHasBeenCalled()); |
+ EXPECT_EQ(NSUInteger(1), [window subviews].count); |
+} |
+ |
+// Tests that -applicationDidEnterBackground do nothing if the application has |
+// never been in a Foreground stage. |
+TEST_F(AppStateTest, applicationDidEnterBackgroundStageBackground) { |
+ // Setup. |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ id application = [OCMockObject mockForClass:[UIApplication class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id browserLauncher = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_BACKGROUND; |
+ |
+ [[[browserLauncher stub] andReturnValue:@(stage)] browserInitializationStage]; |
+ |
+ ASSERT_EQ(NSUInteger(0), [window subviews].count); |
+ |
+ // Action. |
+ [getAppStateWithRealWindow(window) applicationDidEnterBackground:application |
+ memoryHelper:memoryHelper |
+ tabSwitcherIsActive:YES]; |
+ |
+ // Tests. |
+ EXPECT_EQ(NSUInteger(0), [window subviews].count); |
+} |
+ |
+// Tests that -applicationDidEnterBackground does not create an incognito |
+// blocker if there is no incognito tab. |
+TEST_F(AppStateTest, applicationDidEnterBackgroundNoIncognitoBlocker) { |
+ // Setup. |
+ UIWindow* window = [[[UIWindow alloc] init] autorelease]; |
+ id application = [OCMockObject niceMockForClass:[UIApplication class]]; |
+ id memoryHelper = [OCMockObject mockForClass:[MemoryWarningHelper class]]; |
+ id browserViewInformation = getBrowserViewInformationMock(); |
+ id tabModel = [OCMockObject mockForClass:[TabModel class]]; |
+ id startupInformation = getStartupInformationMock(); |
+ id browserLauncher = getBrowserLauncherMock(); |
+ BrowserInitializationStageType stage = INITIALIZATION_STAGE_FOREGROUND; |
+ |
+ AppState* appState = getAppStateWithRealWindow(window); |
+ |
+ [[startupInformation expect] expireFirstUserActionRecorder]; |
+ [[[memoryHelper stub] andReturnValue:@0] foregroundMemoryWarningCount]; |
+ [[[tabModel stub] andReturnValue:@YES] isEmpty]; |
+ [[[browserViewInformation stub] andReturn:tabModel] otrTabModel]; |
+ [[[browserViewInformation stub] andReturn:nil] currentBVC]; |
+ stubNullCurrentBrowserState(browserViewInformation); |
+ [[[browserLauncher stub] andReturnValue:@(stage)] browserInitializationStage]; |
+ [[[browserLauncher stub] andReturn:browserViewInformation] |
+ browserViewInformation]; |
+ |
+ swizzleMetricsMediatorDisableReporting(); |
+ |
+ ASSERT_EQ(NSUInteger(0), [window subviews].count); |
+ |
+ // Action. |
+ [appState applicationDidEnterBackground:application |
+ memoryHelper:memoryHelper |
+ tabSwitcherIsActive:YES]; |
+ |
+ // Tests. |
+ EXPECT_OCMOCK_VERIFY(startupInformation); |
+ EXPECT_TRUE(metricsMediatorHasBeenCalled()); |
+ EXPECT_EQ(NSUInteger(0), [window subviews].count); |
+} |