| 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);
|
| +}
|
|
|