blob: e55a0351fcc3f5e7a60ac86d61f5cd5c0345f356 [file] [log] [blame]
// Copyright 2017 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/browser/ui/overlays/overlay_scheduler.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/ui/coordinators/browser_coordinator_test.h"
#import "ios/chrome/browser/ui/coordinators/browser_coordinator_test_util.h"
#import "ios/chrome/browser/ui/overlays/browser_overlay_queue.h"
#import "ios/chrome/browser/ui/overlays/overlay_queue_manager.h"
#import "ios/chrome/browser/ui/overlays/overlay_scheduler_observer.h"
#import "ios/chrome/browser/ui/overlays/test/test_overlay_coordinator.h"
#import "ios/chrome/browser/ui/overlays/test/test_overlay_parent_coordinator.h"
#import "ios/chrome/browser/ui/overlays/test/test_overlay_queue.h"
#import "ios/chrome/browser/ui/overlays/test/test_overlay_queue_observer.h"
#import "ios/chrome/browser/ui/overlays/web_state_overlay_queue.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#import "ios/chrome/browser/web_state_list/web_state_opener.h"
#include "ios/web/public/test/fakes/test_web_state.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test observer for the scheduler.
class TestOverlaySchedulerObserver : public OverlaySchedulerObserver {
public:
TestOverlaySchedulerObserver(WebStateList* web_state_list)
: web_state_list_(web_state_list),
active_index_(WebStateList::kInvalidIndex) {}
void OverlaySchedulerWillShowOverlay(OverlayScheduler* scheduler,
web::WebState* web_state) override {
active_index_ = web_state_list_->GetIndexOfWebState(web_state);
if (web_state) {
EXPECT_NE(active_index_, WebStateList::kInvalidIndex);
web_state_list_->ActivateWebStateAt(active_index_);
web_state->WasShown();
}
}
int active_index() { return active_index_; }
private:
WebStateList* web_state_list_;
int active_index_;
};
// Test fixture for OverlayScheduler.
class OverlaySchedulerTest : public BrowserCoordinatorTest {
public:
OverlaySchedulerTest() {
observer_ =
std::make_unique<TestOverlaySchedulerObserver>(web_state_list());
OverlayQueueManager::CreateForBrowser(GetBrowser());
OverlayScheduler::CreateForBrowser(GetBrowser());
scheduler()->SetQueueManager(manager());
scheduler()->AddObserver(observer());
}
~OverlaySchedulerTest() override {
scheduler()->RemoveObserver(observer());
scheduler()->Disconnect();
}
WebStateList* web_state_list() { return &(GetBrowser()->web_state_list()); }
TestOverlaySchedulerObserver* observer() { return observer_.get(); }
OverlayQueueManager* manager() {
return OverlayQueueManager::FromBrowser(GetBrowser());
}
OverlayScheduler* scheduler() {
return OverlayScheduler::FromBrowser(GetBrowser());
}
private:
std::unique_ptr<TestOverlaySchedulerObserver> observer_;
TestOverlayQueue queue_;
DISALLOW_COPY_AND_ASSIGN(OverlaySchedulerTest);
};
// Tests that adding an overlay to the BrowserOverlayQueue triggers successful
// presentation.
TEST_F(OverlaySchedulerTest, AddBrowserOverlay) {
BrowserOverlayQueue* queue = BrowserOverlayQueue::FromBrowser(GetBrowser());
ASSERT_TRUE(queue);
TestOverlayParentCoordinator* parent =
[[TestOverlayParentCoordinator alloc] init];
TestOverlayCoordinator* overlay = [[TestOverlayCoordinator alloc] init];
queue->AddBrowserOverlay(overlay, parent);
EXPECT_EQ(parent.presentedOverlay, overlay);
WaitForBrowserCoordinatorActivation(overlay);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
[overlay stop];
WaitForBrowserCoordinatorDeactivation(overlay);
EXPECT_EQ(parent.presentedOverlay, nil);
EXPECT_FALSE(scheduler()->IsShowingOverlay());
}
// Tests that adding an overlay to a WebStateOverlayQueue triggers successful
// presentation.
TEST_F(OverlaySchedulerTest, AddWebStateOverlay) {
web_state_list()->InsertWebState(0, std::make_unique<web::TestWebState>(),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
web_state_list()->ActivateWebStateAt(0);
ASSERT_EQ(web_state_list()->count(), 1);
web::WebState* web_state = web_state_list()->GetWebStateAt(0);
WebStateOverlayQueue* queue = WebStateOverlayQueue::FromWebState(web_state);
ASSERT_TRUE(queue);
TestOverlayParentCoordinator* parent =
[[TestOverlayParentCoordinator alloc] init];
queue->SetWebStateParentCoordinator(parent);
TestOverlayCoordinator* overlay = [[TestOverlayCoordinator alloc] init];
queue->AddWebStateOverlay(overlay);
EXPECT_EQ(parent.presentedOverlay, overlay);
WaitForBrowserCoordinatorActivation(overlay);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
[overlay stop];
WaitForBrowserCoordinatorDeactivation(overlay);
EXPECT_EQ(parent.presentedOverlay, nil);
EXPECT_FALSE(scheduler()->IsShowingOverlay());
}
// Tests that attempting to present an overlay for an inactive WebState will
// correctly switch the active WebState before presenting.
TEST_F(OverlaySchedulerTest, SwitchWebStateForOverlay) {
// Add two WebStates and activate the second.
web_state_list()->InsertWebState(0, std::make_unique<web::TestWebState>(),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
ASSERT_EQ(web_state_list()->count(), 1);
web_state_list()->InsertWebState(1, std::make_unique<web::TestWebState>(),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
web_state_list()->ActivateWebStateAt(1);
// Add an overlay to the queue corresponding with the first WebState.
WebStateOverlayQueue* queue =
WebStateOverlayQueue::FromWebState(web_state_list()->GetWebStateAt(0));
ASSERT_TRUE(queue);
TestOverlayParentCoordinator* parent =
[[TestOverlayParentCoordinator alloc] init];
queue->SetWebStateParentCoordinator(parent);
TestOverlayCoordinator* overlay = [[TestOverlayCoordinator alloc] init];
queue->AddWebStateOverlay(overlay);
// Verify that the overlay is presented and the active WebState index is
// updated.
EXPECT_EQ(parent.presentedOverlay, overlay);
WaitForBrowserCoordinatorActivation(overlay);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
EXPECT_EQ(observer()->active_index(), 0);
[overlay stop];
WaitForBrowserCoordinatorDeactivation(overlay);
EXPECT_EQ(parent.presentedOverlay, nil);
EXPECT_FALSE(scheduler()->IsShowingOverlay());
}
// Tests that attempting to present an overlay for an inactive WebState will
// correctly switch the active WebState before presenting.
TEST_F(OverlaySchedulerTest, SwitchWebStateForQueuedOverlays) {
// Add two WebStates and activate the second.
web_state_list()->InsertWebState(0, std::make_unique<web::TestWebState>(),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
ASSERT_EQ(web_state_list()->count(), 1);
web_state_list()->InsertWebState(1, std::make_unique<web::TestWebState>(),
WebStateList::INSERT_FORCE_INDEX,
WebStateOpener());
web_state_list()->ActivateWebStateAt(1);
// Add an overlay to the queue corresponding with the first WebState.
WebStateOverlayQueue* queue_0 =
WebStateOverlayQueue::FromWebState(web_state_list()->GetWebStateAt(0));
ASSERT_TRUE(queue_0);
TestOverlayParentCoordinator* parent_0 =
[[TestOverlayParentCoordinator alloc] init];
queue_0->SetWebStateParentCoordinator(parent_0);
TestOverlayCoordinator* overlay_0 = [[TestOverlayCoordinator alloc] init];
queue_0->AddWebStateOverlay(overlay_0);
EXPECT_EQ(parent_0.presentedOverlay, overlay_0);
WaitForBrowserCoordinatorActivation(overlay_0);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
EXPECT_EQ(observer()->active_index(), 0);
// Add an overlay to the queue corresponding with the second WebState.
WebStateOverlayQueue* queue_1 =
WebStateOverlayQueue::FromWebState(web_state_list()->GetWebStateAt(1));
ASSERT_TRUE(queue_1);
TestOverlayParentCoordinator* parent_1 =
[[TestOverlayParentCoordinator alloc] init];
queue_1->SetWebStateParentCoordinator(parent_1);
TestOverlayCoordinator* overlay_1 = [[TestOverlayCoordinator alloc] init];
queue_1->AddWebStateOverlay(overlay_1);
// Stop the first overlay and verify that the second overlay has been
// presented and the active index updated.
[overlay_0 stop];
WaitForBrowserCoordinatorDeactivation(overlay_0);
EXPECT_EQ(parent_1.presentedOverlay, overlay_1);
WaitForBrowserCoordinatorActivation(overlay_1);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
EXPECT_EQ(observer()->active_index(), 1);
EXPECT_EQ(parent_0.presentedOverlay, nil);
[overlay_1 stop];
WaitForBrowserCoordinatorDeactivation(overlay_1);
EXPECT_EQ(parent_1.presentedOverlay, nil);
EXPECT_FALSE(scheduler()->IsShowingOverlay());
}
// Tests that pausing the scheduler prevents overlays from being started and
// that unpausing the scheduler successfully shows queued overlays.
TEST_F(OverlaySchedulerTest, PauseUnpause) {
scheduler()->SetPaused(true);
BrowserOverlayQueue* queue = BrowserOverlayQueue::FromBrowser(GetBrowser());
ASSERT_TRUE(queue);
TestOverlayParentCoordinator* parent =
[[TestOverlayParentCoordinator alloc] init];
TestOverlayCoordinator* overlay = [[TestOverlayCoordinator alloc] init];
queue->AddBrowserOverlay(overlay, parent);
EXPECT_FALSE(parent.presentedOverlay);
EXPECT_FALSE(scheduler()->IsShowingOverlay());
scheduler()->SetPaused(false);
EXPECT_EQ(parent.presentedOverlay, overlay);
WaitForBrowserCoordinatorActivation(overlay);
EXPECT_TRUE(scheduler()->IsShowingOverlay());
[overlay stop];
}