Index: chrome/browser/ui/tabs/mru_tab_controller_unittest.cc |
diff --git a/chrome/browser/ui/tabs/mru_tab_controller_unittest.cc b/chrome/browser/ui/tabs/mru_tab_controller_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2d99bfcbb6713461f254a54ebed1cd2cc6bf5091 |
--- /dev/null |
+++ b/chrome/browser/ui/tabs/mru_tab_controller_unittest.cc |
@@ -0,0 +1,288 @@ |
+// Copyright (c) 2012 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. |
+ |
+#include "chrome/browser/ui/tabs/mru_tab_controller.h" |
+ |
+#include <map> |
+#include <string> |
+ |
+#include "base/stl_util.h" |
+#include "base/string_number_conversions.h" |
+#include "base/string_split.h" |
+#include "base/utf_string_conversions.h" |
+#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/browser_tabstrip.h" |
+#include "chrome/browser/ui/tab_contents/tab_contents.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" |
+#include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h" |
+#include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h" |
+#include "chrome/common/url_constants.h" |
+#include "chrome/test/base/chrome_render_view_host_test_harness.h" |
+#include "chrome/test/base/testing_profile.h" |
+#include "content/public/browser/web_contents.h" |
+#include "content/public/test/test_browser_thread.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using content::BrowserThread; |
+using content::SiteInstance; |
+using content::WebContents; |
+ |
+class TabStripDummyDelegate : public TestTabStripModelDelegate { |
+ public: |
+ explicit TabStripDummyDelegate(TabContents* dummy) |
+ : dummy_contents_(dummy), |
+ can_close_(true), |
+ run_unload_(false) {} |
+ virtual ~TabStripDummyDelegate() {} |
+ |
+ void set_can_close(bool value) { can_close_ = value; } |
+ void set_run_unload_listener(bool value) { run_unload_ = value; } |
+ |
+ // Overridden from TabStripModelDelegate: |
+ virtual TabContents* CreateTabContentsForURL( |
+ const GURL& url, |
+ const content::Referrer& referrer, |
+ Profile* profile, |
+ content::PageTransition transition, |
+ bool defer_load, |
+ SiteInstance* instance) const OVERRIDE { |
+ if (url == GURL(chrome::kChromeUINewTabURL)) |
+ return dummy_contents_; |
+ return NULL; |
+ } |
+ virtual bool RunUnloadListenerBeforeClosing(TabContents* contents) OVERRIDE { |
+ return run_unload_; |
+ } |
+ virtual bool CanCloseContents(std::vector<int>* indices) OVERRIDE { |
+ if (!can_close_) |
+ indices->clear(); |
+ return can_close_; |
+ } |
+ |
+ private: |
+ // A dummy TabContents we give to callers that expect us to actually |
+ // build a Destinations tab for them. |
+ TabContents* dummy_contents_; |
+ |
+ // Whether tabs can be closed. |
+ bool can_close_; |
+ |
+ // Whether to report that we need to run an unload listener before closing. |
+ bool run_unload_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate); |
+}; |
+ |
+class MRUTabControllerTest : public ChromeRenderViewHostTestHarness { |
+ public: |
+ MRUTabControllerTest() : browser_thread_(BrowserThread::UI, &message_loop_) { |
+ } |
+ |
+ TabContents* CreateTabContents() { |
+ return chrome::TabContentsFactory( |
+ profile(), NULL, MSG_ROUTING_NONE, NULL, NULL); |
+ } |
+ |
+ TabContents* CreateTabContentsWithSharedRPH( |
+ WebContents* web_contents) { |
+ TabContents* retval = chrome::TabContentsFactory(profile(), |
+ web_contents->GetRenderViewHost()->GetSiteInstance(), MSG_ROUTING_NONE, |
+ NULL, NULL); |
+ EXPECT_EQ(retval->web_contents()->GetRenderProcessHost(), |
+ web_contents->GetRenderProcessHost()); |
+ return retval; |
+ } |
+ |
+ // Forwards a URL "load" request through to our dummy TabContents |
+ // implementation. |
+ void LoadURL(WebContents* con, const std::wstring& url) { |
+ controller().LoadURL(GURL(WideToUTF16(url)), content::Referrer(), |
+ content::PAGE_TRANSITION_LINK, std::string()); |
+ } |
+ |
+ void GoBack(WebContents* contents) { |
+ controller().GoBack(); |
+ } |
+ |
+ void GoForward(WebContents* contents) { |
+ controller().GoForward(); |
+ } |
+ |
+ void SwitchTabTo(WebContents* contents) { |
+ // contents()->DidBecomeSelected(); |
+ } |
+ |
+ // Sets the id of the specified contents. |
+ void SetID(WebContents* contents, int id) { |
+ GetIDAccessor()->SetProperty(contents->GetPropertyBag(), id); |
+ } |
+ |
+ // Returns the id of the specified contents. |
+ int GetID(WebContents* contents) { |
+ return *GetIDAccessor()->GetProperty(contents->GetPropertyBag()); |
+ } |
+ |
+ // Returns the state of the given tab strip as a string. The state consists |
+ // of the ID of each tab contents followed by a 'p' if pinned. For example, |
+ // if the model consists of two tabs with ids 2 and 1, with the first |
+ // tab pinned, this returns "2p 1". |
+ std::string GetPinnedState(const TabStripModel& model) { |
+ std::string actual; |
+ for (int i = 0; i < model.count(); ++i) { |
+ if (i > 0) |
+ actual += " "; |
+ |
+ actual += |
+ base::IntToString(GetID(model.GetTabContentsAt(i)->web_contents())); |
+ |
+ if (model.IsAppTab(i)) |
+ actual += "a"; |
+ |
+ if (model.IsTabPinned(i)) |
+ actual += "p"; |
+ } |
+ return actual; |
+ } |
+ |
+ std::string GetIndicesClosedByCommandAsString( |
+ const TabStripModel& model, |
+ int index, |
+ TabStripModel::ContextMenuCommand id) const { |
+ std::vector<int> indices = model.GetIndicesClosedByCommand(index, id); |
+ std::string result; |
+ for (size_t i = 0; i < indices.size(); ++i) { |
+ if (i != 0) |
+ result += " "; |
+ result += base::IntToString(indices[i]); |
+ } |
+ return result; |
+ } |
+ |
+ void PrepareTabstripForSelectionTest(TabStripModel* model, |
+ int tab_count, |
+ int pinned_count, |
+ const std::string& selected_tabs) { |
+ for (int i = 0; i < tab_count; ++i) { |
+ TabContents* contents = CreateTabContents(); |
+ SetID(contents->web_contents(), i); |
+ model->AppendTabContents(contents, true); |
+ } |
+ for (int i = 0; i < pinned_count; ++i) |
+ model->SetTabPinned(i, true); |
+ |
+ TabStripSelectionModel selection_model; |
+ std::vector<std::string> selection; |
+ base::SplitStringAlongWhitespace(selected_tabs, &selection); |
+ for (size_t i = 0; i < selection.size(); ++i) { |
+ int value; |
+ ASSERT_TRUE(base::StringToInt(selection[i], &value)); |
+ selection_model.AddIndexToSelection(value); |
+ } |
+ selection_model.set_active(selection_model.selected_indices()[0]); |
+ model->SetSelectionFromModel(selection_model); |
+ } |
+ |
+ private: |
+ base::PropertyAccessor<int>* GetIDAccessor() { |
+ static base::PropertyAccessor<int> accessor; |
+ return &accessor; |
+ } |
+ |
+ content::TestBrowserThread browser_thread_; |
+ |
+ std::wstring test_dir_; |
+ std::wstring profile_path_; |
+}; |
+ |
+static int GetInsertionIndex(TabStripModel* tabstrip, |
+ TabContents* contents) { |
+ return tabstrip->order_controller()->DetermineInsertionIndex( |
+ contents, content::PAGE_TRANSITION_LINK, false); |
+} |
+ |
+static void InsertTabContentses(TabStripModel* tabstrip, |
+ TabContents* contents1, |
+ TabContents* contents2, |
+ TabContents* contents3) { |
+ tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents1), |
+ contents1, TabStripModel::ADD_INHERIT_GROUP); |
+ tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents2), |
+ contents2, TabStripModel::ADD_INHERIT_GROUP); |
+ tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents3), |
+ contents3, TabStripModel::ADD_INHERIT_GROUP); |
+} |
+ |
+// Test toggling between mru tabs |
+TEST_F(MRUTabControllerTest, ToggleMRUTabs) { |
+ TabStripDummyDelegate delegate(NULL); |
+ TabStripModel tabstrip(&delegate, profile()); |
+ MRUTabController controller(&tabstrip); |
+ |
+ EXPECT_TRUE(tabstrip.empty()); |
+ |
+ TabContents* opener_contents = CreateTabContents(); |
+ tabstrip.AppendTabContents(opener_contents, true); |
+ |
+ TabContents* contents1 = CreateTabContents(); |
+ TabContents* contents2 = CreateTabContents(); |
+ TabContents* contents3 = CreateTabContents(); |
+ |
+ InsertTabContentses(&tabstrip, contents1, contents2, contents3); |
+ EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(1)); |
+ EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(2)); |
+ EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(3)); |
+ |
+ EXPECT_EQ(0, tabstrip.active_index()); |
+ tabstrip.ActivateTabAt(2, true); |
+ EXPECT_EQ(2, tabstrip.active_index()); |
+ |
+ EXPECT_EQ(0, tabstrip.GetIndexOfTabContents(controller.GetPreviousMRUTab())); |
+ |
+ tabstrip.CloseAllTabs(); |
+ // TabStripModel should now be empty. |
+ EXPECT_TRUE(tabstrip.empty()); |
+} |
+ |
+// Test toggling between mru tabs |
+TEST_F(MRUTabControllerTest, PauseStackAndToggle) { |
+ TabStripDummyDelegate delegate(NULL); |
+ TabStripModel tabstrip(&delegate, profile()); |
+ MRUTabController controller(&tabstrip); |
+ |
+ EXPECT_TRUE(tabstrip.empty()); |
+ |
+ TabContents* opener_contents = CreateTabContents(); |
+ tabstrip.AppendTabContents(opener_contents, true); |
+ |
+ TabContents* contents1 = CreateTabContents(); |
+ TabContents* contents2 = CreateTabContents(); |
+ TabContents* contents3 = CreateTabContents(); |
+ |
+ InsertTabContentses(&tabstrip, contents1, contents2, contents3); |
+ EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(1)); |
+ EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(2)); |
+ EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(3)); |
+ |
+ EXPECT_EQ(0, tabstrip.active_index()); |
+ controller.PauseStackUpdates(); |
+ tabstrip.ActivateTabAt(1, true); |
+ EXPECT_EQ(1, tabstrip.active_index()); |
+ tabstrip.ActivateTabAt(2, true); |
+ EXPECT_EQ(2, tabstrip.active_index()); |
+ tabstrip.ActivateTabAt(3, true); |
+ EXPECT_EQ(3, tabstrip.active_index()); |
+ |
+ // Commit the active tab changes now. |
+ controller.CommitActiveTabChanges(); |
+ tabstrip.ActivateTabAt(0, true); |
+ EXPECT_EQ(0, tabstrip.active_index()); |
+ |
+ // Previous MRU tab would be 3 |
+ EXPECT_EQ(3, tabstrip.GetIndexOfTabContents(controller.GetPreviousMRUTab())); |
+ |
+ tabstrip.CloseAllTabs(); |
+ // TabStripModel should now be empty. |
+ EXPECT_TRUE(tabstrip.empty()); |
+} |