blob: f15b4f24e0ef239f2e6963944a974e5a9be2dfc1 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/tabs/public/tab_collection.h"
#include <cstddef>
#include <memory>
#include <optional>
#include "chrome/browser/ui/tabs/features.h"
#include "chrome/browser/ui/tabs/tab_group_desktop.h"
#include "chrome/browser/ui/tabs/tab_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/test/base/testing_profile.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "components/tabs/public/pinned_tab_collection.h"
#include "components/tabs/public/split_tab_collection.h"
#include "components/tabs/public/split_tab_data.h"
#include "components/tabs/public/split_tab_id.h"
#include "components/tabs/public/split_tab_visual_data.h"
#include "components/tabs/public/tab_collection_storage.h"
#include "components/tabs/public/tab_group_tab_collection.h"
#include "components/tabs/public/tab_strip_collection.h"
#include "components/tabs/public/unpinned_tab_collection.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
// TODO(crbug.com/392950857): Refactor tests so that things that are shared
// between all tab collections are tested once at the TabCollectionBaseTest
// level. Then only things specific to individual collections will be tested in
// their respective test suites.
class TabCollectionBaseTest : public ::testing::Test {
public:
TabCollectionBaseTest() {
testing_profile_ = std::make_unique<TestingProfile>();
tab_strip_model_delegate_ = std::make_unique<TestTabStripModelDelegate>();
tab_strip_model_ = std::make_unique<TabStripModel>(
tab_strip_model_delegate_.get(), testing_profile_.get());
}
TabCollectionBaseTest(const TabCollectionBaseTest&) = delete;
TabCollectionBaseTest& operator=(const TabCollectionBaseTest&) = delete;
~TabCollectionBaseTest() override = default;
TabStripModel* GetTabStripModel() { return tab_strip_model_.get(); }
tabs::TabInterface* GetTabInCollectionStorage(
tabs::TabCollectionStorage* storage,
size_t index) {
const auto& child = storage->GetChildren().at(index);
const auto tab_ptr =
std::get_if<std::unique_ptr<tabs::TabInterface>>(&child);
return tab_ptr ? tab_ptr->get() : nullptr;
}
tabs::TabCollection* GetCollectionInCollectionStorage(
tabs::TabCollectionStorage* storage,
size_t index) {
const auto& child = storage->GetChildren().at(index);
const auto tab_collection_ptr =
std::get_if<std::unique_ptr<tabs::TabCollection>>(&child);
return tab_collection_ptr ? tab_collection_ptr->get() : nullptr;
}
std::unique_ptr<content::WebContents> MakeWebContents() {
return content::WebContents::Create(
content::WebContents::CreateParams(testing_profile_.get()));
}
// Adds a tab to the end of a collection.
tabs::TabInterface* AppendTab(tabs::TabCollection* collection,
std::unique_ptr<tabs::TabInterface> tab) {
return collection->AddTab(std::move(tab), collection->ChildCount());
}
// Returns true if the tab model is a direct child of the collection.
bool ContainsTab(tabs::TabCollection* collection,
const tabs::TabInterface* tab) {
return collection->GetIndexOfTab(tab).has_value();
}
// Returns true if the tab collection tree contains the tab.
bool ContainsTabRecursive(tabs::TabCollection* collection,
const tabs::TabInterface* tab) {
return collection->GetIndexOfTabRecursive(tab).has_value();
}
void AddTabsToPinnedContainer(tabs::PinnedTabCollection* collection,
TabStripModel* tab_strip_model,
int num) {
for (int i = 0; i < num; i++) {
std::unique_ptr<tabs::TabModel> tab_model =
std::make_unique<tabs::TabModel>(MakeWebContents(), tab_strip_model);
tabs::TabModel* tab_model_ptr = tab_model.get();
AppendTab(collection, std::move(tab_model));
EXPECT_EQ(collection->GetIndexOfTabRecursive(tab_model_ptr),
collection->ChildCount() - 1);
}
}
void AddTabsToGroupContainer(tabs::TabGroupTabCollection* collection,
TabStripModel* tab_strip_model,
int num) {
for (int i = 0; i < num; i++) {
std::unique_ptr<tabs::TabModel> tab_model =
std::make_unique<tabs::TabModel>(MakeWebContents(), tab_strip_model);
tabs::TabModel* tab_model_ptr = tab_model.get();
AppendTab(collection, std::move(tab_model));
EXPECT_EQ(collection->GetIndexOfTabRecursive(tab_model_ptr),
collection->ChildCount() - 1);
}
}
void AddTabsToUnpinnedContainer(tabs::UnpinnedTabCollection* collection,
TabStripModel* tab_strip_model,
int num) {
for (int i = 0; i < num; i++) {
std::unique_ptr<tabs::TabModel> tab_model =
std::make_unique<tabs::TabModel>(MakeWebContents(), tab_strip_model);
AppendTab(collection, std::move(tab_model));
}
}
Profile* profile() { return testing_profile_.get(); }
private:
content::BrowserTaskEnvironment task_environment_;
content::RenderViewHostTestEnabler test_enabler_;
std::unique_ptr<Profile> testing_profile_;
std::unique_ptr<TestTabStripModelDelegate> tab_strip_model_delegate_;
std::unique_ptr<TabStripModel> tab_strip_model_;
const tabs::TabModel::PreventFeatureInitializationForTesting prevent_;
};
TEST_F(TabCollectionBaseTest, GetDirectChildIndexOfCollectionContainingTab) {
std::unique_ptr<tabs::UnpinnedTabCollection> unpinned_collection =
std::make_unique<tabs::UnpinnedTabCollection>();
TabGroupDesktop::Factory factory(profile());
std::unique_ptr<tabs::TabGroupTabCollection> group_collection =
std::make_unique<tabs::TabGroupTabCollection>(
factory, tab_groups::TabGroupId::GenerateNew(),
tab_groups::TabGroupVisualData());
std::unique_ptr<tabs::SplitTabCollection> split_collection =
std::make_unique<tabs::SplitTabCollection>(
split_tabs::SplitTabId::GenerateNew(),
split_tabs::SplitTabVisualData());
tabs::TabGroupTabCollection* group_collection_ptr = group_collection.get();
tabs::SplitTabCollection* split_collection_ptr = split_collection.get();
std::vector<std::unique_ptr<tabs::TabModel>> tabs;
std::vector<tabs::TabModel*> tab_ptrs;
for (size_t i = 0; i < 4; i++) {
tabs.push_back(std::make_unique<tabs::TabModel>(MakeWebContents(),
GetTabStripModel()));
tab_ptrs.push_back(tabs[i].get());
}
AppendTab(unpinned_collection.get(), std::move(tabs[0]));
AppendTab(group_collection.get(), std::move(tabs[1]));
AppendTab(split_collection.get(), std::move(tabs[2]));
AppendTab(split_collection.get(), std::move(tabs[3]));
group_collection->AddCollection(std::move(split_collection), 1);
unpinned_collection->AddCollection(std::move(group_collection), 1);
// u{0, g{1, s{2, 3}}}
EXPECT_EQ(0,
split_collection_ptr->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[2]));
EXPECT_EQ(1,
split_collection_ptr->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[3]));
EXPECT_EQ(0,
group_collection_ptr->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[1]));
EXPECT_EQ(1,
group_collection_ptr->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[2]));
EXPECT_EQ(1,
group_collection_ptr->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[3]));
EXPECT_EQ(0,
unpinned_collection->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[0]));
EXPECT_EQ(1,
unpinned_collection->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[1]));
EXPECT_EQ(1,
unpinned_collection->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[2]));
EXPECT_EQ(1,
unpinned_collection->GetDirectChildIndexOfCollectionContainingTab(
tab_ptrs[3]));
}
class PinnedTabCollectionTest : public TabCollectionBaseTest {
public:
PinnedTabCollectionTest() {
pinned_collection_ = std::make_unique<tabs::PinnedTabCollection>();
}
PinnedTabCollectionTest(const PinnedTabCollectionTest&) = delete;
PinnedTabCollectionTest& operator=(const PinnedTabCollectionTest&) = delete;
~PinnedTabCollectionTest() override { pinned_collection_.reset(); }
tabs::PinnedTabCollection* pinned_collection() {
return pinned_collection_.get();
}
private:
std::unique_ptr<tabs::PinnedTabCollection> pinned_collection_;
};
TEST_F(PinnedTabCollectionTest, AddOperation) {
// Setup phase of keeping track of two tabs.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
auto tab_model_two =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabModel* tab_model_two_ptr = tab_model_two.get();
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
tabs::PinnedTabCollection* pinned_collection_instance = pinned_collection();
// Add a tab to the end of the pinned collection.
AppendTab(pinned_collection_instance, std::move(tab_model_one));
EXPECT_TRUE(tab_model_one_ptr->IsPinned());
EXPECT_EQ(tab_model_one_ptr->GetParentCollectionForTesting(),
pinned_collection_instance);
EXPECT_TRUE(
ContainsTabRecursive(pinned_collection_instance, tab_model_one_ptr));
// Add four more tabs to the collection.
AddTabsToPinnedContainer(pinned_collection_instance, GetTabStripModel(), 4);
EXPECT_EQ(pinned_collection_instance->ChildCount(), 5ul);
EXPECT_EQ(pinned_collection_instance->TabCountRecursive(), 5ul);
// Add the second tab to index 3.
pinned_collection_instance->AddTab(std::move(tab_model_two), 3ul);
EXPECT_EQ(
pinned_collection_instance->GetIndexOfTabRecursive(tab_model_two_ptr),
3ul);
}
TEST_F(PinnedTabCollectionTest, RemoveOperation) {
// Setup phase of keeping track of a tab.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::PinnedTabCollection* pinned_collection_instance = pinned_collection();
// Add four tabs to the collection.
AddTabsToPinnedContainer(pinned_collection_instance, GetTabStripModel(), 4);
// Add `tab_model_one` to index 3.
pinned_collection_instance->AddTab(std::move(tab_model_one), 3ul);
EXPECT_EQ(
pinned_collection_instance->GetIndexOfTabRecursive(tab_model_one_ptr),
3ul);
EXPECT_EQ(pinned_collection_instance->ChildCount(), 5ul);
EXPECT_TRUE(tab_model_one_ptr->IsPinned());
tab_model_one_ptr->set_will_be_detaching_for_testing(true);
// Remove `tab_model_one` from the collection.
auto removed_tab =
pinned_collection_instance->MaybeRemoveTab(tab_model_one_ptr);
EXPECT_EQ(tab_model_one_ptr, removed_tab.get());
EXPECT_FALSE(tab_model_one_ptr->IsPinned());
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
EXPECT_EQ(pinned_collection_instance->ChildCount(), 4ul);
}
TEST_F(PinnedTabCollectionTest, CollectionOperations) {
// Setup phase of keeping track of a tab.
tabs::PinnedTabCollection* pinned_collection_instance = pinned_collection();
// Add four tabs to the collection.
AddTabsToPinnedContainer(pinned_collection_instance, GetTabStripModel(), 4);
std::unique_ptr<tabs::TabCollection> collection =
std::make_unique<tabs::SplitTabCollection>(
split_tabs::SplitTabId::GenerateNew(),
split_tabs::SplitTabVisualData(split_tabs::SplitTabLayout::kVertical,
0.5));
tabs::TabCollection* collection_ptr = collection.get();
EXPECT_EQ(pinned_collection_instance->GetIndexOfCollection(collection_ptr),
std::nullopt);
EXPECT_FALSE(pinned_collection_instance->ContainsCollection(collection_ptr));
EXPECT_EQ(collection_ptr, pinned_collection_instance->AddCollection(
std::move(collection), 2));
EXPECT_TRUE(pinned_collection_instance->ContainsCollection(collection_ptr));
EXPECT_EQ(2,
pinned_collection_instance->GetIndexOfCollection(collection_ptr));
EXPECT_EQ(
collection_ptr,
pinned_collection_instance->MaybeRemoveCollection(collection_ptr).get());
EXPECT_FALSE(pinned_collection_instance->ContainsCollection(collection_ptr));
EXPECT_EQ(std::nullopt,
pinned_collection_instance->GetIndexOfCollection(collection_ptr));
}
class TabGroupTabCollectionTest : public TabCollectionBaseTest {
public:
TabGroupTabCollectionTest() {
TabGroupDesktop::Factory factory(profile());
grouped_collection_ = std::make_unique<tabs::TabGroupTabCollection>(
factory, tab_groups::TabGroupId::GenerateNew(),
tab_groups::TabGroupVisualData());
}
TabGroupTabCollectionTest(const TabGroupTabCollectionTest&) = delete;
TabGroupTabCollectionTest& operator=(const TabGroupTabCollectionTest&) =
delete;
~TabGroupTabCollectionTest() override { grouped_collection_.reset(); }
tabs::TabGroupTabCollection* GetCollection() {
return grouped_collection_.get();
}
private:
std::unique_ptr<tabs::TabGroupTabCollection> grouped_collection_;
const tabs::TabModel::PreventFeatureInitializationForTesting prevent_;
};
TEST_F(TabGroupTabCollectionTest, AddOperation) {
// Setup phase of keeping track of two tabs.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
auto tab_model_two =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabModel* tab_model_two_ptr = tab_model_two.get();
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
tabs::TabGroupTabCollection* grouped_collection = GetCollection();
// Add `tab_model_one` to the end of the collection.
AppendTab(grouped_collection, std::move(tab_model_one));
EXPECT_EQ(tab_model_one_ptr->group(), grouped_collection->GetTabGroupId());
EXPECT_EQ(tab_model_one_ptr->GetParentCollectionForTesting(),
grouped_collection);
EXPECT_TRUE(ContainsTabRecursive(grouped_collection, tab_model_one_ptr));
// Add four tabs to the collection.
AddTabsToGroupContainer(GetCollection(), GetTabStripModel(), 4);
EXPECT_EQ(grouped_collection->ChildCount(), 5ul);
EXPECT_EQ(grouped_collection->TabCountRecursive(), 5ul);
// Add `tab_model_two` to index 3.
grouped_collection->AddTab(std::move(tab_model_two), 3ul);
EXPECT_EQ(grouped_collection->GetIndexOfTabRecursive(tab_model_two_ptr), 3ul);
}
TEST_F(TabGroupTabCollectionTest, RemoveOperation) {
// Setup phase of keeping track of a tab.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabGroupTabCollection* grouped_collection = GetCollection();
// Add four tabs to the collection.
AddTabsToGroupContainer(GetCollection(), GetTabStripModel(), 4);
// Add `tab_model_one` to index 3.
grouped_collection->AddTab(std::move(tab_model_one), 3ul);
EXPECT_EQ(grouped_collection->GetIndexOfTabRecursive(tab_model_one_ptr), 3ul);
EXPECT_EQ(grouped_collection->ChildCount(), 5ul);
EXPECT_EQ(tab_model_one_ptr->group(), grouped_collection->GetTabGroupId());
tab_model_one_ptr->set_will_be_detaching_for_testing(true);
// Remove `tab_model_one` from the collection.
auto removed_tab = grouped_collection->MaybeRemoveTab(tab_model_one_ptr);
EXPECT_EQ(tab_model_one_ptr, removed_tab.get());
EXPECT_FALSE(tab_model_one_ptr->group().has_value());
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
EXPECT_EQ(grouped_collection->ChildCount(), 4ul);
}
class SplitTabCollectionTest : public TabCollectionBaseTest {
public:
SplitTabCollectionTest() {
split_collection_ = std::make_unique<tabs::SplitTabCollection>(
split_tabs::SplitTabId::GenerateNew(),
split_tabs::SplitTabVisualData(split_tabs::SplitTabLayout::kVertical,
0.5));
}
SplitTabCollectionTest(const SplitTabCollectionTest&) = delete;
SplitTabCollectionTest& operator=(const SplitTabCollectionTest&) = delete;
~SplitTabCollectionTest() override { split_collection_.reset(); }
tabs::SplitTabCollection* GetCollection() { return split_collection_.get(); }
void AddTabsToSplitContainer(tabs::SplitTabCollection* collection,
TabStripModel* tab_strip_model,
int num) {
for (int i = 0; i < num; i++) {
std::unique_ptr<tabs::TabModel> tab_model =
std::make_unique<tabs::TabModel>(MakeWebContents(), tab_strip_model);
tabs::TabModel* tab_model_ptr = tab_model.get();
AppendTab(collection, std::move(tab_model));
EXPECT_EQ(collection->GetIndexOfTabRecursive(tab_model_ptr),
collection->ChildCount() - 1);
}
}
private:
std::unique_ptr<tabs::SplitTabCollection> split_collection_;
const tabs::TabModel::PreventFeatureInitializationForTesting prevent_;
};
TEST_F(SplitTabCollectionTest, AddOperation) {
// Setup phase of keeping track of two tabs.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
auto tab_model_two =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabModel* tab_model_two_ptr = tab_model_two.get();
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
tabs::SplitTabCollection* split_collection = GetCollection();
// Add `tab_model_one` to the end of the collection.
AppendTab(split_collection, std::move(tab_model_one));
EXPECT_EQ(tab_model_one_ptr->GetSplit(), split_collection->GetSplitTabId());
EXPECT_EQ(tab_model_one_ptr->GetParentCollectionForTesting(),
split_collection);
EXPECT_TRUE(ContainsTabRecursive(split_collection, tab_model_one_ptr));
// Add two tabs to the collection.
AddTabsToSplitContainer(GetCollection(), GetTabStripModel(), 2);
EXPECT_EQ(split_collection->ChildCount(), 3ul);
EXPECT_EQ(split_collection->TabCountRecursive(), 3ul);
// Add `tab_model_two` to index 1.
split_collection->AddTab(std::move(tab_model_two), 1ul);
EXPECT_EQ(split_collection->GetIndexOfTabRecursive(tab_model_two_ptr), 1ul);
}
TEST_F(SplitTabCollectionTest, RemoveOperation) {
// Setup phase of keeping track of a tab.
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::SplitTabCollection* split_collection = GetCollection();
// Add three tabs to the collection.
AddTabsToSplitContainer(GetCollection(), GetTabStripModel(), 3);
// Add `tab_model_one` to index 2.
split_collection->AddTab(std::move(tab_model_one), 2ul);
EXPECT_EQ(split_collection->GetIndexOfTabRecursive(tab_model_one_ptr), 2ul);
EXPECT_EQ(split_collection->ChildCount(), 4ul);
EXPECT_EQ(tab_model_one_ptr->GetSplit(), split_collection->GetSplitTabId());
tab_model_one_ptr->set_will_be_detaching_for_testing(true);
// Remove `tab_model_one` from the collection.
auto removed_tab = split_collection->MaybeRemoveTab(tab_model_one_ptr);
EXPECT_EQ(tab_model_one_ptr, removed_tab.get());
EXPECT_FALSE(tab_model_one_ptr->GetSplit().has_value());
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
EXPECT_EQ(split_collection->ChildCount(), 3ul);
}
class UnpinnedTabCollectionTest : public TabCollectionBaseTest {
public:
UnpinnedTabCollectionTest() {
unpinned_collection_ = std::make_unique<tabs::UnpinnedTabCollection>();
}
UnpinnedTabCollectionTest(const UnpinnedTabCollectionTest&) = delete;
UnpinnedTabCollectionTest& operator=(const UnpinnedTabCollectionTest&) =
delete;
~UnpinnedTabCollectionTest() override { unpinned_collection_.reset(); }
tabs::UnpinnedTabCollection* GetCollection() {
return unpinned_collection_.get();
}
// Creates a basic setup of the unpinned collection with -
// 1. Two tabs at the start of the collection. Followed by
// 2. A group with two tabs. Followed by
// 3. Two tabs.
void PerformBasicSetup() {
AddTabsToUnpinnedContainer(GetCollection(), GetTabStripModel(), 2);
tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
TabGroupDesktop::Factory factory(profile());
auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
factory, group_id, tab_groups::TabGroupVisualData());
AddTabsToGroupContainer(tab_group_one.get(), GetTabStripModel(), 2);
GetCollection()->AddCollection(std::move(tab_group_one), 2);
AddTabsToUnpinnedContainer(GetCollection(), GetTabStripModel(), 2);
EXPECT_EQ(GetCollection()->ChildCount(), 5ul);
EXPECT_EQ(GetCollection()->TabCountRecursive(), 6ul);
EXPECT_EQ(GetCollection()->GetDirectChildIndexOfCollectionContainingTab(
GetCollection()->GetTabAtIndexRecursive(1)),
1ul);
EXPECT_EQ(GetCollection()->GetDirectChildIndexOfCollectionContainingTab(
GetCollection()->GetTabAtIndexRecursive(3)),
2ul);
}
private:
std::unique_ptr<tabs::UnpinnedTabCollection> unpinned_collection_;
};
TEST_F(UnpinnedTabCollectionTest, AddOperation) {
// Use the basic setup scenario and track a tab and group.
PerformBasicSetup();
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
TabGroupDesktop::Factory factory(profile());
auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
factory, group_id, tab_groups::TabGroupVisualData());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabGroupTabCollection* tab_group_one_ptr = tab_group_one.get();
EXPECT_FALSE(tab_model_one_ptr->GetParentCollectionForTesting());
EXPECT_FALSE(tab_group_one_ptr->GetParentCollection());
tabs::UnpinnedTabCollection* unpinned_collection = GetCollection();
// Add the `tab_model_one` to the collection.
AppendTab(unpinned_collection, std::move(tab_model_one));
EXPECT_EQ(tab_model_one_ptr->GetParentCollectionForTesting(),
unpinned_collection);
EXPECT_TRUE(ContainsTabRecursive(unpinned_collection, tab_model_one_ptr));
EXPECT_FALSE(unpinned_collection->ContainsCollection(tab_group_one_ptr));
// Add a group to the collection at index 2.
unpinned_collection->AddCollection(std::move(tab_group_one), 2ul);
EXPECT_EQ(tab_group_one_ptr->GetParentCollection(), unpinned_collection);
EXPECT_TRUE(ContainsTabRecursive(unpinned_collection, tab_model_one_ptr));
EXPECT_TRUE(unpinned_collection->ContainsCollection(tab_group_one_ptr));
EXPECT_EQ(unpinned_collection->GetIndexOfTabRecursive(tab_model_one_ptr),
6ul);
EXPECT_EQ(unpinned_collection->GetIndexOfCollection(tab_group_one_ptr), 2ul);
auto tab_model_in_group =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_in_group_ptr = tab_model_in_group.get();
// Add tabs to the group and validate index and size. Track one of the tabs.
AppendTab(tab_group_one_ptr, std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()));
AppendTab(tab_group_one_ptr, std::move(tab_model_in_group));
EXPECT_EQ(unpinned_collection->GetIndexOfTabRecursive(tab_model_in_group_ptr),
3);
EXPECT_EQ(unpinned_collection->ChildCount(), 7ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 9ul);
}
TEST_F(UnpinnedTabCollectionTest, RemoveOperation) {
// Use the basic setup scenario and track a tab and group.
PerformBasicSetup();
auto tab_model_one =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tab_groups::TabGroupId group_id = tab_groups::TabGroupId::GenerateNew();
TabGroupDesktop::Factory factory(profile());
auto tab_group_one = std::make_unique<tabs::TabGroupTabCollection>(
factory, group_id, tab_groups::TabGroupVisualData());
tabs::TabModel* tab_model_one_ptr = tab_model_one.get();
tabs::TabGroupTabCollection* tab_group_one_ptr = tab_group_one.get();
// Add two tabs to the group
AddTabsToGroupContainer(tab_group_one_ptr, GetTabStripModel(), 2);
tabs::UnpinnedTabCollection* unpinned_collection = GetCollection();
// Add the tab and the group at index 2 and index 4 respectively.
unpinned_collection->AddTab(std::move(tab_model_one), 2ul);
unpinned_collection->AddCollection(std::move(tab_group_one), 4ul);
// Remove the tab
tab_model_one_ptr->set_will_be_detaching_for_testing(true);
std::unique_ptr<tabs::TabInterface> removed_tab =
unpinned_collection->MaybeRemoveTab(tab_model_one_ptr);
EXPECT_EQ(removed_tab.get(), tab_model_one_ptr);
EXPECT_EQ(unpinned_collection->ChildCount(), 6ul);
EXPECT_FALSE(ContainsTabRecursive(unpinned_collection, tab_model_one_ptr));
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 8ul);
EXPECT_EQ(unpinned_collection->GetIndexOfCollection(tab_group_one_ptr), 3ul);
// Remove the collection
std::unique_ptr<tabs::TabCollection> removed_collection =
unpinned_collection->MaybeRemoveCollection(tab_group_one_ptr);
EXPECT_EQ(removed_collection.get(), tab_group_one_ptr);
EXPECT_EQ(unpinned_collection->ChildCount(), 5ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 6ul);
EXPECT_FALSE(unpinned_collection->ContainsCollection(tab_group_one_ptr));
EXPECT_EQ(removed_collection->GetParentCollection(), nullptr);
}
class TabStripCollectionTest : public TabCollectionBaseTest {
public:
TabStripCollectionTest() {
tab_strip_collection_ = std::make_unique<tabs::TabStripCollection>();
}
TabStripCollectionTest(const TabStripCollectionTest&) = delete;
TabStripCollectionTest& operator=(const TabStripCollectionTest&) = delete;
~TabStripCollectionTest() override { tab_strip_collection_.reset(); }
tabs::TabStripCollection* GetCollection() {
return tab_strip_collection_.get();
}
void PerformBasicSetup() {
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Add four pinned tabs.
AddTabsToPinnedContainer(pinned_collection, GetTabStripModel(), 4);
AddTabsToUnpinnedContainer(unpinned_collection, GetTabStripModel(), 2);
// Add a group to the unpinned collection with two tabs.
TabGroupDesktop::Factory factory(profile());
std::unique_ptr<tabs::TabGroupTabCollection> group_one =
std::make_unique<tabs::TabGroupTabCollection>(
factory, tab_groups::TabGroupId::GenerateNew(),
tab_groups::TabGroupVisualData());
tabs::TabGroupTabCollection* group_one_ptr = group_one.get();
AddTabsToGroupContainer(group_one_ptr, GetTabStripModel(), 2);
tab_strip_collection->InsertTabCollectionAt(std::move(group_one), 6, false,
std::nullopt);
// Add one more tab.
AppendTab(unpinned_collection, std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()));
tabs::TabCollectionStorage* pinned_storage =
pinned_collection->GetTabCollectionStorageForTesting();
tabs::TabCollectionStorage* unpinned_storage =
unpinned_collection->GetTabCollectionStorageForTesting();
tabs::TabCollectionStorage* group_one_storage =
group_one_ptr->GetTabCollectionStorageForTesting();
EXPECT_EQ(tab_strip_collection->TabCountRecursive(), 9ul);
// GetTabAtIndex checks
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(0),
GetTabInCollectionStorage(pinned_storage, 0ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(1),
GetTabInCollectionStorage(pinned_storage, 1ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(2),
GetTabInCollectionStorage(pinned_storage, 2ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(3),
GetTabInCollectionStorage(pinned_storage, 3ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(4),
GetTabInCollectionStorage(unpinned_storage, 0ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(5),
GetTabInCollectionStorage(unpinned_storage, 1ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(6),
GetTabInCollectionStorage(group_one_storage, 0ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(7),
GetTabInCollectionStorage(group_one_storage, 1ul));
EXPECT_EQ(tab_strip_collection->GetTabAtIndexRecursive(8),
GetTabInCollectionStorage(unpinned_storage, 3ul));
}
void TestAddTabRecursive(size_t index,
std::optional<tab_groups::TabGroupId> new_group_id,
bool new_pinned_state) {
tabs::TabStripCollection* tab_strip_collection = GetCollection();
std::unique_ptr<tabs::TabModel> tab =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_ptr = tab.get();
tab_strip_collection->AddTabRecursive(std::move(tab), index, new_group_id,
new_pinned_state);
EXPECT_EQ(tab_ptr, tab_strip_collection->GetTabAtIndexRecursive(index));
}
private:
std::unique_ptr<tabs::TabStripCollection> tab_strip_collection_;
const tabs::TabModel::PreventFeatureInitializationForTesting prevent_;
};
TEST_F(TabStripCollectionTest, CollectionOperations) {
tabs::TabStripCollection* tab_strip_collection = GetCollection();
EXPECT_EQ(tab_strip_collection->ChildCount(), 2ul);
EXPECT_TRUE(tab_strip_collection->ContainsCollection(
tab_strip_collection->pinned_collection()));
EXPECT_TRUE(tab_strip_collection->ContainsCollection(
tab_strip_collection->unpinned_collection()));
EXPECT_EQ(tab_strip_collection->GetIndexOfCollection(
tab_strip_collection->pinned_collection()),
0ul);
EXPECT_EQ(tab_strip_collection->GetIndexOfCollection(
tab_strip_collection->unpinned_collection()),
1ul);
EXPECT_EQ(tab_strip_collection->MaybeRemoveCollection(
tab_strip_collection->unpinned_collection()),
nullptr);
}
TEST_F(TabStripCollectionTest, GroupOperations) {
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
EXPECT_EQ(tab_strip_collection->ChildCount(), 2ul);
tab_groups::TabGroupId group_two_id = tab_groups::TabGroupId::GenerateNew();
TabGroupDesktop::Factory factory(profile());
std::unique_ptr<tabs::TabGroupTabCollection> group_two =
std::make_unique<tabs::TabGroupTabCollection>(
factory, group_two_id, tab_groups::TabGroupVisualData());
tabs::TabGroupTabCollection* group_two_ptr = group_two.get();
EXPECT_EQ(nullptr, tab_strip_collection->GetTabGroupCollection(group_two_id));
// TODO(crbug.com/332586827): Re-enable death testing.
// Add group to pinned container.
// EXPECT_DEATH_IF_SUPPORTED(
// tab_strip_collection->AddTabGroup(std::move(group_two), 2), "");
// Add group to unpinned container.
tab_strip_collection->InsertTabCollectionAt(std::move(group_two), 5, false,
std::nullopt);
EXPECT_EQ(group_two_ptr,
tab_strip_collection->GetTabGroupCollection(group_two_id));
EXPECT_EQ(group_two_ptr,
tab_strip_collection->GetTabGroupCollection(group_two_id));
EXPECT_EQ(1ul,
tab_strip_collection->unpinned_collection()->GetIndexOfCollection(
group_two_ptr));
EXPECT_EQ(group_two_ptr,
tab_strip_collection->RemoveTabCollection(group_two_ptr).get());
EXPECT_EQ(nullptr, tab_strip_collection->GetTabGroupCollection(group_two_id));
}
TEST_F(TabStripCollectionTest, SplitOperations) {
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_collection =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2));
auto createSplitAtIndices = [tab_strip_collection](std::vector<int> indices) {
std::vector<tabs::TabInterface*> tabs;
for (int i : indices) {
tabs.push_back(tab_strip_collection->GetTabAtIndexRecursive(i));
}
split_tabs::SplitTabId split_id = split_tabs::SplitTabId::GenerateNew();
tab_strip_collection->CreateSplit(
split_id, tabs,
split_tabs::SplitTabVisualData(split_tabs::SplitTabLayout::kVertical,
0.5));
return std::tuple{
tabs, tab_strip_collection->GetSplitTabCollection(split_id), split_id};
};
// Add split to pinned container
// 0p 1ps 2ps 3p 4u 5u 6ug 7ug 8u
EXPECT_EQ(4ul, pinned_collection->ChildCount());
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
auto [tabs, split, split_id] = createSplitAtIndices({1, 2});
EXPECT_EQ(split_id, split->GetSplitTabId());
EXPECT_EQ(3ul, pinned_collection->ChildCount());
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
EXPECT_EQ(1ul, pinned_collection->GetIndexOfCollection(split));
EXPECT_EQ(2ul, split->ChildCount());
EXPECT_EQ(tabs, split->GetTabsRecursive());
tab_strip_collection->Unsplit(split_id);
EXPECT_EQ(nullptr, tab_strip_collection->GetSplitTabCollection(split_id));
EXPECT_EQ(4ul, pinned_collection->ChildCount());
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
// Add split to unpinned container.
// 0p 1p 2p 3p 4us 5us 6ug 7ug 8u
EXPECT_EQ(4ul, unpinned_collection->ChildCount());
EXPECT_EQ(5ul, unpinned_collection->TabCountRecursive());
std::tie(tabs, split, split_id) = createSplitAtIndices({4, 5});
EXPECT_EQ(split_id, split->GetSplitTabId());
EXPECT_EQ(3ul, unpinned_collection->ChildCount());
EXPECT_EQ(5ul, unpinned_collection->TabCountRecursive());
EXPECT_EQ(0ul, unpinned_collection->GetIndexOfCollection(split));
EXPECT_EQ(2ul, split->ChildCount());
EXPECT_EQ(tabs, split->GetTabsRecursive());
tab_strip_collection->Unsplit(split_id);
EXPECT_EQ(nullptr, tab_strip_collection->GetSplitTabCollection(split_id));
EXPECT_EQ(4ul, unpinned_collection->ChildCount());
EXPECT_EQ(5ul, unpinned_collection->TabCountRecursive());
// Add split to group container.
// 0p 1p 2p 3p 4u 5u 6ugs 7ugs 8u
EXPECT_EQ(2ul, group_collection->ChildCount());
EXPECT_EQ(2ul, group_collection->TabCountRecursive());
std::tie(tabs, split, split_id) = createSplitAtIndices({6, 7});
EXPECT_EQ(split_id, split->GetSplitTabId());
EXPECT_EQ(1ul, group_collection->ChildCount());
EXPECT_EQ(2ul, group_collection->TabCountRecursive());
EXPECT_EQ(0ul, group_collection->GetIndexOfCollection(split));
EXPECT_EQ(2ul, split->ChildCount());
EXPECT_EQ(tabs, split->GetTabsRecursive());
tab_strip_collection->Unsplit(split_id);
EXPECT_EQ(nullptr, tab_strip_collection->GetSplitTabCollection(split_id));
EXPECT_EQ(2ul, group_collection->ChildCount());
EXPECT_EQ(2ul, group_collection->TabCountRecursive());
}
TEST_F(TabStripCollectionTest, RemoveAndInsertSplit) {
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_collection =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2));
auto createSplitAtIndices = [tab_strip_collection](std::vector<int> indices) {
std::vector<tabs::TabInterface*> tabs;
for (int i : indices) {
tabs.push_back(tab_strip_collection->GetTabAtIndexRecursive(i));
}
split_tabs::SplitTabId split_id = split_tabs::SplitTabId::GenerateNew();
tab_strip_collection->CreateSplit(
split_id, tabs,
split_tabs::SplitTabVisualData(split_tabs::SplitTabLayout::kVertical,
0.5));
return std::tuple{
tabs, tab_strip_collection->GetSplitTabCollection(split_id), split_id};
};
// Add split to pinned container
// 0p 1ps 2ps 3p 4u 5u 6ug 7ug 8u
EXPECT_EQ(4ul, pinned_collection->ChildCount());
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
auto [tabs, split, split_id] = createSplitAtIndices({1, 2});
EXPECT_EQ(split_id, split->GetSplitTabId());
EXPECT_EQ(3ul, pinned_collection->ChildCount());
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
EXPECT_EQ(1ul, pinned_collection->GetIndexOfCollection(split));
EXPECT_EQ(2ul, split->ChildCount());
EXPECT_EQ(tabs, split->GetTabsRecursive());
// Remove split from pinned container
// 0p 3p 4u 5u 6ug 7ug 8u
std::unique_ptr<tabs::SplitTabCollection> removed_split_collection =
base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
tab_strip_collection->RemoveTabCollection(split).release()));
EXPECT_EQ(2ul, pinned_collection->TabCountRecursive());
EXPECT_FALSE(
tab_strip_collection->GetSplitTabCollection(split->GetSplitTabId()));
// Insert back into pinned container
// 0p 1ps 2ps 3p 4u 5u 6ug 7ug 8u
tab_strip_collection->InsertTabCollectionAt(
std::move(removed_split_collection), 1, true, std::nullopt);
EXPECT_TRUE(
tab_strip_collection->GetSplitTabCollection(split->GetSplitTabId()));
EXPECT_EQ(4ul, pinned_collection->TabCountRecursive());
// Remove split and insert into unpinned container
// 0p 3p 4u 1s 2s 5u 6ug 7ug 8u
removed_split_collection =
base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
tab_strip_collection->RemoveTabCollection(split).release()));
tab_strip_collection->InsertTabCollectionAt(
std::move(removed_split_collection), 3, false, std::nullopt);
EXPECT_EQ(7ul, unpinned_collection->TabCountRecursive());
EXPECT_TRUE(
tab_strip_collection->GetSplitTabCollection(split->GetSplitTabId()));
// Remove split and insert into group container
// 0p 3p 4u 5u 6ug 1gs 2gs 7ug 8u
removed_split_collection =
base::WrapUnique(static_cast<tabs::SplitTabCollection*>(
tab_strip_collection->RemoveTabCollection(split).release()));
tab_strip_collection->InsertTabCollectionAt(
std::move(removed_split_collection), 5, false,
group_collection->GetTabGroupId());
EXPECT_EQ(7ul, unpinned_collection->TabCountRecursive());
EXPECT_EQ(4ul, group_collection->TabCountRecursive());
EXPECT_TRUE(
tab_strip_collection->GetSplitTabCollection(split->GetSplitTabId()));
}
TEST_F(TabStripCollectionTest, TabOperations) {
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
tabs::TabCollectionStorage* pinned_storage =
pinned_collection->GetTabCollectionStorageForTesting();
tabs::TabCollectionStorage* unpinned_storage =
unpinned_collection->GetTabCollectionStorageForTesting();
// Add three tabs to the pinned collection.
AddTabsToPinnedContainer(pinned_collection, GetTabStripModel(), 3);
// Add one tab, a group with two tabs and another tab to the unpinned
// collection.
AppendTab(unpinned_collection, std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()));
TabGroupDesktop::Factory factory(profile());
std::unique_ptr<tabs::TabGroupTabCollection> group_one =
std::make_unique<tabs::TabGroupTabCollection>(
factory, tab_groups::TabGroupId::GenerateNew(),
tab_groups::TabGroupVisualData());
tabs::TabGroupTabCollection* group_one_ptr = group_one.get();
AddTabsToGroupContainer(group_one_ptr, GetTabStripModel(), 2);
unpinned_collection->AddCollection(std::move(group_one), 1ul);
AppendTab(unpinned_collection, std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()));
std::unique_ptr<tabs::TabModel> tab_not_present =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabCollectionStorage* group_storage =
group_one_ptr->GetTabCollectionStorageForTesting();
// tab count test in tab strip.
EXPECT_EQ(tab_strip_collection->TabCountRecursive(), 7ul);
// tab contains test in tab strip.
EXPECT_FALSE(
ContainsTabRecursive(tab_strip_collection, tab_not_present.get()));
EXPECT_TRUE(ContainsTabRecursive(
tab_strip_collection, GetTabInCollectionStorage(pinned_storage, 2ul)));
EXPECT_TRUE(ContainsTabRecursive(
tab_strip_collection, GetTabInCollectionStorage(group_storage, 1ul)));
EXPECT_FALSE(ContainsTab(tab_strip_collection,
GetTabInCollectionStorage(unpinned_storage, 2ul)));
EXPECT_TRUE(ContainsTabRecursive(
tab_strip_collection, GetTabInCollectionStorage(unpinned_storage, 2ul)));
// tab recursive index test in tab strip.
EXPECT_EQ(tab_strip_collection->GetIndexOfTabRecursive(
GetTabInCollectionStorage(pinned_storage, 2ul)),
2ul);
EXPECT_EQ(tab_strip_collection->GetIndexOfTabRecursive(
GetTabInCollectionStorage(group_storage, 0ul)),
4ul);
EXPECT_EQ(tab_strip_collection->GetIndexOfTabRecursive(
GetTabInCollectionStorage(group_storage, 1ul)),
5ul);
EXPECT_EQ(tab_strip_collection->GetIndexOfTabRecursive(
GetTabInCollectionStorage(unpinned_storage, 2ul)),
6ul);
// We cannot remove a tab as it is not a direct child of the tab strip
// collection.
EXPECT_EQ(tab_strip_collection->MaybeRemoveTab(
GetTabInCollectionStorage(unpinned_storage, 2ul)),
nullptr);
}
// Test for `AddTabRecursive`.
TEST_F(TabStripCollectionTest, RecursiveTabIndexOperationTests) {
// Setup for the main collections.
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_one_ptr =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2));
// Insert Recursive checks -
// 1. Add to pinned container.
TestAddTabRecursive(2, std::nullopt, true);
EXPECT_EQ(pinned_collection->TabCountRecursive(), 5ul);
// 2. Add as a tab to unpinned container. Now pinned container has 5 tabs.
TestAddTabRecursive(5, std::nullopt, false);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 6ul);
EXPECT_EQ(unpinned_collection->ChildCount(), 5ul);
// 3. Add to the end of the unpinned container.
TestAddTabRecursive(11, std::nullopt, false);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 7ul);
EXPECT_EQ(unpinned_collection->ChildCount(), 6ul);
// 4. Add to group container.
TestAddTabRecursive(9, group_one_ptr->GetTabGroupId(), false);
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 3ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 8ul);
// 5. Corner case add to boundary of group container.
TestAddTabRecursive(8, group_one_ptr->GetTabGroupId(), false);
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 4ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 9ul);
TestAddTabRecursive(8, std::nullopt, false);
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 4ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 10ul);
// Now group has 4. And 4 unpinned before the group.
TestAddTabRecursive(13, group_one_ptr->GetTabGroupId(), false);
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 5ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 11ul);
TestAddTabRecursive(14, std::nullopt, false);
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 5ul);
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 12ul);
}
TEST_F(TabStripCollectionTest, RecursiveRemoveTabAtIndex) {
// Setup for the main collections.
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_one_ptr =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2ul));
// Remove a pinned tab.
tabs::TabInterface* tab_to_check =
tab_strip_collection->GetTabAtIndexRecursive(2ul);
EXPECT_EQ(tab_to_check,
tab_strip_collection->RemoveTabAtIndexRecursive(2).get());
EXPECT_EQ(pinned_collection->TabCountRecursive(), 3ul);
// Remove an unpinned tab. Now there are 3 pinned tabs.
tab_to_check = tab_strip_collection->GetTabAtIndexRecursive(4ul);
EXPECT_EQ(tab_to_check,
tab_strip_collection->RemoveTabAtIndexRecursive(4ul).get());
EXPECT_EQ(unpinned_collection->TabCountRecursive(), 4ul);
// Remove a grouped tab. Now there are 3 pinned tabs and 1 unpinned tab
// before the group.
tab_to_check = tab_strip_collection->GetTabAtIndexRecursive(4ul);
EXPECT_EQ(tab_to_check,
tab_strip_collection->RemoveTabAtIndexRecursive(4ul).get());
EXPECT_EQ(group_one_ptr->TabCountRecursive(), 1ul);
}
// TODO(b/332586827): Re-enable death testing.
TEST_F(TabStripCollectionTest, DISABLED_RecursiveTabAddBadInput) {
// Setup for the main collections.
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
// Try to add an index OOB
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
20ul, std::nullopt, false),
"");
// Try to add a pinned tab to unpinned container index location.
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
5ul, std::nullopt, true),
"");
// Try to add a unpinned tab to pinned container index location.
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
1ul, std::nullopt, false),
"");
// Try to add a tab to pinned container index location.
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
1ul, std::nullopt, false),
"");
// Try to add a tab to pinned container index location with a group.
tabs::TabGroupTabCollection* group_one_ptr =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
GetCollection()
->unpinned_collection()
->GetTabCollectionStorageForTesting(),
2));
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
1ul, group_one_ptr->GetTabGroupId(), true),
"");
// Try to add a tab to unpinned container index that should not be a part of a
// group but a group value is passed.
EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()),
5ul, group_one_ptr->GetTabGroupId(), true),
"");
EXPECT_DEATH_IF_SUPPORTED(
tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(MakeWebContents(),
GetTabStripModel()),
6ul, tab_groups::TabGroupId::GenerateNew(), true),
"");
// Try to add a tab to unpinned container index that should not be a part of a
// group but a different group id.
EXPECT_DEATH_IF_SUPPORTED(
tab_strip_collection->AddTabRecursive(
std::make_unique<tabs::TabModel>(MakeWebContents(),
GetTabStripModel()),
7ul, tab_groups::TabGroupId::GenerateNew(), true),
"");
}
TEST_F(TabStripCollectionTest, UpdateProperties) {
// Setup for the main collections.
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::PinnedTabCollection* pinned_collection =
tab_strip_collection->pinned_collection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_collection =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2ul));
std::unique_ptr<tabs::TabModel> tab_model =
std::make_unique<tabs::TabModel>(MakeWebContents(), GetTabStripModel());
tabs::TabModel* tab_model_ptr = tab_model.get();
ASSERT_FALSE(tab_model_ptr->IsPinned());
ASSERT_FALSE(tab_model_ptr->IsSplit());
ASSERT_EQ(std::nullopt, tab_model_ptr->GetGroup());
// Move to pinned collection.
ASSERT_EQ(tab_model_ptr, AppendTab(pinned_collection, std::move(tab_model)));
EXPECT_TRUE(tab_model_ptr->IsPinned());
EXPECT_FALSE(tab_model_ptr->IsSplit());
EXPECT_EQ(std::nullopt, tab_model_ptr->GetGroup());
// Move to group collection.
ASSERT_EQ(tab_model_ptr,
AppendTab(group_collection,
pinned_collection->MaybeRemoveTab(tab_model_ptr)));
EXPECT_FALSE(tab_model_ptr->IsPinned());
EXPECT_FALSE(tab_model_ptr->IsSplit());
EXPECT_EQ(group_collection->GetTabGroupId(), tab_model_ptr->GetGroup());
// Move to split collection.
tabs::SplitTabCollection* split_collection =
unpinned_collection->AddCollection(
std::make_unique<tabs::SplitTabCollection>(
split_tabs::SplitTabId::GenerateNew(),
split_tabs::SplitTabVisualData(
split_tabs::SplitTabLayout::kVertical, 0.5)),
unpinned_collection->ChildCount());
AppendTab(split_collection, std::make_unique<tabs::TabModel>(
MakeWebContents(), GetTabStripModel()));
ASSERT_EQ(tab_model_ptr,
AppendTab(split_collection,
group_collection->MaybeRemoveTab(tab_model_ptr)));
EXPECT_FALSE(tab_model_ptr->IsPinned());
EXPECT_EQ(split_collection->GetSplitTabId(), tab_model_ptr->GetSplit());
EXPECT_EQ(std::nullopt, tab_model_ptr->GetGroup());
// Move split collection to pinned collection
ASSERT_EQ(split_collection,
pinned_collection->AddCollection(
unpinned_collection->MaybeRemoveCollection(split_collection),
pinned_collection->ChildCount()));
EXPECT_TRUE(tab_model_ptr->IsPinned());
EXPECT_EQ(split_collection->GetSplitTabId(), tab_model_ptr->GetSplit());
EXPECT_EQ(std::nullopt, tab_model_ptr->GetGroup());
// Move split collection to group collection
ASSERT_EQ(split_collection,
group_collection->AddCollection(
pinned_collection->MaybeRemoveCollection(split_collection),
group_collection->ChildCount()));
EXPECT_FALSE(tab_model_ptr->IsPinned());
EXPECT_EQ(split_collection->GetSplitTabId(), tab_model_ptr->GetSplit());
EXPECT_EQ(group_collection->GetTabGroupId(), tab_model_ptr->GetGroup());
}
TEST_F(TabStripCollectionTest, ValidateData) {
// Setup for the main collections.
PerformBasicSetup();
tabs::TabStripCollection* tab_strip_collection = GetCollection();
tabs::UnpinnedTabCollection* unpinned_collection =
tab_strip_collection->unpinned_collection();
// Get the group collection from the basic setup.
tabs::TabGroupTabCollection* group_one_ptr =
static_cast<tabs::TabGroupTabCollection*>(
GetCollectionInCollectionStorage(
unpinned_collection->GetTabCollectionStorageForTesting(), 2ul));
tab_strip_collection->ValidateData();
tab_groups::TabGroupId group_two_id = tab_groups::TabGroupId::GenerateNew();
TabGroupDesktop::Factory factory(profile());
tab_strip_collection->CreateTabGroup(
std::make_unique<tabs::TabGroupTabCollection>(
factory, group_two_id, tab_groups::TabGroupVisualData()));
// TODO(crbug.com/332586827): Re-enable death testing.
// EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->ValidateData(), "");
tab_strip_collection->CloseDetachedTabGroup(group_two_id);
tab_strip_collection->ValidateData();
ASSERT_EQ(group_one_ptr->ChildCount(), 2ul);
group_one_ptr->MaybeRemoveTab(group_one_ptr->GetTabAtIndexRecursive(0))
.reset();
group_one_ptr->MaybeRemoveTab(group_one_ptr->GetTabAtIndexRecursive(0))
.reset();
ASSERT_EQ(group_one_ptr->ChildCount(), 0ul);
// TODO(crbug.com/332586827): Re-enable death testing.
// EXPECT_DEATH_IF_SUPPORTED(tab_strip_collection->ValidateData(), "");
}