1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/defaults.h"
18 #include "chrome/browser/extensions/tab_helper.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_tabstrip.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
24 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
25 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "components/web_modal/popup_manager.h"
30 #include "components/web_modal/web_contents_modal_dialog_manager.h"
31 #include "content/public/browser/navigation_controller.h"
32 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/render_process_host.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/browser/web_contents_observer.h"
36 #include "extensions/common/extension.h"
37 #include "testing/gtest/include/gtest/gtest.h"
39 using content::SiteInstance
;
40 using content::WebContents
;
41 using extensions::Extension
;
45 // Class used to delete a WebContents and TabStripModel when another WebContents
47 class DeleteWebContentsOnDestroyedObserver
48 : public content::WebContentsObserver
{
50 // When |source| is deleted both |tab_to_delete| and |tab_strip| are deleted.
51 // |tab_to_delete| and |tab_strip| may be NULL.
52 DeleteWebContentsOnDestroyedObserver(WebContents
* source
,
53 WebContents
* tab_to_delete
,
54 TabStripModel
* tab_strip
)
55 : WebContentsObserver(source
),
56 tab_to_delete_(tab_to_delete
),
57 tab_strip_(tab_strip
) {
60 void WebContentsDestroyed() override
{
61 WebContents
* tab_to_delete
= tab_to_delete_
;
62 tab_to_delete_
= NULL
;
63 TabStripModel
* tab_strip_to_delete
= tab_strip_
;
66 delete tab_strip_to_delete
;
70 WebContents
* tab_to_delete_
;
71 TabStripModel
* tab_strip_
;
73 DISALLOW_COPY_AND_ASSIGN(DeleteWebContentsOnDestroyedObserver
);
76 class TabStripDummyDelegate
: public TestTabStripModelDelegate
{
78 TabStripDummyDelegate() : run_unload_(false) {}
79 ~TabStripDummyDelegate() override
{}
81 void set_run_unload_listener(bool value
) { run_unload_
= value
; }
83 bool RunUnloadListenerBeforeClosing(WebContents
* contents
) override
{
88 // Whether to report that we need to run an unload listener before closing.
91 DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate
);
94 const char kTabStripModelTestIDUserDataKey
[] = "TabStripModelTestIDUserData";
96 class TabStripModelTestIDUserData
: public base::SupportsUserData::Data
{
98 explicit TabStripModelTestIDUserData(int id
) : id_(id
) {}
99 ~TabStripModelTestIDUserData() override
{}
100 int id() { return id_
; }
106 class DummySingleWebContentsDialogManager
107 : public web_modal::SingleWebContentsDialogManager
{
109 explicit DummySingleWebContentsDialogManager(
110 gfx::NativeWindow dialog
,
111 web_modal::SingleWebContentsDialogManagerDelegate
* delegate
)
112 : delegate_(delegate
),
114 ~DummySingleWebContentsDialogManager() override
{}
116 void Show() override
{}
117 void Hide() override
{}
118 void Close() override
{ delegate_
->WillClose(dialog_
); }
119 void Focus() override
{}
120 void Pulse() override
{}
121 void HostChanged(web_modal::WebContentsModalDialogHost
* new_host
) override
{}
122 gfx::NativeWindow
dialog() override
{ return dialog_
; }
125 web_modal::SingleWebContentsDialogManagerDelegate
* delegate_
;
126 gfx::NativeWindow dialog_
;
128 DISALLOW_COPY_AND_ASSIGN(DummySingleWebContentsDialogManager
);
131 // Test Browser-like class for TabStripModelTest.TabBlockedState.
132 class TabBlockedStateTestBrowser
133 : public TabStripModelObserver
,
134 public web_modal::WebContentsModalDialogManagerDelegate
{
136 explicit TabBlockedStateTestBrowser(TabStripModel
* tab_strip_model
)
137 : tab_strip_model_(tab_strip_model
) {
138 tab_strip_model_
->AddObserver(this);
141 ~TabBlockedStateTestBrowser() override
{
142 tab_strip_model_
->RemoveObserver(this);
146 // TabStripModelObserver
147 void TabInsertedAt(WebContents
* contents
,
149 bool foreground
) override
{
150 web_modal::WebContentsModalDialogManager
* manager
=
151 web_modal::WebContentsModalDialogManager::FromWebContents(contents
);
153 manager
->SetDelegate(this);
156 // WebContentsModalDialogManagerDelegate
157 void SetWebContentsBlocked(content::WebContents
* contents
,
158 bool blocked
) override
{
159 int index
= tab_strip_model_
->GetIndexOfWebContents(contents
);
161 tab_strip_model_
->SetTabBlocked(index
, blocked
);
164 TabStripModel
* tab_strip_model_
;
166 DISALLOW_COPY_AND_ASSIGN(TabBlockedStateTestBrowser
);
171 class TabStripModelTest
: public ChromeRenderViewHostTestHarness
{
173 WebContents
* CreateWebContents() {
174 return WebContents::Create(WebContents::CreateParams(profile()));
177 WebContents
* CreateWebContentsWithSharedRPH(WebContents
* web_contents
) {
178 WebContents::CreateParams
create_params(
179 profile(), web_contents
->GetRenderViewHost()->GetSiteInstance());
180 WebContents
* retval
= WebContents::Create(create_params
);
181 EXPECT_EQ(retval
->GetRenderProcessHost(),
182 web_contents
->GetRenderProcessHost());
186 WebContents
* CreateWebContentsWithID(int id
) {
187 WebContents
* contents
= CreateWebContents();
192 // Sets the id of the specified contents.
193 void SetID(WebContents
* contents
, int id
) {
194 contents
->SetUserData(&kTabStripModelTestIDUserDataKey
,
195 new TabStripModelTestIDUserData(id
));
198 // Returns the id of the specified contents.
199 int GetID(WebContents
* contents
) {
200 TabStripModelTestIDUserData
* user_data
=
201 static_cast<TabStripModelTestIDUserData
*>(
202 contents
->GetUserData(&kTabStripModelTestIDUserDataKey
));
204 return user_data
? user_data
->id() : -1;
207 // Returns the state of the given tab strip as a string. The state consists
208 // of the ID of each web contents followed by a 'p' if pinned. For example,
209 // if the model consists of two tabs with ids 2 and 1, with the first
210 // tab pinned, this returns "2p 1".
211 std::string
GetTabStripStateString(const TabStripModel
& model
) {
213 for (int i
= 0; i
< model
.count(); ++i
) {
217 actual
+= base::IntToString(GetID(model
.GetWebContentsAt(i
)));
219 if (model
.IsAppTab(i
))
222 if (model
.IsTabPinned(i
))
228 std::string
GetIndicesClosedByCommandAsString(
229 const TabStripModel
& model
,
231 TabStripModel::ContextMenuCommand id
) const {
232 std::vector
<int> indices
= model
.GetIndicesClosedByCommand(index
, id
);
234 for (size_t i
= 0; i
< indices
.size(); ++i
) {
237 result
+= base::IntToString(indices
[i
]);
242 void PrepareTabstripForSelectionTest(TabStripModel
* model
,
245 const std::string
& selected_tabs
) {
246 for (int i
= 0; i
< tab_count
; ++i
)
247 model
->AppendWebContents(CreateWebContentsWithID(i
), true);
248 for (int i
= 0; i
< pinned_count
; ++i
)
249 model
->SetTabPinned(i
, true);
251 ui::ListSelectionModel selection_model
;
252 std::vector
<std::string
> selection
;
253 base::SplitStringAlongWhitespace(selected_tabs
, &selection
);
254 for (size_t i
= 0; i
< selection
.size(); ++i
) {
256 ASSERT_TRUE(base::StringToInt(selection
[i
], &value
));
257 selection_model
.AddIndexToSelection(value
);
259 selection_model
.set_active(selection_model
.selected_indices()[0]);
260 model
->SetSelectionFromModel(selection_model
);
264 class MockTabStripModelObserver
: public TabStripModelObserver
{
266 explicit MockTabStripModelObserver(TabStripModel
* model
)
270 ~MockTabStripModelObserver() override
{}
272 enum TabStripModelObserverAction
{
288 State(WebContents
* a_dst_contents
,
290 TabStripModelObserverAction a_action
)
291 : src_contents(NULL
),
292 dst_contents(a_dst_contents
),
294 dst_index(a_dst_index
),
295 change_reason(CHANGE_REASON_NONE
),
300 WebContents
* src_contents
;
301 WebContents
* dst_contents
;
306 TabStripModelObserverAction action
;
309 int GetStateCount() const {
310 return static_cast<int>(states_
.size());
313 // Returns (by way of parameters) the number of state's with CLOSE_ALL and
314 // CLOSE_ALL_CANCELED.
315 void GetCloseCounts(int* close_all_count
,
316 int* close_all_canceled_count
) {
317 *close_all_count
= *close_all_canceled_count
= 0;
318 for (int i
= 0; i
< GetStateCount(); ++i
) {
319 switch (GetStateAt(i
).action
) {
321 (*close_all_count
)++;
323 case CLOSE_ALL_CANCELED
:
324 (*close_all_canceled_count
)++;
332 const State
& GetStateAt(int index
) const {
333 DCHECK(index
>= 0 && index
< GetStateCount());
334 return states_
[index
];
337 bool StateEquals(int index
, const State
& state
) {
338 const State
& s
= GetStateAt(index
);
339 return (s
.src_contents
== state
.src_contents
&&
340 s
.dst_contents
== state
.dst_contents
&&
341 s
.src_index
== state
.src_index
&&
342 s
.dst_index
== state
.dst_index
&&
343 s
.change_reason
== state
.change_reason
&&
344 s
.foreground
== state
.foreground
&&
345 s
.action
== state
.action
);
348 // TabStripModelObserver implementation:
349 void TabInsertedAt(WebContents
* contents
,
351 bool foreground
) override
{
353 State
s(contents
, index
, INSERT
);
354 s
.foreground
= foreground
;
355 states_
.push_back(s
);
357 void ActiveTabChanged(WebContents
* old_contents
,
358 WebContents
* new_contents
,
360 int reason
) override
{
361 State
s(new_contents
, index
, ACTIVATE
);
362 s
.src_contents
= old_contents
;
363 s
.change_reason
= reason
;
364 states_
.push_back(s
);
366 void TabSelectionChanged(TabStripModel
* tab_strip_model
,
367 const ui::ListSelectionModel
& old_model
) override
{
368 State
s(model()->GetActiveWebContents(), model()->active_index(), SELECT
);
369 s
.src_contents
= model()->GetWebContentsAt(old_model
.active());
370 s
.src_index
= old_model
.active();
371 states_
.push_back(s
);
373 void TabMoved(WebContents
* contents
, int from_index
, int to_index
) override
{
374 State
s(contents
, to_index
, MOVE
);
375 s
.src_index
= from_index
;
376 states_
.push_back(s
);
379 void TabClosingAt(TabStripModel
* tab_strip_model
,
380 WebContents
* contents
,
381 int index
) override
{
382 states_
.push_back(State(contents
, index
, CLOSE
));
384 void TabDetachedAt(WebContents
* contents
, int index
) override
{
385 states_
.push_back(State(contents
, index
, DETACH
));
387 void TabDeactivated(WebContents
* contents
) override
{
388 states_
.push_back(State(contents
, model()->active_index(), DEACTIVATE
));
390 void TabChangedAt(WebContents
* contents
,
392 TabChangeType change_type
) override
{
393 states_
.push_back(State(contents
, index
, CHANGE
));
395 void TabReplacedAt(TabStripModel
* tab_strip_model
,
396 WebContents
* old_contents
,
397 WebContents
* new_contents
,
398 int index
) override
{
399 State
s(new_contents
, index
, REPLACED
);
400 s
.src_contents
= old_contents
;
401 states_
.push_back(s
);
403 void TabPinnedStateChanged(WebContents
* contents
, int index
) override
{
404 states_
.push_back(State(contents
, index
, PINNED
));
406 void TabStripEmpty() override
{ empty_
= true; }
407 void WillCloseAllTabs() override
{
408 states_
.push_back(State(NULL
, -1, CLOSE_ALL
));
410 void CloseAllTabsCanceled() override
{
411 states_
.push_back(State(NULL
, -1, CLOSE_ALL_CANCELED
));
413 void TabStripModelDeleted() override
{ deleted_
= true; }
419 bool empty() const { return empty_
; }
420 bool deleted() const { return deleted_
; }
421 TabStripModel
* model() { return model_
; }
424 std::vector
<State
> states_
;
428 TabStripModel
* model_
;
430 DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver
);
433 TEST_F(TabStripModelTest
, TestBasicAPI
) {
434 TabStripDummyDelegate delegate
;
435 TabStripModel
tabstrip(&delegate
, profile());
436 MockTabStripModelObserver
observer(&tabstrip
);
437 tabstrip
.AddObserver(&observer
);
439 EXPECT_TRUE(tabstrip
.empty());
441 typedef MockTabStripModelObserver::State State
;
443 WebContents
* contents1
= CreateWebContentsWithID(1);
445 // Note! The ordering of these tests is important, each subsequent test
446 // builds on the state established in the previous. This is important if you
447 // ever insert tests rather than append.
449 // Test AppendWebContents, ContainsIndex
451 EXPECT_FALSE(tabstrip
.ContainsIndex(0));
452 tabstrip
.AppendWebContents(contents1
, true);
453 EXPECT_TRUE(tabstrip
.ContainsIndex(0));
454 EXPECT_EQ(1, tabstrip
.count());
455 EXPECT_EQ(3, observer
.GetStateCount());
456 State
s1(contents1
, 0, MockTabStripModelObserver::INSERT
);
457 s1
.foreground
= true;
458 EXPECT_TRUE(observer
.StateEquals(0, s1
));
459 State
s2(contents1
, 0, MockTabStripModelObserver::ACTIVATE
);
460 EXPECT_TRUE(observer
.StateEquals(1, s2
));
461 State
s3(contents1
, 0, MockTabStripModelObserver::SELECT
);
462 s3
.src_contents
= NULL
;
463 s3
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
464 EXPECT_TRUE(observer
.StateEquals(2, s3
));
465 observer
.ClearStates();
467 EXPECT_EQ("1", GetTabStripStateString(tabstrip
));
469 // Test InsertWebContentsAt, foreground tab.
470 WebContents
* contents2
= CreateWebContentsWithID(2);
472 tabstrip
.InsertWebContentsAt(1, contents2
, TabStripModel::ADD_ACTIVE
);
474 EXPECT_EQ(2, tabstrip
.count());
475 EXPECT_EQ(4, observer
.GetStateCount());
476 State
s1(contents2
, 1, MockTabStripModelObserver::INSERT
);
477 s1
.foreground
= true;
478 EXPECT_TRUE(observer
.StateEquals(0, s1
));
479 State
s2(contents1
, 0, MockTabStripModelObserver::DEACTIVATE
);
480 EXPECT_TRUE(observer
.StateEquals(1, s2
));
481 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
482 s3
.src_contents
= contents1
;
483 EXPECT_TRUE(observer
.StateEquals(2, s3
));
484 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
485 s4
.src_contents
= contents1
;
487 EXPECT_TRUE(observer
.StateEquals(3, s4
));
488 observer
.ClearStates();
490 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
492 // Test InsertWebContentsAt, background tab.
493 WebContents
* contents3
= CreateWebContentsWithID(3);
495 tabstrip
.InsertWebContentsAt(2, contents3
, TabStripModel::ADD_NONE
);
497 EXPECT_EQ(3, tabstrip
.count());
498 EXPECT_EQ(1, observer
.GetStateCount());
499 State
s1(contents3
, 2, MockTabStripModelObserver::INSERT
);
500 s1
.foreground
= false;
501 EXPECT_TRUE(observer
.StateEquals(0, s1
));
502 observer
.ClearStates();
504 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
506 // Test ActivateTabAt
508 tabstrip
.ActivateTabAt(2, true);
509 EXPECT_EQ(3, observer
.GetStateCount());
510 State
s1(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
511 EXPECT_TRUE(observer
.StateEquals(0, s1
));
512 State
s2(contents3
, 2, MockTabStripModelObserver::ACTIVATE
);
513 s2
.src_contents
= contents2
;
514 s2
.change_reason
= TabStripModelObserver::CHANGE_REASON_USER_GESTURE
;
515 EXPECT_TRUE(observer
.StateEquals(1, s2
));
516 State
s3(contents3
, 2, MockTabStripModelObserver::SELECT
);
517 s3
.src_contents
= contents2
;
519 EXPECT_TRUE(observer
.StateEquals(2, s3
));
520 observer
.ClearStates();
522 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
524 // Test DetachWebContentsAt
527 WebContents
* detached
= tabstrip
.DetachWebContentsAt(2);
528 // ... and append again because we want this for later.
529 tabstrip
.AppendWebContents(detached
, true);
530 EXPECT_EQ(8, observer
.GetStateCount());
531 State
s1(detached
, 2, MockTabStripModelObserver::DETACH
);
532 EXPECT_TRUE(observer
.StateEquals(0, s1
));
533 State
s2(detached
, ui::ListSelectionModel::kUnselectedIndex
,
534 MockTabStripModelObserver::DEACTIVATE
);
535 EXPECT_TRUE(observer
.StateEquals(1, s2
));
536 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
537 s3
.src_contents
= contents3
;
538 s3
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
539 EXPECT_TRUE(observer
.StateEquals(2, s3
));
540 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
541 s4
.src_contents
= NULL
;
542 s4
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
543 EXPECT_TRUE(observer
.StateEquals(3, s4
));
544 State
s5(detached
, 2, MockTabStripModelObserver::INSERT
);
545 s5
.foreground
= true;
546 EXPECT_TRUE(observer
.StateEquals(4, s5
));
547 State
s6(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
548 EXPECT_TRUE(observer
.StateEquals(5, s6
));
549 State
s7(detached
, 2, MockTabStripModelObserver::ACTIVATE
);
550 s7
.src_contents
= contents2
;
551 s7
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
552 EXPECT_TRUE(observer
.StateEquals(6, s7
));
553 State
s8(detached
, 2, MockTabStripModelObserver::SELECT
);
554 s8
.src_contents
= contents2
;
556 EXPECT_TRUE(observer
.StateEquals(7, s8
));
557 observer
.ClearStates();
559 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
561 // Test CloseWebContentsAt
563 EXPECT_TRUE(tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
));
564 EXPECT_EQ(2, tabstrip
.count());
566 EXPECT_EQ(5, observer
.GetStateCount());
567 State
s1(contents3
, 2, MockTabStripModelObserver::CLOSE
);
568 EXPECT_TRUE(observer
.StateEquals(0, s1
));
569 State
s2(contents3
, 2, MockTabStripModelObserver::DETACH
);
570 EXPECT_TRUE(observer
.StateEquals(1, s2
));
571 State
s3(contents3
, ui::ListSelectionModel::kUnselectedIndex
,
572 MockTabStripModelObserver::DEACTIVATE
);
573 EXPECT_TRUE(observer
.StateEquals(2, s3
));
574 State
s4(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
575 s4
.src_contents
= contents3
;
576 s4
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
577 EXPECT_TRUE(observer
.StateEquals(3, s4
));
578 State
s5(contents2
, 1, MockTabStripModelObserver::SELECT
);
579 s5
.src_contents
= NULL
;
580 s5
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
581 EXPECT_TRUE(observer
.StateEquals(4, s5
));
582 observer
.ClearStates();
584 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
586 // Test MoveWebContentsAt, select_after_move == true
588 tabstrip
.MoveWebContentsAt(1, 0, true);
590 EXPECT_EQ(1, observer
.GetStateCount());
591 State
s1(contents2
, 0, MockTabStripModelObserver::MOVE
);
593 EXPECT_TRUE(observer
.StateEquals(0, s1
));
594 EXPECT_EQ(0, tabstrip
.active_index());
595 observer
.ClearStates();
597 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
599 // Test MoveWebContentsAt, select_after_move == false
601 tabstrip
.MoveWebContentsAt(1, 0, false);
602 EXPECT_EQ(1, observer
.GetStateCount());
603 State
s1(contents1
, 0, MockTabStripModelObserver::MOVE
);
605 EXPECT_TRUE(observer
.StateEquals(0, s1
));
606 EXPECT_EQ(1, tabstrip
.active_index());
608 tabstrip
.MoveWebContentsAt(0, 1, false);
609 observer
.ClearStates();
611 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
615 EXPECT_EQ(contents2
, tabstrip
.GetActiveWebContents());
616 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(0));
617 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
618 EXPECT_EQ(0, tabstrip
.GetIndexOfWebContents(contents2
));
619 EXPECT_EQ(1, tabstrip
.GetIndexOfWebContents(contents1
));
622 // Test UpdateWebContentsStateAt
624 tabstrip
.UpdateWebContentsStateAt(0, TabStripModelObserver::ALL
);
625 EXPECT_EQ(1, observer
.GetStateCount());
626 State
s1(contents2
, 0, MockTabStripModelObserver::CHANGE
);
627 EXPECT_TRUE(observer
.StateEquals(0, s1
));
628 observer
.ClearStates();
631 // Test SelectNextTab, SelectPreviousTab, SelectLastTab
633 // Make sure the second of the two tabs is selected first...
634 tabstrip
.ActivateTabAt(1, true);
635 tabstrip
.SelectPreviousTab();
636 EXPECT_EQ(0, tabstrip
.active_index());
637 tabstrip
.SelectLastTab();
638 EXPECT_EQ(1, tabstrip
.active_index());
639 tabstrip
.SelectNextTab();
640 EXPECT_EQ(0, tabstrip
.active_index());
643 // Test CloseSelectedTabs
645 tabstrip
.CloseSelectedTabs();
646 // |CloseSelectedTabs| calls CloseWebContentsAt, we already tested that, now
647 // just verify that the count and selected index have changed
649 EXPECT_EQ(1, tabstrip
.count());
650 EXPECT_EQ(0, tabstrip
.active_index());
653 observer
.ClearStates();
654 tabstrip
.CloseAllTabs();
656 int close_all_count
= 0, close_all_canceled_count
= 0;
657 observer
.GetCloseCounts(&close_all_count
, &close_all_canceled_count
);
658 EXPECT_EQ(1, close_all_count
);
659 EXPECT_EQ(0, close_all_canceled_count
);
661 // TabStripModel should now be empty.
662 EXPECT_TRUE(tabstrip
.empty());
664 // Opener methods are tested below...
666 tabstrip
.RemoveObserver(&observer
);
669 TEST_F(TabStripModelTest
, TestBasicOpenerAPI
) {
670 TabStripDummyDelegate delegate
;
671 TabStripModel
tabstrip(&delegate
, profile());
672 EXPECT_TRUE(tabstrip
.empty());
674 // This is a basic test of opener functionality. opener is created
675 // as the first tab in the strip and then we create 5 other tabs in the
676 // background with opener set as their opener.
678 WebContents
* opener
= CreateWebContents();
679 tabstrip
.AppendWebContents(opener
, true);
680 WebContents
* contents1
= CreateWebContents();
681 WebContents
* contents2
= CreateWebContents();
682 WebContents
* contents3
= CreateWebContents();
683 WebContents
* contents4
= CreateWebContents();
684 WebContents
* contents5
= CreateWebContents();
686 // We use |InsertWebContentsAt| here instead of |AppendWebContents| so that
687 // openership relationships are preserved.
688 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents1
,
689 TabStripModel::ADD_INHERIT_GROUP
);
690 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents2
,
691 TabStripModel::ADD_INHERIT_GROUP
);
692 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents3
,
693 TabStripModel::ADD_INHERIT_GROUP
);
694 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents4
,
695 TabStripModel::ADD_INHERIT_GROUP
);
696 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents5
,
697 TabStripModel::ADD_INHERIT_GROUP
);
699 // All the tabs should have the same opener.
700 for (int i
= 1; i
< tabstrip
.count(); ++i
)
701 EXPECT_EQ(opener
, tabstrip
.GetOpenerOfWebContentsAt(i
));
703 // If there is a next adjacent item, then the index should be of that item.
704 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
705 // If the last tab in the group is closed, the preceding tab in the same
706 // group should be selected.
707 EXPECT_EQ(4, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
709 // Tests the method that finds the last tab opened by the same opener in the
710 // strip (this is the insertion index for the next background tab for the
711 // specified opener).
712 EXPECT_EQ(5, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
714 // For a tab that has opened no other tabs, the return value should always be
717 tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents1
, 3, false));
719 tabstrip
.GetIndexOfLastWebContentsOpenedBy(contents1
, 3));
721 // ForgetAllOpeners should destroy all opener relationships.
722 tabstrip
.ForgetAllOpeners();
723 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
724 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
725 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
727 // Specify the last tab as the opener of the others.
728 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
729 tabstrip
.SetOpenerOfWebContentsAt(i
, contents5
);
731 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
732 EXPECT_EQ(contents5
, tabstrip
.GetOpenerOfWebContentsAt(i
));
734 // If there is a next adjacent item, then the index should be of that item.
735 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 1, false));
737 // If the last tab in the group is closed, the preceding tab in the same
738 // group should be selected.
739 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 4, false));
741 tabstrip
.CloseAllTabs();
742 EXPECT_TRUE(tabstrip
.empty());
745 static int GetInsertionIndex(TabStripModel
* tabstrip
) {
746 return tabstrip
->order_controller()->DetermineInsertionIndex(
747 ui::PAGE_TRANSITION_LINK
, false);
750 static void InsertWebContentses(TabStripModel
* tabstrip
,
751 WebContents
* contents1
,
752 WebContents
* contents2
,
753 WebContents
* contents3
) {
754 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
756 TabStripModel::ADD_INHERIT_GROUP
);
757 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
759 TabStripModel::ADD_INHERIT_GROUP
);
760 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
762 TabStripModel::ADD_INHERIT_GROUP
);
765 // Tests opening background tabs.
766 TEST_F(TabStripModelTest
, TestLTRInsertionOptions
) {
767 TabStripDummyDelegate delegate
;
768 TabStripModel
tabstrip(&delegate
, profile());
769 EXPECT_TRUE(tabstrip
.empty());
771 WebContents
* opener
= CreateWebContents();
772 tabstrip
.AppendWebContents(opener
, true);
774 WebContents
* contents1
= CreateWebContents();
775 WebContents
* contents2
= CreateWebContents();
776 WebContents
* contents3
= CreateWebContents();
779 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
780 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
781 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
782 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
784 tabstrip
.CloseAllTabs();
785 EXPECT_TRUE(tabstrip
.empty());
788 // This test constructs a tabstrip, and then simulates loading several tabs in
789 // the background from link clicks on the first tab. Then it simulates opening
790 // a new tab from the first tab in the foreground via a link click, verifies
791 // that this tab is opened adjacent to the opener, then closes it.
792 // Finally it tests that a tab opened for some non-link purpose opens at the
793 // end of the strip, not bundled to any existing context.
794 TEST_F(TabStripModelTest
, TestInsertionIndexDetermination
) {
795 TabStripDummyDelegate delegate
;
796 TabStripModel
tabstrip(&delegate
, profile());
797 EXPECT_TRUE(tabstrip
.empty());
799 WebContents
* opener
= CreateWebContents();
800 tabstrip
.AppendWebContents(opener
, true);
802 // Open some other random unrelated tab in the background to monkey with our
804 WebContents
* other
= CreateWebContents();
805 tabstrip
.AppendWebContents(other
, false);
807 WebContents
* contents1
= CreateWebContents();
808 WebContents
* contents2
= CreateWebContents();
809 WebContents
* contents3
= CreateWebContents();
811 // Start by testing LTR.
812 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
813 EXPECT_EQ(opener
, tabstrip
.GetWebContentsAt(0));
814 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
815 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
816 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
817 EXPECT_EQ(other
, tabstrip
.GetWebContentsAt(4));
819 // The opener API should work...
820 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
821 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
822 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
824 // Now open a foreground tab from a link. It should be opened adjacent to the
826 WebContents
* fg_link_contents
= CreateWebContents();
827 int insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
828 ui::PAGE_TRANSITION_LINK
, true);
829 EXPECT_EQ(1, insert_index
);
830 tabstrip
.InsertWebContentsAt(insert_index
, fg_link_contents
,
831 TabStripModel::ADD_ACTIVE
|
832 TabStripModel::ADD_INHERIT_GROUP
);
833 EXPECT_EQ(1, tabstrip
.active_index());
834 EXPECT_EQ(fg_link_contents
, tabstrip
.GetActiveWebContents());
836 // Now close this contents. The selection should move to the opener contents.
837 tabstrip
.CloseSelectedTabs();
838 EXPECT_EQ(0, tabstrip
.active_index());
840 // Now open a new empty tab. It should open at the end of the strip.
841 WebContents
* fg_nonlink_contents
= CreateWebContents();
842 insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
843 ui::PAGE_TRANSITION_AUTO_BOOKMARK
, true);
844 EXPECT_EQ(tabstrip
.count(), insert_index
);
845 // We break the opener relationship...
846 tabstrip
.InsertWebContentsAt(insert_index
,
848 TabStripModel::ADD_NONE
);
849 // Now select it, so that user_gesture == true causes the opener relationship
850 // to be forgotten...
851 tabstrip
.ActivateTabAt(tabstrip
.count() - 1, true);
852 EXPECT_EQ(tabstrip
.count() - 1, tabstrip
.active_index());
853 EXPECT_EQ(fg_nonlink_contents
, tabstrip
.GetActiveWebContents());
855 // Verify that all opener relationships are forgotten.
856 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
857 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
858 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
859 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
861 tabstrip
.CloseAllTabs();
862 EXPECT_TRUE(tabstrip
.empty());
865 // Tests that non-adjacent tabs with an opener are ignored when deciding where
867 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationAfterDragged
) {
868 TabStripDummyDelegate delegate
;
869 TabStripModel
tabstrip(&delegate
, profile());
870 EXPECT_TRUE(tabstrip
.empty());
872 // Start with three tabs, of which the first is active.
873 WebContents
* opener1
= CreateWebContentsWithID(1);
874 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
875 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
876 tabstrip
.AppendWebContents(CreateWebContentsWithID(3), false);
877 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
878 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
879 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
881 // Open a link in a new background tab.
882 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
883 CreateWebContentsWithID(11),
884 TabStripModel::ADD_INHERIT_GROUP
);
885 EXPECT_EQ("1 11 2 3", GetTabStripStateString(tabstrip
));
886 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
887 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
889 // Drag that tab (which activates it) one to the right.
890 tabstrip
.MoveWebContentsAt(1, 2, true /* select_after_move */);
891 EXPECT_EQ("1 2 11 3", GetTabStripStateString(tabstrip
));
892 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
893 // It should no longer be counted by GetIndexOfLastWebContentsOpenedBy,
894 // since there is a tab in between, even though its opener is unchanged.
895 // TODO(johnme): Maybe its opener should be reset when it's dragged away.
896 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
897 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(2));
899 // Activate the parent tab again.
900 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
901 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
903 // Open another link in a new background tab.
904 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
905 CreateWebContentsWithID(12),
906 TabStripModel::ADD_INHERIT_GROUP
);
907 // Tab 12 should be next to 1, and considered opened by it.
908 EXPECT_EQ("1 12 2 11 3", GetTabStripStateString(tabstrip
));
909 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
910 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
912 tabstrip
.CloseAllTabs();
913 EXPECT_TRUE(tabstrip
.empty());
916 // Tests that grandchild tabs are considered to be opened by their grandparent
917 // tab when deciding where to position tabs.
918 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationNestedOpener
) {
919 TabStripDummyDelegate delegate
;
920 TabStripModel
tabstrip(&delegate
, profile());
921 EXPECT_TRUE(tabstrip
.empty());
923 // Start with two tabs, of which the first is active:
924 WebContents
* opener1
= CreateWebContentsWithID(1);
925 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
926 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
927 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
928 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
929 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
931 // Open a link in a new background child tab.
932 WebContents
* child11
= CreateWebContentsWithID(11);
933 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
935 TabStripModel::ADD_INHERIT_GROUP
);
936 EXPECT_EQ("1 11 2", GetTabStripStateString(tabstrip
));
937 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
938 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
940 // Activate the child tab:
941 tabstrip
.ActivateTabAt(1, true /* user_gesture */);
942 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
944 // Open a link in a new background grandchild tab.
945 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
946 CreateWebContentsWithID(111),
947 TabStripModel::ADD_INHERIT_GROUP
);
948 EXPECT_EQ("1 11 111 2", GetTabStripStateString(tabstrip
));
949 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
950 // The grandchild tab should be counted by GetIndexOfLastWebContentsOpenedBy
951 // as opened by both its parent (child11) and grandparent (opener1).
952 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
953 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
955 // Activate the parent tab again:
956 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
957 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
959 // Open another link in a new background child tab (a sibling of child11).
960 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
961 CreateWebContentsWithID(12),
962 TabStripModel::ADD_INHERIT_GROUP
);
963 EXPECT_EQ("1 11 111 12 2", GetTabStripStateString(tabstrip
));
964 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
965 // opener1 has three adjacent descendants (11, 111, 12)
966 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
967 // child11 has only one adjacent descendant (111)
968 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
970 // Closing a tab should cause its children to inherit the tab's opener.
971 EXPECT_EQ(true, tabstrip
.CloseWebContentsAt(
973 TabStripModel::CLOSE_USER_GESTURE
|
974 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
));
975 EXPECT_EQ("1 111 12 2", GetTabStripStateString(tabstrip
));
976 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
977 // opener1 is now the opener of 111, so has two adjacent descendants (111, 12)
978 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(1));
979 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
981 tabstrip
.CloseAllTabs();
982 EXPECT_TRUE(tabstrip
.empty());
985 // Tests that selection is shifted to the correct tab when a tab is closed.
986 // If a tab is in the background when it is closed, the selection does not
988 // If a tab is in the foreground (selected),
989 // If that tab does not have an opener, selection shifts to the right.
990 // If the tab has an opener,
991 // The next tab (scanning LTR) in the entire strip that has the same opener
993 // If there are no other tabs that have the same opener,
994 // The opener is selected
996 TEST_F(TabStripModelTest
, TestSelectOnClose
) {
997 TabStripDummyDelegate delegate
;
998 TabStripModel
tabstrip(&delegate
, profile());
999 EXPECT_TRUE(tabstrip
.empty());
1001 WebContents
* opener
= CreateWebContents();
1002 tabstrip
.AppendWebContents(opener
, true);
1004 WebContents
* contents1
= CreateWebContents();
1005 WebContents
* contents2
= CreateWebContents();
1006 WebContents
* contents3
= CreateWebContents();
1008 // Note that we use Detach instead of Close throughout this test to avoid
1009 // having to keep reconstructing these WebContentses.
1011 // First test that closing tabs that are in the background doesn't adjust the
1012 // current selection.
1013 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1014 EXPECT_EQ(0, tabstrip
.active_index());
1016 tabstrip
.DetachWebContentsAt(1);
1017 EXPECT_EQ(0, tabstrip
.active_index());
1019 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1020 tabstrip
.DetachWebContentsAt(i
);
1022 // Now test that when a tab doesn't have an opener, selection shifts to the
1023 // right when the tab is closed.
1024 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1025 EXPECT_EQ(0, tabstrip
.active_index());
1027 tabstrip
.ForgetAllOpeners();
1028 tabstrip
.ActivateTabAt(1, true);
1029 EXPECT_EQ(1, tabstrip
.active_index());
1030 tabstrip
.DetachWebContentsAt(1);
1031 EXPECT_EQ(1, tabstrip
.active_index());
1032 tabstrip
.DetachWebContentsAt(1);
1033 EXPECT_EQ(1, tabstrip
.active_index());
1034 tabstrip
.DetachWebContentsAt(1);
1035 EXPECT_EQ(0, tabstrip
.active_index());
1037 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1038 tabstrip
.DetachWebContentsAt(i
);
1040 // Now test that when a tab does have an opener, it selects the next tab
1041 // opened by the same opener scanning LTR when it is closed.
1042 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1043 EXPECT_EQ(0, tabstrip
.active_index());
1044 tabstrip
.ActivateTabAt(2, false);
1045 EXPECT_EQ(2, tabstrip
.active_index());
1046 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1047 EXPECT_EQ(2, tabstrip
.active_index());
1048 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1049 EXPECT_EQ(1, tabstrip
.active_index());
1050 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1051 EXPECT_EQ(0, tabstrip
.active_index());
1052 // Finally test that when a tab has no "siblings" that the opener is
1054 WebContents
* other_contents
= CreateWebContents();
1055 tabstrip
.InsertWebContentsAt(1, other_contents
,
1056 TabStripModel::ADD_NONE
);
1057 EXPECT_EQ(2, tabstrip
.count());
1058 WebContents
* opened_contents
= CreateWebContents();
1059 tabstrip
.InsertWebContentsAt(2, opened_contents
,
1060 TabStripModel::ADD_ACTIVE
|
1061 TabStripModel::ADD_INHERIT_GROUP
);
1062 EXPECT_EQ(2, tabstrip
.active_index());
1063 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1064 EXPECT_EQ(0, tabstrip
.active_index());
1066 tabstrip
.CloseAllTabs();
1067 EXPECT_TRUE(tabstrip
.empty());
1070 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1072 TEST_F(TabStripModelTest
, CommandCloseTab
) {
1073 TabStripDummyDelegate delegate
;
1074 TabStripModel
tabstrip(&delegate
, profile());
1075 EXPECT_TRUE(tabstrip
.empty());
1077 // Make sure can_close is honored.
1078 ASSERT_NO_FATAL_FAILURE(
1079 PrepareTabstripForSelectionTest(&tabstrip
, 1, 0, "0"));
1080 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1081 0, TabStripModel::CommandCloseTab
));
1082 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1083 ASSERT_TRUE(tabstrip
.empty());
1085 // Make sure close on a tab that is selected affects all the selected tabs.
1086 ASSERT_NO_FATAL_FAILURE(
1087 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1088 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1089 0, TabStripModel::CommandCloseTab
));
1090 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1091 // Should have closed tabs 0 and 1.
1092 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1094 tabstrip
.CloseAllTabs();
1095 EXPECT_TRUE(tabstrip
.empty());
1097 // Select two tabs and make close on a tab that isn't selected doesn't affect
1099 ASSERT_NO_FATAL_FAILURE(
1100 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1101 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1102 2, TabStripModel::CommandCloseTab
));
1103 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1104 // Should have closed tab 2.
1105 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1106 tabstrip
.CloseAllTabs();
1107 EXPECT_TRUE(tabstrip
.empty());
1109 // Tests with 3 tabs, one pinned, two tab selected, one of which is pinned.
1110 ASSERT_NO_FATAL_FAILURE(
1111 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1112 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1113 0, TabStripModel::CommandCloseTab
));
1114 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1115 // Should have closed tab 2.
1116 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1117 tabstrip
.CloseAllTabs();
1118 EXPECT_TRUE(tabstrip
.empty());
1121 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1122 // CommandCloseTabs.
1123 TEST_F(TabStripModelTest
, CommandCloseOtherTabs
) {
1124 TabStripDummyDelegate delegate
;
1125 TabStripModel
tabstrip(&delegate
, profile());
1126 EXPECT_TRUE(tabstrip
.empty());
1128 // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
1129 // and close two tabs.
1130 ASSERT_NO_FATAL_FAILURE(
1131 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1132 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1133 0, TabStripModel::CommandCloseOtherTabs
));
1134 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1135 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1136 tabstrip
.CloseAllTabs();
1137 EXPECT_TRUE(tabstrip
.empty());
1139 // Select two tabs, CommandCloseOtherTabs should be enabled and invoking it
1140 // with a non-selected index should close the two other tabs.
1141 ASSERT_NO_FATAL_FAILURE(
1142 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1143 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1144 2, TabStripModel::CommandCloseOtherTabs
));
1145 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1146 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1147 tabstrip
.CloseAllTabs();
1148 EXPECT_TRUE(tabstrip
.empty());
1150 // Select all, CommandCloseOtherTabs should not be enabled.
1151 ASSERT_NO_FATAL_FAILURE(
1152 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1 2"));
1153 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1154 2, TabStripModel::CommandCloseOtherTabs
));
1155 tabstrip
.CloseAllTabs();
1156 EXPECT_TRUE(tabstrip
.empty());
1158 // Three tabs, pin one, select the two non-pinned.
1159 ASSERT_NO_FATAL_FAILURE(
1160 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1 2"));
1161 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1162 1, TabStripModel::CommandCloseOtherTabs
));
1163 // If we don't pass in the pinned index, the command should be enabled.
1164 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1165 0, TabStripModel::CommandCloseOtherTabs
));
1166 tabstrip
.CloseAllTabs();
1167 EXPECT_TRUE(tabstrip
.empty());
1169 // 3 tabs, one pinned.
1170 ASSERT_NO_FATAL_FAILURE(
1171 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1"));
1172 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1173 1, TabStripModel::CommandCloseOtherTabs
));
1174 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1175 0, TabStripModel::CommandCloseOtherTabs
));
1176 tabstrip
.ExecuteContextMenuCommand(1, TabStripModel::CommandCloseOtherTabs
);
1177 // The pinned tab shouldn't be closed.
1178 EXPECT_EQ("0p 1", GetTabStripStateString(tabstrip
));
1179 tabstrip
.CloseAllTabs();
1180 EXPECT_TRUE(tabstrip
.empty());
1183 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1184 // CommandCloseTabsToRight.
1185 TEST_F(TabStripModelTest
, CommandCloseTabsToRight
) {
1186 TabStripDummyDelegate delegate
;
1187 TabStripModel
tabstrip(&delegate
, profile());
1188 EXPECT_TRUE(tabstrip
.empty());
1190 // Create three tabs, select last two tabs, CommandCloseTabsToRight should
1191 // only be enabled for the first tab.
1192 ASSERT_NO_FATAL_FAILURE(
1193 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "1 2"));
1194 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1195 0, TabStripModel::CommandCloseTabsToRight
));
1196 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1197 1, TabStripModel::CommandCloseTabsToRight
));
1198 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1199 2, TabStripModel::CommandCloseTabsToRight
));
1200 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1201 EXPECT_EQ("0", GetTabStripStateString(tabstrip
));
1202 tabstrip
.CloseAllTabs();
1203 EXPECT_TRUE(tabstrip
.empty());
1206 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1207 // CommandTogglePinned.
1208 TEST_F(TabStripModelTest
, CommandTogglePinned
) {
1209 TabStripDummyDelegate delegate
;
1210 TabStripModel
tabstrip(&delegate
, profile());
1211 EXPECT_TRUE(tabstrip
.empty());
1213 // Create three tabs with one pinned, pin the first two.
1214 ASSERT_NO_FATAL_FAILURE(
1215 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1216 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1217 0, TabStripModel::CommandTogglePinned
));
1218 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1219 1, TabStripModel::CommandTogglePinned
));
1220 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1221 2, TabStripModel::CommandTogglePinned
));
1222 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1223 EXPECT_EQ("0p 1p 2", GetTabStripStateString(tabstrip
));
1225 // Execute CommandTogglePinned again, this should unpin.
1226 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1227 EXPECT_EQ("0 1 2", GetTabStripStateString(tabstrip
));
1230 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandTogglePinned
);
1231 EXPECT_EQ("2p 0 1", GetTabStripStateString(tabstrip
));
1233 tabstrip
.CloseAllTabs();
1234 EXPECT_TRUE(tabstrip
.empty());
1237 // Tests the following context menu commands:
1239 // - Close Other Tabs
1240 // - Close Tabs To Right
1241 TEST_F(TabStripModelTest
, TestContextMenuCloseCommands
) {
1242 TabStripDummyDelegate delegate
;
1243 TabStripModel
tabstrip(&delegate
, profile());
1244 EXPECT_TRUE(tabstrip
.empty());
1246 WebContents
* opener
= CreateWebContents();
1247 tabstrip
.AppendWebContents(opener
, true);
1249 WebContents
* contents1
= CreateWebContents();
1250 WebContents
* contents2
= CreateWebContents();
1251 WebContents
* contents3
= CreateWebContents();
1253 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1254 EXPECT_EQ(0, tabstrip
.active_index());
1256 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1257 EXPECT_EQ(3, tabstrip
.count());
1259 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1260 EXPECT_EQ(1, tabstrip
.count());
1261 EXPECT_EQ(opener
, tabstrip
.GetActiveWebContents());
1263 WebContents
* dummy
= CreateWebContents();
1264 tabstrip
.AppendWebContents(dummy
, false);
1266 contents1
= CreateWebContents();
1267 contents2
= CreateWebContents();
1268 contents3
= CreateWebContents();
1269 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1270 EXPECT_EQ(5, tabstrip
.count());
1272 int dummy_index
= tabstrip
.count() - 1;
1273 tabstrip
.ActivateTabAt(dummy_index
, true);
1274 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1276 tabstrip
.ExecuteContextMenuCommand(dummy_index
,
1277 TabStripModel::CommandCloseOtherTabs
);
1278 EXPECT_EQ(1, tabstrip
.count());
1279 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1281 tabstrip
.CloseAllTabs();
1282 EXPECT_TRUE(tabstrip
.empty());
1285 // Tests GetIndicesClosedByCommand.
1286 TEST_F(TabStripModelTest
, GetIndicesClosedByCommand
) {
1287 TabStripDummyDelegate delegate
;
1288 TabStripModel
tabstrip(&delegate
, profile());
1289 EXPECT_TRUE(tabstrip
.empty());
1291 WebContents
* contents1
= CreateWebContents();
1292 WebContents
* contents2
= CreateWebContents();
1293 WebContents
* contents3
= CreateWebContents();
1294 WebContents
* contents4
= CreateWebContents();
1295 WebContents
* contents5
= CreateWebContents();
1297 tabstrip
.AppendWebContents(contents1
, true);
1298 tabstrip
.AppendWebContents(contents2
, true);
1299 tabstrip
.AppendWebContents(contents3
, true);
1300 tabstrip
.AppendWebContents(contents4
, true);
1301 tabstrip
.AppendWebContents(contents5
, true);
1303 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1304 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1305 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1306 tabstrip
, 1, TabStripModel::CommandCloseTabsToRight
));
1308 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1309 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1310 EXPECT_EQ("4 3 2 0", GetIndicesClosedByCommandAsString(
1311 tabstrip
, 1, TabStripModel::CommandCloseOtherTabs
));
1313 // Pin the first two tabs. Pinned tabs shouldn't be closed by the close other
1315 tabstrip
.SetTabPinned(0, true);
1316 tabstrip
.SetTabPinned(1, true);
1318 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1319 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1320 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1321 tabstrip
, 2, TabStripModel::CommandCloseTabsToRight
));
1323 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1324 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1325 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1326 tabstrip
, 2, TabStripModel::CommandCloseOtherTabs
));
1328 tabstrip
.CloseAllTabs();
1329 EXPECT_TRUE(tabstrip
.empty());
1332 // Tests whether or not WebContentses are inserted in the correct position
1333 // using this "smart" function with a simulated middle click action on a series
1334 // of links on the home page.
1335 TEST_F(TabStripModelTest
, AddWebContents_MiddleClickLinksAndClose
) {
1336 TabStripDummyDelegate delegate
;
1337 TabStripModel
tabstrip(&delegate
, profile());
1338 EXPECT_TRUE(tabstrip
.empty());
1340 // Open the Home Page.
1341 WebContents
* homepage_contents
= CreateWebContents();
1342 tabstrip
.AddWebContents(
1343 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1344 TabStripModel::ADD_ACTIVE
);
1346 // Open some other tab, by user typing.
1347 WebContents
* typed_page_contents
= CreateWebContents();
1348 tabstrip
.AddWebContents(
1349 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1350 TabStripModel::ADD_ACTIVE
);
1352 EXPECT_EQ(2, tabstrip
.count());
1354 // Re-select the home page.
1355 tabstrip
.ActivateTabAt(0, true);
1357 // Open a bunch of tabs by simulating middle clicking on links on the home
1359 WebContents
* middle_click_contents1
= CreateWebContents();
1360 tabstrip
.AddWebContents(
1361 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1362 TabStripModel::ADD_NONE
);
1363 WebContents
* middle_click_contents2
= CreateWebContents();
1364 tabstrip
.AddWebContents(
1365 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1366 TabStripModel::ADD_NONE
);
1367 WebContents
* middle_click_contents3
= CreateWebContents();
1368 tabstrip
.AddWebContents(
1369 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1370 TabStripModel::ADD_NONE
);
1372 EXPECT_EQ(5, tabstrip
.count());
1374 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1375 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetWebContentsAt(1));
1376 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetWebContentsAt(2));
1377 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetWebContentsAt(3));
1378 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1380 // Now simulate selecting a tab in the middle of the group of tabs opened from
1381 // the home page and start closing them. Each WebContents in the group
1382 // should be closed, right to left. This test is constructed to start at the
1383 // middle WebContents in the group to make sure the cursor wraps around
1384 // to the first WebContents in the group before closing the opener or
1385 // any other WebContents.
1386 tabstrip
.ActivateTabAt(2, true);
1387 tabstrip
.CloseSelectedTabs();
1388 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1389 tabstrip
.CloseSelectedTabs();
1390 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1391 tabstrip
.CloseSelectedTabs();
1392 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1393 tabstrip
.CloseSelectedTabs();
1394 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1396 EXPECT_EQ(1, tabstrip
.count());
1398 tabstrip
.CloseAllTabs();
1399 EXPECT_TRUE(tabstrip
.empty());
1402 // Tests whether or not a WebContents created by a left click on a link
1403 // that opens a new tab is inserted correctly adjacent to the tab that spawned
1405 TEST_F(TabStripModelTest
, AddWebContents_LeftClickPopup
) {
1406 TabStripDummyDelegate delegate
;
1407 TabStripModel
tabstrip(&delegate
, profile());
1408 EXPECT_TRUE(tabstrip
.empty());
1410 // Open the Home Page.
1411 WebContents
* homepage_contents
= CreateWebContents();
1412 tabstrip
.AddWebContents(
1413 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1414 TabStripModel::ADD_ACTIVE
);
1416 // Open some other tab, by user typing.
1417 WebContents
* typed_page_contents
= CreateWebContents();
1418 tabstrip
.AddWebContents(
1419 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1420 TabStripModel::ADD_ACTIVE
);
1422 EXPECT_EQ(2, tabstrip
.count());
1424 // Re-select the home page.
1425 tabstrip
.ActivateTabAt(0, true);
1427 // Open a tab by simulating a left click on a link that opens in a new tab.
1428 WebContents
* left_click_contents
= CreateWebContents();
1429 tabstrip
.AddWebContents(left_click_contents
, -1,
1430 ui::PAGE_TRANSITION_LINK
,
1431 TabStripModel::ADD_ACTIVE
);
1433 // Verify the state meets our expectations.
1434 EXPECT_EQ(3, tabstrip
.count());
1435 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1436 EXPECT_EQ(left_click_contents
, tabstrip
.GetWebContentsAt(1));
1437 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(2));
1439 // The newly created tab should be selected.
1440 EXPECT_EQ(left_click_contents
, tabstrip
.GetActiveWebContents());
1442 // After closing the selected tab, the selection should move to the left, to
1444 tabstrip
.CloseSelectedTabs();
1445 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1447 EXPECT_EQ(2, tabstrip
.count());
1449 tabstrip
.CloseAllTabs();
1450 EXPECT_TRUE(tabstrip
.empty());
1453 // Tests whether or not new tabs that should split context (typed pages,
1454 // generated urls, also blank tabs) open at the end of the tabstrip instead of
1456 TEST_F(TabStripModelTest
, AddWebContents_CreateNewBlankTab
) {
1457 TabStripDummyDelegate delegate
;
1458 TabStripModel
tabstrip(&delegate
, profile());
1459 EXPECT_TRUE(tabstrip
.empty());
1461 // Open the Home Page.
1462 WebContents
* homepage_contents
= CreateWebContents();
1463 tabstrip
.AddWebContents(
1464 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1465 TabStripModel::ADD_ACTIVE
);
1467 // Open some other tab, by user typing.
1468 WebContents
* typed_page_contents
= CreateWebContents();
1469 tabstrip
.AddWebContents(
1470 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1471 TabStripModel::ADD_ACTIVE
);
1473 EXPECT_EQ(2, tabstrip
.count());
1475 // Re-select the home page.
1476 tabstrip
.ActivateTabAt(0, true);
1478 // Open a new blank tab in the foreground.
1479 WebContents
* new_blank_contents
= CreateWebContents();
1480 tabstrip
.AddWebContents(new_blank_contents
, -1,
1481 ui::PAGE_TRANSITION_TYPED
,
1482 TabStripModel::ADD_ACTIVE
);
1484 // Verify the state of the tabstrip.
1485 EXPECT_EQ(3, tabstrip
.count());
1486 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1487 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1488 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1490 // Now open a couple more blank tabs in the background.
1491 WebContents
* background_blank_contents1
= CreateWebContents();
1492 tabstrip
.AddWebContents(
1493 background_blank_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1494 TabStripModel::ADD_NONE
);
1495 WebContents
* background_blank_contents2
= CreateWebContents();
1496 tabstrip
.AddWebContents(
1497 background_blank_contents2
, -1, ui::PAGE_TRANSITION_GENERATED
,
1498 TabStripModel::ADD_NONE
);
1499 EXPECT_EQ(5, tabstrip
.count());
1500 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1501 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1502 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1503 EXPECT_EQ(background_blank_contents1
, tabstrip
.GetWebContentsAt(3));
1504 EXPECT_EQ(background_blank_contents2
, tabstrip
.GetWebContentsAt(4));
1506 tabstrip
.CloseAllTabs();
1507 EXPECT_TRUE(tabstrip
.empty());
1510 // Tests whether opener state is correctly forgotten when the user switches
1512 TEST_F(TabStripModelTest
, AddWebContents_ForgetOpeners
) {
1513 TabStripDummyDelegate delegate
;
1514 TabStripModel
tabstrip(&delegate
, profile());
1515 EXPECT_TRUE(tabstrip
.empty());
1517 // Open the Home Page
1518 WebContents
* homepage_contents
= CreateWebContents();
1519 tabstrip
.AddWebContents(
1520 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1521 TabStripModel::ADD_ACTIVE
);
1523 // Open some other tab, by user typing.
1524 WebContents
* typed_page_contents
= CreateWebContents();
1525 tabstrip
.AddWebContents(
1526 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1527 TabStripModel::ADD_ACTIVE
);
1529 EXPECT_EQ(2, tabstrip
.count());
1531 // Re-select the home page.
1532 tabstrip
.ActivateTabAt(0, true);
1534 // Open a bunch of tabs by simulating middle clicking on links on the home
1536 WebContents
* middle_click_contents1
= CreateWebContents();
1537 tabstrip
.AddWebContents(
1538 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1539 TabStripModel::ADD_NONE
);
1540 WebContents
* middle_click_contents2
= CreateWebContents();
1541 tabstrip
.AddWebContents(
1542 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1543 TabStripModel::ADD_NONE
);
1544 WebContents
* middle_click_contents3
= CreateWebContents();
1545 tabstrip
.AddWebContents(
1546 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1547 TabStripModel::ADD_NONE
);
1549 // Break out of the context by selecting a tab in a different context.
1550 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1551 tabstrip
.SelectLastTab();
1552 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1554 // Step back into the context by selecting a tab inside it.
1555 tabstrip
.ActivateTabAt(2, true);
1556 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetActiveWebContents());
1558 // Now test that closing tabs selects to the right until there are no more,
1559 // then to the left, as if there were no context (context has been
1560 // successfully forgotten).
1561 tabstrip
.CloseSelectedTabs();
1562 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1563 tabstrip
.CloseSelectedTabs();
1564 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1565 tabstrip
.CloseSelectedTabs();
1566 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1567 tabstrip
.CloseSelectedTabs();
1568 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1570 EXPECT_EQ(1, tabstrip
.count());
1572 tabstrip
.CloseAllTabs();
1573 EXPECT_TRUE(tabstrip
.empty());
1576 // Added for http://b/issue?id=958960
1577 TEST_F(TabStripModelTest
, AppendContentsReselectionTest
) {
1578 TabStripDummyDelegate delegate
;
1579 TabStripModel
tabstrip(&delegate
, profile());
1580 EXPECT_TRUE(tabstrip
.empty());
1582 // Open the Home Page.
1583 WebContents
* homepage_contents
= CreateWebContents();
1584 tabstrip
.AddWebContents(
1585 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1586 TabStripModel::ADD_ACTIVE
);
1588 // Open some other tab, by user typing.
1589 WebContents
* typed_page_contents
= CreateWebContents();
1590 tabstrip
.AddWebContents(
1591 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1592 TabStripModel::ADD_NONE
);
1594 // The selected tab should still be the first.
1595 EXPECT_EQ(0, tabstrip
.active_index());
1597 // Now simulate a link click that opens a new tab (by virtue of target=_blank)
1598 // and make sure the correct tab gets selected when the new tab is closed.
1599 WebContents
* target_blank
= CreateWebContents();
1600 tabstrip
.AppendWebContents(target_blank
, true);
1601 EXPECT_EQ(2, tabstrip
.active_index());
1602 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1603 EXPECT_EQ(0, tabstrip
.active_index());
1605 // Clean up after ourselves.
1606 tabstrip
.CloseAllTabs();
1609 // Added for http://b/issue?id=1027661
1610 TEST_F(TabStripModelTest
, ReselectionConsidersChildrenTest
) {
1611 TabStripDummyDelegate delegate
;
1612 TabStripModel
strip(&delegate
, profile());
1615 WebContents
* page_a_contents
= CreateWebContents();
1616 strip
.AddWebContents(
1617 page_a_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1618 TabStripModel::ADD_ACTIVE
);
1620 // Simulate middle click to open page A.A and A.B
1621 WebContents
* page_a_a_contents
= CreateWebContents();
1622 strip
.AddWebContents(page_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1623 TabStripModel::ADD_NONE
);
1624 WebContents
* page_a_b_contents
= CreateWebContents();
1625 strip
.AddWebContents(page_a_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1626 TabStripModel::ADD_NONE
);
1629 strip
.ActivateTabAt(1, true);
1630 EXPECT_EQ(page_a_a_contents
, strip
.GetActiveWebContents());
1632 // Simulate a middle click to open page A.A.A
1633 WebContents
* page_a_a_a_contents
= CreateWebContents();
1634 strip
.AddWebContents(page_a_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1635 TabStripModel::ADD_NONE
);
1637 EXPECT_EQ(page_a_a_a_contents
, strip
.GetWebContentsAt(2));
1640 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1642 // Page A.A.A should be selected, NOT A.B
1643 EXPECT_EQ(page_a_a_a_contents
, strip
.GetActiveWebContents());
1646 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1648 // Page A.B should be selected
1649 EXPECT_EQ(page_a_b_contents
, strip
.GetActiveWebContents());
1652 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1654 // Page A should be selected
1655 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
1658 strip
.CloseAllTabs();
1661 TEST_F(TabStripModelTest
, AddWebContents_NewTabAtEndOfStripInheritsGroup
) {
1662 TabStripDummyDelegate delegate
;
1663 TabStripModel
strip(&delegate
, profile());
1666 WebContents
* page_a_contents
= CreateWebContents();
1667 strip
.AddWebContents(page_a_contents
, -1,
1668 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1669 TabStripModel::ADD_ACTIVE
);
1671 // Open pages B, C and D in the background from links on page A...
1672 WebContents
* page_b_contents
= CreateWebContents();
1673 WebContents
* page_c_contents
= CreateWebContents();
1674 WebContents
* page_d_contents
= CreateWebContents();
1675 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1676 TabStripModel::ADD_NONE
);
1677 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1678 TabStripModel::ADD_NONE
);
1679 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1680 TabStripModel::ADD_NONE
);
1682 // Switch to page B's tab.
1683 strip
.ActivateTabAt(1, true);
1685 // Open a New Tab at the end of the strip (simulate Ctrl+T)
1686 WebContents
* new_contents
= CreateWebContents();
1687 strip
.AddWebContents(new_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1688 TabStripModel::ADD_ACTIVE
);
1690 EXPECT_EQ(4, strip
.GetIndexOfWebContents(new_contents
));
1691 EXPECT_EQ(4, strip
.active_index());
1693 // Close the New Tab that was just opened. We should be returned to page B's
1695 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1697 EXPECT_EQ(1, strip
.active_index());
1699 // Open a non-New Tab tab at the end of the strip, with a TYPED transition.
1700 // This is like typing a URL in the address bar and pressing Alt+Enter. The
1701 // behavior should be the same as above.
1702 WebContents
* page_e_contents
= CreateWebContents();
1703 strip
.AddWebContents(page_e_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1704 TabStripModel::ADD_ACTIVE
);
1706 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_e_contents
));
1707 EXPECT_EQ(4, strip
.active_index());
1709 // Close the Tab. Selection should shift back to page B's Tab.
1710 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1712 EXPECT_EQ(1, strip
.active_index());
1714 // Open a non-New Tab tab at the end of the strip, with some other
1715 // transition. This is like right clicking on a bookmark and choosing "Open
1716 // in New Tab". No opener relationship should be preserved between this Tab
1717 // and the one that was active when the gesture was performed.
1718 WebContents
* page_f_contents
= CreateWebContents();
1719 strip
.AddWebContents(page_f_contents
, -1,
1720 ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1721 TabStripModel::ADD_ACTIVE
);
1723 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_f_contents
));
1724 EXPECT_EQ(4, strip
.active_index());
1726 // Close the Tab. The next-adjacent should be selected.
1727 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1729 EXPECT_EQ(3, strip
.active_index());
1732 strip
.CloseAllTabs();
1735 // A test of navigations in a tab that is part of a group of opened from some
1736 // parent tab. If the navigations are link clicks, the group relationship of
1737 // the tab to its parent are preserved. If they are of any other type, they are
1739 TEST_F(TabStripModelTest
, NavigationForgetsOpeners
) {
1740 TabStripDummyDelegate delegate
;
1741 TabStripModel
strip(&delegate
, profile());
1744 WebContents
* page_a_contents
= CreateWebContents();
1745 strip
.AddWebContents(page_a_contents
, -1,
1746 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1747 TabStripModel::ADD_ACTIVE
);
1749 // Open pages B, C and D in the background from links on page A...
1750 WebContents
* page_b_contents
= CreateWebContents();
1751 WebContents
* page_c_contents
= CreateWebContents();
1752 WebContents
* page_d_contents
= CreateWebContents();
1753 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1754 TabStripModel::ADD_NONE
);
1755 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1756 TabStripModel::ADD_NONE
);
1757 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1758 TabStripModel::ADD_NONE
);
1760 // Open page E in a different opener group from page A.
1761 WebContents
* page_e_contents
= CreateWebContents();
1762 strip
.AddWebContents(page_e_contents
, -1,
1763 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1764 TabStripModel::ADD_NONE
);
1766 // Tell the TabStripModel that we are navigating page D via a link click.
1767 strip
.ActivateTabAt(3, true);
1768 strip
.TabNavigating(page_d_contents
, ui::PAGE_TRANSITION_LINK
);
1770 // Close page D, page C should be selected. (part of same group).
1771 strip
.CloseWebContentsAt(3, TabStripModel::CLOSE_NONE
);
1772 EXPECT_EQ(2, strip
.active_index());
1774 // Tell the TabStripModel that we are navigating in page C via a bookmark.
1775 strip
.TabNavigating(page_c_contents
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
);
1777 // Close page C, page E should be selected. (C is no longer part of the
1778 // A-B-C-D group, selection moves to the right).
1779 strip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1780 EXPECT_EQ(page_e_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1782 strip
.CloseAllTabs();
1785 // A test that the forgetting behavior tested in NavigationForgetsOpeners above
1786 // doesn't cause the opener relationship for a New Tab opened at the end of the
1787 // TabStrip to be reset (Test 1 below), unless another any other tab is
1788 // selected (Test 2 below).
1789 TEST_F(TabStripModelTest
, NavigationForgettingDoesntAffectNewTab
) {
1790 TabStripDummyDelegate delegate
;
1791 TabStripModel
strip(&delegate
, profile());
1793 // Open a tab and several tabs from it, then select one of the tabs that was
1795 WebContents
* page_a_contents
= CreateWebContents();
1796 strip
.AddWebContents(page_a_contents
, -1,
1797 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1798 TabStripModel::ADD_ACTIVE
);
1800 WebContents
* page_b_contents
= CreateWebContents();
1801 WebContents
* page_c_contents
= CreateWebContents();
1802 WebContents
* page_d_contents
= CreateWebContents();
1803 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1804 TabStripModel::ADD_NONE
);
1805 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1806 TabStripModel::ADD_NONE
);
1807 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1808 TabStripModel::ADD_NONE
);
1810 strip
.ActivateTabAt(2, true);
1812 // TEST 1: If the user is in a group of tabs and opens a new tab at the end
1813 // of the strip, closing that new tab will select the tab that they were
1816 // Now simulate opening a new tab at the end of the TabStrip.
1817 WebContents
* new_contents1
= CreateWebContents();
1818 strip
.AddWebContents(new_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1819 TabStripModel::ADD_ACTIVE
);
1821 // At this point, if we close this tab the last selected one should be
1823 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1824 EXPECT_EQ(page_c_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1826 // TEST 2: If the user is in a group of tabs and opens a new tab at the end
1827 // of the strip, selecting any other tab in the strip will cause that new
1828 // tab's opener relationship to be forgotten.
1830 // Open a new tab again.
1831 WebContents
* new_contents2
= CreateWebContents();
1832 strip
.AddWebContents(new_contents2
, -1, ui::PAGE_TRANSITION_TYPED
,
1833 TabStripModel::ADD_ACTIVE
);
1835 // Now select the first tab.
1836 strip
.ActivateTabAt(0, true);
1838 // Now select the last tab.
1839 strip
.ActivateTabAt(strip
.count() - 1, true);
1841 // Now close the last tab. The next adjacent should be selected.
1842 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1843 EXPECT_EQ(page_d_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1845 strip
.CloseAllTabs();
1848 // This fails on Linux when run with the rest of unit_tests (crbug.com/302156)
1849 // and fails consistently on Mac and Windows.
1850 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
1851 #define MAYBE_FastShutdown \
1852 DISABLED_FastShutdown
1854 #define MAYBE_FastShutdown \
1857 // Tests that fast shutdown is attempted appropriately.
1858 TEST_F(TabStripModelTest
, MAYBE_FastShutdown
) {
1859 TabStripDummyDelegate delegate
;
1860 TabStripModel
tabstrip(&delegate
, profile());
1861 MockTabStripModelObserver
observer(&tabstrip
);
1862 tabstrip
.AddObserver(&observer
);
1864 EXPECT_TRUE(tabstrip
.empty());
1866 // Make sure fast shutdown is attempted when tabs that share a RPH are shut
1869 WebContents
* contents1
= CreateWebContents();
1870 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1872 SetID(contents1
, 1);
1873 SetID(contents2
, 2);
1875 tabstrip
.AppendWebContents(contents1
, true);
1876 tabstrip
.AppendWebContents(contents2
, true);
1878 // Turn on the fake unload listener so the tabs don't actually get shut
1879 // down when we call CloseAllTabs()---we need to be able to check that
1880 // fast shutdown was attempted.
1881 delegate
.set_run_unload_listener(true);
1882 tabstrip
.CloseAllTabs();
1883 // On a mock RPH this checks whether we *attempted* fast shutdown.
1884 // A real RPH would reject our attempt since there is an unload handler.
1885 EXPECT_TRUE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1886 EXPECT_EQ(2, tabstrip
.count());
1888 delegate
.set_run_unload_listener(false);
1889 tabstrip
.CloseAllTabs();
1890 EXPECT_TRUE(tabstrip
.empty());
1893 // Make sure fast shutdown is not attempted when only some tabs that share a
1894 // RPH are shut down.
1896 WebContents
* contents1
= CreateWebContents();
1897 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1899 SetID(contents1
, 1);
1900 SetID(contents2
, 2);
1902 tabstrip
.AppendWebContents(contents1
, true);
1903 tabstrip
.AppendWebContents(contents2
, true);
1905 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1906 EXPECT_FALSE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1907 EXPECT_EQ(1, tabstrip
.count());
1909 tabstrip
.CloseAllTabs();
1910 EXPECT_TRUE(tabstrip
.empty());
1914 // Tests various permutations of apps.
1915 TEST_F(TabStripModelTest
, Apps
) {
1916 TabStripDummyDelegate delegate
;
1917 TabStripModel
tabstrip(&delegate
, profile());
1918 MockTabStripModelObserver
observer(&tabstrip
);
1919 tabstrip
.AddObserver(&observer
);
1921 EXPECT_TRUE(tabstrip
.empty());
1923 typedef MockTabStripModelObserver::State State
;
1926 base::FilePath
path(FILE_PATH_LITERAL("c:\\foo"));
1927 #elif defined(OS_POSIX)
1928 base::FilePath
path(FILE_PATH_LITERAL("/foo"));
1931 base::DictionaryValue manifest
;
1932 manifest
.SetString("name", "hi!");
1933 manifest
.SetString("version", "1");
1934 manifest
.SetString("app.launch.web_url", "http://www.google.com");
1936 scoped_refptr
<Extension
> extension_app(
1937 Extension::Create(path
, extensions::Manifest::INVALID_LOCATION
,
1938 manifest
, Extension::NO_FLAGS
, &error
));
1939 WebContents
* contents1
= CreateWebContentsWithID(1);
1940 extensions::TabHelper::CreateForWebContents(contents1
);
1941 extensions::TabHelper::FromWebContents(contents1
)
1942 ->SetExtensionApp(extension_app
.get());
1943 WebContents
* contents2
= CreateWebContentsWithID(2);
1944 extensions::TabHelper::CreateForWebContents(contents2
);
1945 extensions::TabHelper::FromWebContents(contents2
)
1946 ->SetExtensionApp(extension_app
.get());
1947 WebContents
* contents3
= CreateWebContentsWithID(3);
1949 // Note! The ordering of these tests is important, each subsequent test
1950 // builds on the state established in the previous. This is important if you
1951 // ever insert tests rather than append.
1953 // Initial state, tab3 only and selected.
1954 tabstrip
.AppendWebContents(contents3
, true);
1956 observer
.ClearStates();
1958 // Attempt to insert tab1 (an app tab) at position 1. This isn't a legal
1959 // position and tab1 should end up at position 0.
1961 tabstrip
.InsertWebContentsAt(1, contents1
, TabStripModel::ADD_NONE
);
1963 ASSERT_EQ(1, observer
.GetStateCount());
1964 State
state(contents1
, 0, MockTabStripModelObserver::INSERT
);
1965 EXPECT_TRUE(observer
.StateEquals(0, state
));
1967 // And verify the state.
1968 EXPECT_EQ("1ap 3", GetTabStripStateString(tabstrip
));
1970 observer
.ClearStates();
1973 // Insert tab 2 at position 1.
1975 tabstrip
.InsertWebContentsAt(1, contents2
, TabStripModel::ADD_NONE
);
1977 ASSERT_EQ(1, observer
.GetStateCount());
1978 State
state(contents2
, 1, MockTabStripModelObserver::INSERT
);
1979 EXPECT_TRUE(observer
.StateEquals(0, state
));
1981 // And verify the state.
1982 EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip
));
1984 observer
.ClearStates();
1987 // Try to move tab 3 to position 0. This isn't legal and should be ignored.
1989 tabstrip
.MoveWebContentsAt(2, 0, false);
1991 ASSERT_EQ(0, observer
.GetStateCount());
1993 // And verify the state didn't change.
1994 EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip
));
1996 observer
.ClearStates();
1999 // Try to move tab 0 to position 3. This isn't legal and should be ignored.
2001 tabstrip
.MoveWebContentsAt(0, 2, false);
2003 ASSERT_EQ(0, observer
.GetStateCount());
2005 // And verify the state didn't change.
2006 EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip
));
2008 observer
.ClearStates();
2011 // Try to move tab 0 to position 1. This is a legal move.
2013 tabstrip
.MoveWebContentsAt(0, 1, false);
2015 ASSERT_EQ(1, observer
.GetStateCount());
2016 State
state(contents1
, 1, MockTabStripModelObserver::MOVE
);
2017 state
.src_index
= 0;
2018 EXPECT_TRUE(observer
.StateEquals(0, state
));
2020 // And verify the state didn't change.
2021 EXPECT_EQ("2ap 1ap 3", GetTabStripStateString(tabstrip
));
2023 observer
.ClearStates();
2026 // Remove tab3 and insert at position 0. It should be forced to position 2.
2028 tabstrip
.DetachWebContentsAt(2);
2029 observer
.ClearStates();
2031 tabstrip
.InsertWebContentsAt(0, contents3
, TabStripModel::ADD_NONE
);
2033 ASSERT_EQ(1, observer
.GetStateCount());
2034 State
state(contents3
, 2, MockTabStripModelObserver::INSERT
);
2035 EXPECT_TRUE(observer
.StateEquals(0, state
));
2037 // And verify the state didn't change.
2038 EXPECT_EQ("2ap 1ap 3", GetTabStripStateString(tabstrip
));
2040 observer
.ClearStates();
2043 tabstrip
.CloseAllTabs();
2046 // Tests various permutations of pinning tabs.
2047 TEST_F(TabStripModelTest
, Pinning
) {
2048 TabStripDummyDelegate delegate
;
2049 TabStripModel
tabstrip(&delegate
, profile());
2050 MockTabStripModelObserver
observer(&tabstrip
);
2051 tabstrip
.AddObserver(&observer
);
2053 EXPECT_TRUE(tabstrip
.empty());
2055 typedef MockTabStripModelObserver::State State
;
2057 WebContents
* contents1
= CreateWebContentsWithID(1);
2058 WebContents
* contents2
= CreateWebContentsWithID(2);
2059 WebContents
* contents3
= CreateWebContentsWithID(3);
2061 // Note! The ordering of these tests is important, each subsequent test
2062 // builds on the state established in the previous. This is important if you
2063 // ever insert tests rather than append.
2065 // Initial state, three tabs, first selected.
2066 tabstrip
.AppendWebContents(contents1
, true);
2067 tabstrip
.AppendWebContents(contents2
, false);
2068 tabstrip
.AppendWebContents(contents3
, false);
2070 observer
.ClearStates();
2072 // Pin the first tab, this shouldn't visually reorder anything.
2074 tabstrip
.SetTabPinned(0, true);
2076 // As the order didn't change, we should get a pinned notification.
2077 ASSERT_EQ(1, observer
.GetStateCount());
2078 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
2079 EXPECT_TRUE(observer
.StateEquals(0, state
));
2081 // And verify the state.
2082 EXPECT_EQ("1p 2 3", GetTabStripStateString(tabstrip
));
2084 observer
.ClearStates();
2087 // Unpin the first tab.
2089 tabstrip
.SetTabPinned(0, false);
2091 // As the order didn't change, we should get a pinned notification.
2092 ASSERT_EQ(1, observer
.GetStateCount());
2093 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
2094 EXPECT_TRUE(observer
.StateEquals(0, state
));
2096 // And verify the state.
2097 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
2099 observer
.ClearStates();
2102 // Pin the 3rd tab, which should move it to the front.
2104 tabstrip
.SetTabPinned(2, true);
2106 // The pinning should have resulted in a move and a pinned notification.
2107 ASSERT_EQ(2, observer
.GetStateCount());
2108 State
state(contents3
, 0, MockTabStripModelObserver::MOVE
);
2109 state
.src_index
= 2;
2110 EXPECT_TRUE(observer
.StateEquals(0, state
));
2112 state
= State(contents3
, 0, MockTabStripModelObserver::PINNED
);
2113 EXPECT_TRUE(observer
.StateEquals(1, state
));
2115 // And verify the state.
2116 EXPECT_EQ("3p 1 2", GetTabStripStateString(tabstrip
));
2118 observer
.ClearStates();
2121 // Pin the tab "1", which shouldn't move anything.
2123 tabstrip
.SetTabPinned(1, true);
2125 // As the order didn't change, we should get a pinned notification.
2126 ASSERT_EQ(1, observer
.GetStateCount());
2127 State
state(contents1
, 1, MockTabStripModelObserver::PINNED
);
2128 EXPECT_TRUE(observer
.StateEquals(0, state
));
2130 // And verify the state.
2131 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
2133 observer
.ClearStates();
2136 // Try to move tab "2" to the front, it should be ignored.
2138 tabstrip
.MoveWebContentsAt(2, 0, false);
2140 // As the order didn't change, we should get a pinned notification.
2141 ASSERT_EQ(0, observer
.GetStateCount());
2143 // And verify the state.
2144 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
2146 observer
.ClearStates();
2149 // Unpin tab "3", which implicitly moves it to the end.
2151 tabstrip
.SetTabPinned(0, false);
2153 ASSERT_EQ(2, observer
.GetStateCount());
2154 State
state(contents3
, 1, MockTabStripModelObserver::MOVE
);
2155 state
.src_index
= 0;
2156 EXPECT_TRUE(observer
.StateEquals(0, state
));
2158 state
= State(contents3
, 1, MockTabStripModelObserver::PINNED
);
2159 EXPECT_TRUE(observer
.StateEquals(1, state
));
2161 // And verify the state.
2162 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2164 observer
.ClearStates();
2167 // Unpin tab "3", nothing should happen.
2169 tabstrip
.SetTabPinned(1, false);
2171 ASSERT_EQ(0, observer
.GetStateCount());
2173 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2175 observer
.ClearStates();
2180 tabstrip
.SetTabPinned(0, true);
2181 tabstrip
.SetTabPinned(1, true);
2183 EXPECT_EQ("1p 3p 2", GetTabStripStateString(tabstrip
));
2185 observer
.ClearStates();
2188 WebContents
* contents4
= CreateWebContentsWithID(4);
2190 // Insert "4" between "1" and "3". As "1" and "4" are pinned, "4" should end
2193 tabstrip
.InsertWebContentsAt(1, contents4
, TabStripModel::ADD_NONE
);
2195 ASSERT_EQ(1, observer
.GetStateCount());
2196 State
state(contents4
, 2, MockTabStripModelObserver::INSERT
);
2197 EXPECT_TRUE(observer
.StateEquals(0, state
));
2199 EXPECT_EQ("1p 3p 4 2", GetTabStripStateString(tabstrip
));
2202 tabstrip
.CloseAllTabs();
2205 // Makes sure the TabStripModel calls the right observer methods during a
2207 TEST_F(TabStripModelTest
, ReplaceSendsSelected
) {
2208 typedef MockTabStripModelObserver::State State
;
2210 TabStripDummyDelegate delegate
;
2211 TabStripModel
strip(&delegate
, profile());
2213 WebContents
* first_contents
= CreateWebContents();
2214 strip
.AddWebContents(first_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
2215 TabStripModel::ADD_ACTIVE
);
2217 MockTabStripModelObserver
tabstrip_observer(&strip
);
2218 strip
.AddObserver(&tabstrip_observer
);
2220 WebContents
* new_contents
= CreateWebContents();
2221 delete strip
.ReplaceWebContentsAt(0, new_contents
);
2223 ASSERT_EQ(2, tabstrip_observer
.GetStateCount());
2225 // First event should be for replaced.
2226 State
state(new_contents
, 0, MockTabStripModelObserver::REPLACED
);
2227 state
.src_contents
= first_contents
;
2228 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2230 // And the second for selected.
2231 state
= State(new_contents
, 0, MockTabStripModelObserver::ACTIVATE
);
2232 state
.src_contents
= first_contents
;
2233 state
.change_reason
= TabStripModelObserver::CHANGE_REASON_REPLACED
;
2234 EXPECT_TRUE(tabstrip_observer
.StateEquals(1, state
));
2236 // Now add another tab and replace it, making sure we don't get a selected
2238 WebContents
* third_contents
= CreateWebContents();
2239 strip
.AddWebContents(third_contents
, 1, ui::PAGE_TRANSITION_TYPED
,
2240 TabStripModel::ADD_NONE
);
2242 tabstrip_observer
.ClearStates();
2245 new_contents
= CreateWebContents();
2246 delete strip
.ReplaceWebContentsAt(1, new_contents
);
2248 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2250 state
= State(new_contents
, 1, MockTabStripModelObserver::REPLACED
);
2251 state
.src_contents
= third_contents
;
2252 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2254 strip
.CloseAllTabs();
2257 // Ensures discarding tabs leaves TabStripModel in a good state.
2258 TEST_F(TabStripModelTest
, DiscardWebContentsAt
) {
2259 typedef MockTabStripModelObserver::State State
;
2261 TabStripDummyDelegate delegate
;
2262 TabStripModel
tabstrip(&delegate
, profile());
2264 // Fill it with some tabs.
2265 WebContents
* contents1
= CreateWebContents();
2266 tabstrip
.AppendWebContents(contents1
, true);
2267 WebContents
* contents2
= CreateWebContents();
2268 tabstrip
.AppendWebContents(contents2
, true);
2270 // Start watching for events after the appends to avoid observing state
2271 // transitions that aren't relevant to this test.
2272 MockTabStripModelObserver
tabstrip_observer(&tabstrip
);
2273 tabstrip
.AddObserver(&tabstrip_observer
);
2275 // Discard one of the tabs.
2276 WebContents
* null_contents1
= tabstrip
.DiscardWebContentsAt(0);
2277 ASSERT_EQ(2, tabstrip
.count());
2278 EXPECT_TRUE(tabstrip
.IsTabDiscarded(0));
2279 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2280 ASSERT_EQ(null_contents1
, tabstrip
.GetWebContentsAt(0));
2281 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2282 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2283 State
state1(null_contents1
, 0, MockTabStripModelObserver::REPLACED
);
2284 state1
.src_contents
= contents1
;
2285 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state1
));
2286 tabstrip_observer
.ClearStates();
2288 // Discard the same tab again.
2289 WebContents
* null_contents2
= tabstrip
.DiscardWebContentsAt(0);
2290 ASSERT_EQ(2, tabstrip
.count());
2291 EXPECT_TRUE(tabstrip
.IsTabDiscarded(0));
2292 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2293 ASSERT_EQ(null_contents2
, tabstrip
.GetWebContentsAt(0));
2294 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2295 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2296 State
state2(null_contents2
, 0, MockTabStripModelObserver::REPLACED
);
2297 state2
.src_contents
= null_contents1
;
2298 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state2
));
2299 tabstrip_observer
.ClearStates();
2301 // Activating the tab should clear its discard state.
2302 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
2303 ASSERT_EQ(2, tabstrip
.count());
2304 EXPECT_FALSE(tabstrip
.IsTabDiscarded(0));
2305 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2307 // Don't discard active tab.
2308 tabstrip
.DiscardWebContentsAt(0);
2309 ASSERT_EQ(2, tabstrip
.count());
2310 EXPECT_FALSE(tabstrip
.IsTabDiscarded(0));
2311 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2313 tabstrip
.CloseAllTabs();
2316 // Makes sure TabStripModel handles the case of deleting a tab while removing
2318 TEST_F(TabStripModelTest
, DeleteFromDestroy
) {
2319 TabStripDummyDelegate delegate
;
2320 TabStripModel
strip(&delegate
, profile());
2321 WebContents
* contents1
= CreateWebContents();
2322 WebContents
* contents2
= CreateWebContents();
2323 MockTabStripModelObserver
tab_strip_model_observer(&strip
);
2324 strip
.AppendWebContents(contents1
, true);
2325 strip
.AppendWebContents(contents2
, true);
2326 // DeleteWebContentsOnDestroyedObserver deletes contents1 when contents2 sends
2327 // out notification that it is being destroyed.
2328 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, NULL
);
2329 strip
.AddObserver(&tab_strip_model_observer
);
2330 strip
.CloseAllTabs();
2332 int close_all_count
= 0, close_all_canceled_count
= 0;
2333 tab_strip_model_observer
.GetCloseCounts(&close_all_count
,
2334 &close_all_canceled_count
);
2335 EXPECT_EQ(1, close_all_count
);
2336 EXPECT_EQ(0, close_all_canceled_count
);
2338 strip
.RemoveObserver(&tab_strip_model_observer
);
2341 // Makes sure TabStripModel handles the case of deleting another tab and the
2342 // TabStrip while removing another tab.
2343 TEST_F(TabStripModelTest
, DeleteTabStripFromDestroy
) {
2344 TabStripDummyDelegate delegate
;
2345 TabStripModel
* strip
= new TabStripModel(&delegate
, profile());
2346 MockTabStripModelObserver
tab_strip_model_observer(strip
);
2347 strip
->AddObserver(&tab_strip_model_observer
);
2348 WebContents
* contents1
= CreateWebContents();
2349 WebContents
* contents2
= CreateWebContents();
2350 strip
->AppendWebContents(contents1
, true);
2351 strip
->AppendWebContents(contents2
, true);
2352 // DeleteWebContentsOnDestroyedObserver deletes |contents1| and |strip| when
2353 // |contents2| sends out notification that it is being destroyed.
2354 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, strip
);
2355 strip
->CloseAllTabs();
2356 EXPECT_TRUE(tab_strip_model_observer
.empty());
2357 EXPECT_TRUE(tab_strip_model_observer
.deleted());
2360 TEST_F(TabStripModelTest
, MoveSelectedTabsTo
) {
2362 // Number of tabs the tab strip should have.
2363 const int tab_count
;
2365 // Number of pinned tabs.
2366 const int pinned_count
;
2368 // Index of the tabs to select.
2369 const std::string selected_tabs
;
2371 // Index to move the tabs to.
2372 const int target_index
;
2374 // Expected state after the move (space separated list of indices).
2375 const std::string state_after_move
;
2378 { 2, 0, "0", 1, "1 0" },
2379 { 3, 0, "0", 2, "1 2 0" },
2380 { 3, 0, "2", 0, "2 0 1" },
2381 { 3, 0, "2", 1, "0 2 1" },
2382 { 3, 0, "0 1", 0, "0 1 2" },
2385 { 6, 0, "4 5", 1, "0 4 5 1 2 3" },
2386 { 3, 0, "0 1", 1, "2 0 1" },
2387 { 4, 0, "0 2", 1, "1 0 2 3" },
2388 { 6, 0, "0 1", 3, "2 3 4 0 1 5" },
2391 { 6, 0, "0 2 3", 3, "1 4 5 0 2 3" },
2392 { 7, 0, "4 5 6", 1, "0 4 5 6 1 2 3" },
2393 { 7, 0, "1 5 6", 4, "0 2 3 4 1 5 6" },
2396 { 8, 0, "0 2 3 6 7", 3, "1 4 5 0 2 3 6 7" },
2399 { 16, 0, "0 1 2 3 4 7 9", 8, "5 6 8 10 11 12 13 14 0 1 2 3 4 7 9 15" },
2401 // With pinned tabs.
2402 { 6, 2, "2 3", 2, "0p 1p 2 3 4 5" },
2403 { 6, 2, "0 4", 3, "1p 0p 2 3 4 5" },
2404 { 6, 3, "1 2 4", 0, "1p 2p 0p 4 3 5" },
2405 { 8, 3, "1 3 4", 4, "0p 2p 1p 5 6 3 4 7" },
2407 { 7, 4, "2 3 4", 3, "0p 1p 2p 3p 5 4 6" },
2410 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
2411 TabStripDummyDelegate delegate
;
2412 TabStripModel
strip(&delegate
, profile());
2413 ASSERT_NO_FATAL_FAILURE(
2414 PrepareTabstripForSelectionTest(&strip
, test_data
[i
].tab_count
,
2415 test_data
[i
].pinned_count
,
2416 test_data
[i
].selected_tabs
));
2417 strip
.MoveSelectedTabsTo(test_data
[i
].target_index
);
2418 EXPECT_EQ(test_data
[i
].state_after_move
,
2419 GetTabStripStateString(strip
)) << i
;
2420 strip
.CloseAllTabs();
2424 // Tests that moving a tab forgets all groups referencing it.
2425 TEST_F(TabStripModelTest
, MoveSelectedTabsTo_ForgetGroups
) {
2426 TabStripDummyDelegate delegate
;
2427 TabStripModel
strip(&delegate
, profile());
2429 // Open page A as a new tab and then A1 in the background from A.
2430 WebContents
* page_a_contents
= CreateWebContents();
2431 strip
.AddWebContents(page_a_contents
, -1,
2432 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2433 TabStripModel::ADD_ACTIVE
);
2434 WebContents
* page_a1_contents
= CreateWebContents();
2435 strip
.AddWebContents(page_a1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2436 TabStripModel::ADD_NONE
);
2438 // Likewise, open pages B and B1.
2439 WebContents
* page_b_contents
= CreateWebContents();
2440 strip
.AddWebContents(page_b_contents
, -1,
2441 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2442 TabStripModel::ADD_ACTIVE
);
2443 WebContents
* page_b1_contents
= CreateWebContents();
2444 strip
.AddWebContents(page_b1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2445 TabStripModel::ADD_NONE
);
2447 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(0));
2448 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(1));
2449 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(2));
2450 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(3));
2452 // Move page B to the start of the tab strip.
2453 strip
.MoveSelectedTabsTo(0);
2455 // Open page B2 in the background from B. It should end up after B.
2456 WebContents
* page_b2_contents
= CreateWebContents();
2457 strip
.AddWebContents(page_b2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2458 TabStripModel::ADD_NONE
);
2459 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2460 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2461 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2462 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2463 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(4));
2466 strip
.ActivateTabAt(2, true);
2467 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
2469 // Open page A2 in the background from A. It should end up after A1.
2470 WebContents
* page_a2_contents
= CreateWebContents();
2471 strip
.AddWebContents(page_a2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2472 TabStripModel::ADD_NONE
);
2473 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2474 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2475 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2476 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2477 EXPECT_EQ(page_a2_contents
, strip
.GetWebContentsAt(4));
2478 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(5));
2480 strip
.CloseAllTabs();
2483 TEST_F(TabStripModelTest
, CloseSelectedTabs
) {
2484 TabStripDummyDelegate delegate
;
2485 TabStripModel
strip(&delegate
, profile());
2486 WebContents
* contents1
= CreateWebContents();
2487 WebContents
* contents2
= CreateWebContents();
2488 WebContents
* contents3
= CreateWebContents();
2489 strip
.AppendWebContents(contents1
, true);
2490 strip
.AppendWebContents(contents2
, true);
2491 strip
.AppendWebContents(contents3
, true);
2492 strip
.ToggleSelectionAt(1);
2493 strip
.CloseSelectedTabs();
2494 EXPECT_EQ(1, strip
.count());
2495 EXPECT_EQ(0, strip
.active_index());
2496 strip
.CloseAllTabs();
2499 TEST_F(TabStripModelTest
, MultipleSelection
) {
2500 typedef MockTabStripModelObserver::State State
;
2502 TabStripDummyDelegate delegate
;
2503 TabStripModel
strip(&delegate
, profile());
2504 MockTabStripModelObserver
observer(&strip
);
2505 WebContents
* contents0
= CreateWebContents();
2506 WebContents
* contents1
= CreateWebContents();
2507 WebContents
* contents2
= CreateWebContents();
2508 WebContents
* contents3
= CreateWebContents();
2509 strip
.AppendWebContents(contents0
, false);
2510 strip
.AppendWebContents(contents1
, false);
2511 strip
.AppendWebContents(contents2
, false);
2512 strip
.AppendWebContents(contents3
, false);
2513 strip
.AddObserver(&observer
);
2515 // Selection and active tab change.
2516 strip
.ActivateTabAt(3, true);
2517 ASSERT_EQ(2, observer
.GetStateCount());
2518 ASSERT_EQ(observer
.GetStateAt(0).action
,
2519 MockTabStripModelObserver::ACTIVATE
);
2520 State
s1(contents3
, 3, MockTabStripModelObserver::SELECT
);
2521 EXPECT_TRUE(observer
.StateEquals(1, s1
));
2522 observer
.ClearStates();
2524 // Adding all tabs to selection, active tab is now at 0.
2525 strip
.ExtendSelectionTo(0);
2526 ASSERT_EQ(3, observer
.GetStateCount());
2527 ASSERT_EQ(observer
.GetStateAt(0).action
,
2528 MockTabStripModelObserver::DEACTIVATE
);
2529 ASSERT_EQ(observer
.GetStateAt(1).action
,
2530 MockTabStripModelObserver::ACTIVATE
);
2531 State
s2(contents0
, 0, MockTabStripModelObserver::SELECT
);
2532 s2
.src_contents
= contents3
;
2534 EXPECT_TRUE(observer
.StateEquals(2, s2
));
2535 observer
.ClearStates();
2537 // Toggle the active tab, should make the next index active.
2538 strip
.ToggleSelectionAt(0);
2539 EXPECT_EQ(1, strip
.active_index());
2540 EXPECT_EQ(3U, strip
.selection_model().size());
2541 EXPECT_EQ(4, strip
.count());
2542 ASSERT_EQ(3, observer
.GetStateCount());
2543 ASSERT_EQ(observer
.GetStateAt(0).action
,
2544 MockTabStripModelObserver::DEACTIVATE
);
2545 ASSERT_EQ(observer
.GetStateAt(1).action
,
2546 MockTabStripModelObserver::ACTIVATE
);
2547 ASSERT_EQ(observer
.GetStateAt(2).action
,
2548 MockTabStripModelObserver::SELECT
);
2549 observer
.ClearStates();
2551 // Toggle the first tab back to selected and active.
2552 strip
.ToggleSelectionAt(0);
2553 EXPECT_EQ(0, strip
.active_index());
2554 EXPECT_EQ(4U, strip
.selection_model().size());
2555 EXPECT_EQ(4, strip
.count());
2556 ASSERT_EQ(3, observer
.GetStateCount());
2557 ASSERT_EQ(observer
.GetStateAt(0).action
,
2558 MockTabStripModelObserver::DEACTIVATE
);
2559 ASSERT_EQ(observer
.GetStateAt(1).action
,
2560 MockTabStripModelObserver::ACTIVATE
);
2561 ASSERT_EQ(observer
.GetStateAt(2).action
,
2562 MockTabStripModelObserver::SELECT
);
2563 observer
.ClearStates();
2565 // Closing one of the selected tabs, not the active one.
2566 strip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
2567 EXPECT_EQ(3, strip
.count());
2568 ASSERT_EQ(3, observer
.GetStateCount());
2569 ASSERT_EQ(observer
.GetStateAt(0).action
,
2570 MockTabStripModelObserver::CLOSE
);
2571 ASSERT_EQ(observer
.GetStateAt(1).action
,
2572 MockTabStripModelObserver::DETACH
);
2573 ASSERT_EQ(observer
.GetStateAt(2).action
,
2574 MockTabStripModelObserver::SELECT
);
2575 observer
.ClearStates();
2577 // Closing the active tab, while there are others tabs selected.
2578 strip
.CloseWebContentsAt(0, TabStripModel::CLOSE_NONE
);
2579 EXPECT_EQ(2, strip
.count());
2580 ASSERT_EQ(5, observer
.GetStateCount());
2581 ASSERT_EQ(observer
.GetStateAt(0).action
,
2582 MockTabStripModelObserver::CLOSE
);
2583 ASSERT_EQ(observer
.GetStateAt(1).action
,
2584 MockTabStripModelObserver::DETACH
);
2585 ASSERT_EQ(observer
.GetStateAt(2).action
,
2586 MockTabStripModelObserver::DEACTIVATE
);
2587 ASSERT_EQ(observer
.GetStateAt(3).action
,
2588 MockTabStripModelObserver::ACTIVATE
);
2589 ASSERT_EQ(observer
.GetStateAt(4).action
,
2590 MockTabStripModelObserver::SELECT
);
2591 observer
.ClearStates();
2593 // Active tab is at 0, deselecting all but the active tab.
2594 strip
.ToggleSelectionAt(1);
2595 ASSERT_EQ(1, observer
.GetStateCount());
2596 ASSERT_EQ(observer
.GetStateAt(0).action
,
2597 MockTabStripModelObserver::SELECT
);
2598 observer
.ClearStates();
2600 // Attempting to deselect the only selected and therefore active tab,
2601 // it is ignored (no notifications being sent) and tab at 0 remains selected
2603 strip
.ToggleSelectionAt(0);
2604 ASSERT_EQ(0, observer
.GetStateCount());
2606 strip
.RemoveObserver(&observer
);
2607 strip
.CloseAllTabs();
2610 // Verifies that if we change the selection from a multi selection to a single
2611 // selection, but not in a way that changes the selected_index that
2612 // TabSelectionChanged is invoked.
2613 TEST_F(TabStripModelTest
, MultipleToSingle
) {
2614 typedef MockTabStripModelObserver::State State
;
2616 TabStripDummyDelegate delegate
;
2617 TabStripModel
strip(&delegate
, profile());
2618 WebContents
* contents1
= CreateWebContents();
2619 WebContents
* contents2
= CreateWebContents();
2620 strip
.AppendWebContents(contents1
, false);
2621 strip
.AppendWebContents(contents2
, false);
2622 strip
.ToggleSelectionAt(0);
2623 strip
.ToggleSelectionAt(1);
2625 MockTabStripModelObserver
observer(&strip
);
2626 strip
.AddObserver(&observer
);
2627 // This changes the selection (0 is no longer selected) but the selected_index
2628 // still remains at 1.
2629 strip
.ActivateTabAt(1, true);
2630 ASSERT_EQ(1, observer
.GetStateCount());
2631 State
s(contents2
, 1, MockTabStripModelObserver::SELECT
);
2632 s
.src_contents
= contents2
;
2634 s
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
2635 EXPECT_TRUE(observer
.StateEquals(0, s
));
2636 strip
.RemoveObserver(&observer
);
2637 strip
.CloseAllTabs();
2640 // Verifies a newly inserted tab retains its previous blocked state.
2641 // http://crbug.com/276334
2642 TEST_F(TabStripModelTest
, TabBlockedState
) {
2643 // Start with a source tab strip.
2644 TabStripDummyDelegate dummy_tab_strip_delegate
;
2645 TabStripModel
strip_src(&dummy_tab_strip_delegate
, profile());
2646 TabBlockedStateTestBrowser
browser_src(&strip_src
);
2649 WebContents
* contents1
= CreateWebContents();
2650 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents1
);
2651 strip_src
.AppendWebContents(contents1
, false);
2654 WebContents
* contents2
= CreateWebContents();
2655 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents2
);
2656 strip_src
.AppendWebContents(contents2
, false);
2658 // Create a destination tab strip.
2659 TabStripModel
strip_dst(&dummy_tab_strip_delegate
, profile());
2660 TabBlockedStateTestBrowser
browser_dst(&strip_dst
);
2662 // Setup a SingleWebContentsDialogManager for tab |contents2|.
2663 web_modal::WebContentsModalDialogManager
* modal_dialog_manager
=
2664 web_modal::WebContentsModalDialogManager::FromWebContents(contents2
);
2665 web_modal::PopupManager
popup_manager(NULL
);
2666 popup_manager
.RegisterWith(contents2
);
2668 // Show a dialog that blocks tab |contents2|.
2669 // DummySingleWebContentsDialogManager doesn't care about the
2670 // dialog window value, so any dummy value works.
2671 DummySingleWebContentsDialogManager
* native_manager
=
2672 new DummySingleWebContentsDialogManager(
2673 reinterpret_cast<gfx::NativeWindow
>(0), modal_dialog_manager
);
2674 modal_dialog_manager
->ShowDialogWithManager(
2675 reinterpret_cast<gfx::NativeWindow
>(0),
2676 scoped_ptr
<web_modal::SingleWebContentsDialogManager
>(
2677 native_manager
).Pass());
2678 EXPECT_TRUE(strip_src
.IsTabBlocked(1));
2681 WebContents
* moved_contents
= strip_src
.DetachWebContentsAt(1);
2682 EXPECT_EQ(contents2
, moved_contents
);
2684 // Attach the tab to the destination tab strip.
2685 strip_dst
.AppendWebContents(moved_contents
, true);
2686 EXPECT_TRUE(strip_dst
.IsTabBlocked(0));
2688 strip_dst
.CloseAllTabs();
2689 strip_src
.CloseAllTabs();