blob: 2e28c47372d2e2a155cbf77732f4749556111af8 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/browser_list.h"
#include <memory>
#include <set>
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/interaction/browser_elements.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test.h"
#include "ui/base/mojom/window_show_state.mojom.h"
using BrowserListBrowserTest = InProcessBrowserTest;
// This tests that minimized windows get added to the active list, at the front
// the list.
IN_PROC_BROWSER_TEST_F(BrowserListBrowserTest, TestMinimized) {
const BrowserList* browser_list = BrowserList::GetInstance();
EXPECT_EQ(1U, browser_list->size());
EXPECT_EQ(browser(), browser_list->GetLastActive());
// Create a minimized browser window. It should be prepended to the active
// list, so browser() should still be at the end of the list.
Browser::CreateParams params(GetProfile(), true);
params.initial_show_state = ui::mojom::WindowShowState::kMinimized;
Browser::Create(params);
EXPECT_EQ(2U, browser_list->size());
EXPECT_EQ(browser(), browser_list->GetLastActive());
}
// This tests that inactive windows do not get added to the active list.
IN_PROC_BROWSER_TEST_F(BrowserListBrowserTest, TestInactive) {
const BrowserList* browser_list = BrowserList::GetInstance();
EXPECT_EQ(1U, browser_list->size());
EXPECT_EQ(browser(), browser_list->GetLastActive());
// Create an inactive browser window. It should be prepended to
// |BrowserList::browsers_ordered_by_activation_| so the default browser
// should still be the last active.
Browser::CreateParams params(GetProfile(), true);
params.initial_show_state = ui::mojom::WindowShowState::kInactive;
Browser::Create(params);
EXPECT_EQ(2U, browser_list->size());
EXPECT_EQ(browser(), browser_list->GetLastActive());
}
// This tests if the browser list is returning the correct browser reference
// for the context provided as input.
IN_PROC_BROWSER_TEST_F(BrowserListBrowserTest,
TestFindBrowserWithUiElementContext) {
const BrowserList* browser_list = BrowserList::GetInstance();
EXPECT_EQ(1U, browser_list->size());
Browser* result = chrome::FindBrowserWithUiElementContext(
BrowserElements::From(browser_list->get(0))->GetContext());
EXPECT_EQ(browser_list->get(0), result);
Browser* browser2 =
Browser::Create(Browser::CreateParams(GetProfile(), true));
ASSERT_EQ(2U, browser_list->size());
result = chrome::FindBrowserWithUiElementContext(
BrowserElements::From(browser2)->GetContext());
EXPECT_EQ(browser2, result);
result = chrome::FindBrowserWithUiElementContext(ui::ElementContext(100));
EXPECT_EQ(nullptr, result);
}
// Class that tries to observe all pre-existing and newly created browsers.
// Ensures that for each browser there is a single OnBrowserAdded/Removed call
// or it already existed in BrowserList.
class BrowserObserverChild : public BrowserListObserver, TabStripModelObserver {
public:
explicit BrowserObserverChild(Browser* created_for_browser)
: created_for_browser_(created_for_browser) {
BrowserList* browser_list = BrowserList::GetInstance();
for (Browser* browser : *browser_list) {
EXPECT_FALSE(base::Contains(observed_browsers_, browser));
observed_browsers_.insert(browser);
browser->tab_strip_model()->AddObserver(this);
}
EXPECT_TRUE(base::Contains(observed_browsers_, created_for_browser_));
browser_list->AddObserver(this);
}
~BrowserObserverChild() override {
BrowserList* browser_list = BrowserList::GetInstance();
for (Browser* browser : *browser_list) {
EXPECT_TRUE(base::Contains(observed_browsers_, browser));
observed_browsers_.erase(browser);
browser->tab_strip_model()->RemoveObserver(this);
}
browser_list->RemoveObserver(this);
}
void OnBrowserAdded(Browser* browser) override {
EXPECT_NE(browser, created_for_browser_);
EXPECT_FALSE(base::Contains(observed_browsers_, browser));
observed_browsers_.insert(browser);
browser->tab_strip_model()->AddObserver(this);
}
void OnBrowserRemoved(Browser* browser) override {
browser->tab_strip_model()->RemoveObserver(this);
EXPECT_TRUE(base::Contains(observed_browsers_, browser));
observed_browsers_.erase(browser);
}
private:
std::set<raw_ptr<Browser, SetExperimental>> observed_browsers_;
raw_ptr<Browser, DanglingUntriaged> created_for_browser_;
};
// Class that creates BrowserObserverChild when a Browser is created;
class BrowserObserverParent : public BrowserListObserver {
public:
BrowserObserverParent() { BrowserList::GetInstance()->AddObserver(this); }
void OnBrowserAdded(Browser* browser) override {
if (!child_observer_) {
child_observer_ = std::make_unique<BrowserObserverChild>(browser);
}
}
~BrowserObserverParent() override {
BrowserList::GetInstance()->RemoveObserver(this);
}
protected:
std::unique_ptr<BrowserObserverChild> child_observer_;
};
IN_PROC_BROWSER_TEST_F(BrowserListBrowserTest, ObserverAddedInFlight) {
BrowserObserverParent parent_observer;
const BrowserList* browser_list = BrowserList::GetInstance();
EXPECT_EQ(1U, browser_list->size());
// Adding second browser should not trigger double-observation.
Browser::Create(Browser::CreateParams(GetProfile(), true));
EXPECT_EQ(2U, browser_list->size());
// Create one more browser to trigger BrowserObserverChild::OnBrowserAdded.
Browser::Create(Browser::CreateParams(GetProfile(), true));
EXPECT_EQ(3U, browser_list->size());
}