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_discard_state.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
25 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
26 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
27 #include "chrome/common/url_constants.h"
28 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
29 #include "chrome/test/base/testing_profile.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 "content/public/test/web_contents_tester.h"
37 #include "extensions/common/extension.h"
38 #include "testing/gtest/include/gtest/gtest.h"
40 using content::SiteInstance
;
41 using content::WebContents
;
42 using content::WebContentsTester
;
43 using extensions::Extension
;
47 // Class used to delete a WebContents and TabStripModel when another WebContents
49 class DeleteWebContentsOnDestroyedObserver
50 : public content::WebContentsObserver
{
52 // When |source| is deleted both |tab_to_delete| and |tab_strip| are deleted.
53 // |tab_to_delete| and |tab_strip| may be NULL.
54 DeleteWebContentsOnDestroyedObserver(WebContents
* source
,
55 WebContents
* tab_to_delete
,
56 TabStripModel
* tab_strip
)
57 : WebContentsObserver(source
),
58 tab_to_delete_(tab_to_delete
),
59 tab_strip_(tab_strip
) {
62 void WebContentsDestroyed() override
{
63 WebContents
* tab_to_delete
= tab_to_delete_
;
64 tab_to_delete_
= NULL
;
65 TabStripModel
* tab_strip_to_delete
= tab_strip_
;
68 delete tab_strip_to_delete
;
72 WebContents
* tab_to_delete_
;
73 TabStripModel
* tab_strip_
;
75 DISALLOW_COPY_AND_ASSIGN(DeleteWebContentsOnDestroyedObserver
);
78 class TabStripDummyDelegate
: public TestTabStripModelDelegate
{
80 TabStripDummyDelegate() : run_unload_(false) {}
81 ~TabStripDummyDelegate() override
{}
83 void set_run_unload_listener(bool value
) { run_unload_
= value
; }
85 bool RunUnloadListenerBeforeClosing(WebContents
* contents
) override
{
90 // Whether to report that we need to run an unload listener before closing.
93 DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate
);
96 const char kTabStripModelTestIDUserDataKey
[] = "TabStripModelTestIDUserData";
98 class TabStripModelTestIDUserData
: public base::SupportsUserData::Data
{
100 explicit TabStripModelTestIDUserData(int id
) : id_(id
) {}
101 ~TabStripModelTestIDUserData() override
{}
102 int id() { return id_
; }
108 class DummySingleWebContentsDialogManager
109 : public web_modal::SingleWebContentsDialogManager
{
111 explicit DummySingleWebContentsDialogManager(
112 gfx::NativeWindow dialog
,
113 web_modal::SingleWebContentsDialogManagerDelegate
* delegate
)
114 : delegate_(delegate
),
116 ~DummySingleWebContentsDialogManager() override
{}
118 void Show() override
{}
119 void Hide() override
{}
120 void Close() override
{ delegate_
->WillClose(dialog_
); }
121 void Focus() override
{}
122 void Pulse() override
{}
123 void HostChanged(web_modal::WebContentsModalDialogHost
* new_host
) override
{}
124 gfx::NativeWindow
dialog() override
{ return dialog_
; }
127 web_modal::SingleWebContentsDialogManagerDelegate
* delegate_
;
128 gfx::NativeWindow dialog_
;
130 DISALLOW_COPY_AND_ASSIGN(DummySingleWebContentsDialogManager
);
133 // Test Browser-like class for TabStripModelTest.TabBlockedState.
134 class TabBlockedStateTestBrowser
135 : public TabStripModelObserver
,
136 public web_modal::WebContentsModalDialogManagerDelegate
{
138 explicit TabBlockedStateTestBrowser(TabStripModel
* tab_strip_model
)
139 : tab_strip_model_(tab_strip_model
) {
140 tab_strip_model_
->AddObserver(this);
143 ~TabBlockedStateTestBrowser() override
{
144 tab_strip_model_
->RemoveObserver(this);
148 // TabStripModelObserver
149 void TabInsertedAt(WebContents
* contents
,
151 bool foreground
) override
{
152 web_modal::WebContentsModalDialogManager
* manager
=
153 web_modal::WebContentsModalDialogManager::FromWebContents(contents
);
155 manager
->SetDelegate(this);
158 // WebContentsModalDialogManagerDelegate
159 void SetWebContentsBlocked(content::WebContents
* contents
,
160 bool blocked
) override
{
161 int index
= tab_strip_model_
->GetIndexOfWebContents(contents
);
163 tab_strip_model_
->SetTabBlocked(index
, blocked
);
166 TabStripModel
* tab_strip_model_
;
168 DISALLOW_COPY_AND_ASSIGN(TabBlockedStateTestBrowser
);
173 class TabStripModelTest
: public ChromeRenderViewHostTestHarness
{
175 WebContents
* CreateWebContents() {
176 return WebContents::Create(WebContents::CreateParams(profile()));
179 WebContents
* CreateWebContentsWithSharedRPH(WebContents
* web_contents
) {
180 WebContents::CreateParams
create_params(
181 profile(), web_contents
->GetRenderViewHost()->GetSiteInstance());
182 WebContents
* retval
= WebContents::Create(create_params
);
183 EXPECT_EQ(retval
->GetRenderProcessHost(),
184 web_contents
->GetRenderProcessHost());
188 WebContents
* CreateWebContentsWithID(int id
) {
189 WebContents
* contents
= CreateWebContents();
194 // Sets the id of the specified contents.
195 void SetID(WebContents
* contents
, int id
) {
196 contents
->SetUserData(&kTabStripModelTestIDUserDataKey
,
197 new TabStripModelTestIDUserData(id
));
200 // Returns the id of the specified contents.
201 int GetID(WebContents
* contents
) {
202 TabStripModelTestIDUserData
* user_data
=
203 static_cast<TabStripModelTestIDUserData
*>(
204 contents
->GetUserData(&kTabStripModelTestIDUserDataKey
));
206 return user_data
? user_data
->id() : -1;
209 // Returns the state of the given tab strip as a string. The state consists
210 // of the ID of each web contents followed by a 'p' if pinned. For example,
211 // if the model consists of two tabs with ids 2 and 1, with the first
212 // tab pinned, this returns "2p 1".
213 std::string
GetTabStripStateString(const TabStripModel
& model
) {
215 for (int i
= 0; i
< model
.count(); ++i
) {
219 actual
+= base::IntToString(GetID(model
.GetWebContentsAt(i
)));
221 if (model
.IsTabPinned(i
))
227 std::string
GetIndicesClosedByCommandAsString(
228 const TabStripModel
& model
,
230 TabStripModel::ContextMenuCommand id
) const {
231 std::vector
<int> indices
= model
.GetIndicesClosedByCommand(index
, id
);
233 for (size_t i
= 0; i
< indices
.size(); ++i
) {
236 result
+= base::IntToString(indices
[i
]);
241 void PrepareTabstripForSelectionTest(TabStripModel
* model
,
244 const std::string
& selected_tabs
) {
245 for (int i
= 0; i
< tab_count
; ++i
)
246 model
->AppendWebContents(CreateWebContentsWithID(i
), true);
247 for (int i
= 0; i
< pinned_count
; ++i
)
248 model
->SetTabPinned(i
, true);
250 ui::ListSelectionModel selection_model
;
251 for (const base::StringPiece
& sel
: base::SplitStringPiece(
252 selected_tabs
, base::kWhitespaceASCII
,
253 base::TRIM_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
)) {
255 ASSERT_TRUE(base::StringToInt(sel
, &value
));
256 selection_model
.AddIndexToSelection(value
);
258 selection_model
.set_active(selection_model
.selected_indices()[0]);
259 model
->SetSelectionFromModel(selection_model
);
263 class MockTabStripModelObserver
: public TabStripModelObserver
{
265 explicit MockTabStripModelObserver(TabStripModel
* model
)
269 ~MockTabStripModelObserver() override
{}
271 enum TabStripModelObserverAction
{
287 State(WebContents
* a_dst_contents
,
289 TabStripModelObserverAction a_action
)
290 : src_contents(NULL
),
291 dst_contents(a_dst_contents
),
293 dst_index(a_dst_index
),
294 change_reason(CHANGE_REASON_NONE
),
299 WebContents
* src_contents
;
300 WebContents
* dst_contents
;
305 TabStripModelObserverAction action
;
308 int GetStateCount() const {
309 return static_cast<int>(states_
.size());
312 // Returns (by way of parameters) the number of state's with CLOSE_ALL and
313 // CLOSE_ALL_CANCELED.
314 void GetCloseCounts(int* close_all_count
,
315 int* close_all_canceled_count
) {
316 *close_all_count
= *close_all_canceled_count
= 0;
317 for (int i
= 0; i
< GetStateCount(); ++i
) {
318 switch (GetStateAt(i
).action
) {
320 (*close_all_count
)++;
322 case CLOSE_ALL_CANCELED
:
323 (*close_all_canceled_count
)++;
331 const State
& GetStateAt(int index
) const {
332 DCHECK(index
>= 0 && index
< GetStateCount());
333 return states_
[index
];
336 bool StateEquals(int index
, const State
& state
) {
337 const State
& s
= GetStateAt(index
);
338 return (s
.src_contents
== state
.src_contents
&&
339 s
.dst_contents
== state
.dst_contents
&&
340 s
.src_index
== state
.src_index
&&
341 s
.dst_index
== state
.dst_index
&&
342 s
.change_reason
== state
.change_reason
&&
343 s
.foreground
== state
.foreground
&&
344 s
.action
== state
.action
);
347 // TabStripModelObserver implementation:
348 void TabInsertedAt(WebContents
* contents
,
350 bool foreground
) override
{
352 State
s(contents
, index
, INSERT
);
353 s
.foreground
= foreground
;
354 states_
.push_back(s
);
356 void ActiveTabChanged(WebContents
* old_contents
,
357 WebContents
* new_contents
,
359 int reason
) override
{
360 State
s(new_contents
, index
, ACTIVATE
);
361 s
.src_contents
= old_contents
;
362 s
.change_reason
= reason
;
363 states_
.push_back(s
);
365 void TabSelectionChanged(TabStripModel
* tab_strip_model
,
366 const ui::ListSelectionModel
& old_model
) override
{
367 State
s(model()->GetActiveWebContents(), model()->active_index(), SELECT
);
368 s
.src_contents
= model()->GetWebContentsAt(old_model
.active());
369 s
.src_index
= old_model
.active();
370 states_
.push_back(s
);
372 void TabMoved(WebContents
* contents
, int from_index
, int to_index
) override
{
373 State
s(contents
, to_index
, MOVE
);
374 s
.src_index
= from_index
;
375 states_
.push_back(s
);
378 void TabClosingAt(TabStripModel
* tab_strip_model
,
379 WebContents
* contents
,
380 int index
) override
{
381 states_
.push_back(State(contents
, index
, CLOSE
));
383 void TabDetachedAt(WebContents
* contents
, int index
) override
{
384 states_
.push_back(State(contents
, index
, DETACH
));
386 void TabDeactivated(WebContents
* contents
) override
{
387 states_
.push_back(State(contents
, model()->active_index(), DEACTIVATE
));
389 void TabChangedAt(WebContents
* contents
,
391 TabChangeType change_type
) override
{
392 states_
.push_back(State(contents
, index
, CHANGE
));
394 void TabReplacedAt(TabStripModel
* tab_strip_model
,
395 WebContents
* old_contents
,
396 WebContents
* new_contents
,
397 int index
) override
{
398 State
s(new_contents
, index
, REPLACED
);
399 s
.src_contents
= old_contents
;
400 states_
.push_back(s
);
402 void TabPinnedStateChanged(WebContents
* contents
, int index
) override
{
403 states_
.push_back(State(contents
, index
, PINNED
));
405 void TabStripEmpty() override
{ empty_
= true; }
406 void WillCloseAllTabs() override
{
407 states_
.push_back(State(NULL
, -1, CLOSE_ALL
));
409 void CloseAllTabsCanceled() override
{
410 states_
.push_back(State(NULL
, -1, CLOSE_ALL_CANCELED
));
412 void TabStripModelDeleted() override
{ deleted_
= true; }
418 bool empty() const { return empty_
; }
419 bool deleted() const { return deleted_
; }
420 TabStripModel
* model() { return model_
; }
423 std::vector
<State
> states_
;
427 TabStripModel
* model_
;
429 DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver
);
432 TEST_F(TabStripModelTest
, TestBasicAPI
) {
433 TabStripDummyDelegate delegate
;
434 TabStripModel
tabstrip(&delegate
, profile());
435 MockTabStripModelObserver
observer(&tabstrip
);
436 tabstrip
.AddObserver(&observer
);
438 EXPECT_TRUE(tabstrip
.empty());
440 typedef MockTabStripModelObserver::State State
;
442 WebContents
* contents1
= CreateWebContentsWithID(1);
444 // Note! The ordering of these tests is important, each subsequent test
445 // builds on the state established in the previous. This is important if you
446 // ever insert tests rather than append.
448 // Test AppendWebContents, ContainsIndex
450 EXPECT_FALSE(tabstrip
.ContainsIndex(0));
451 tabstrip
.AppendWebContents(contents1
, true);
452 EXPECT_TRUE(tabstrip
.ContainsIndex(0));
453 EXPECT_EQ(1, tabstrip
.count());
454 EXPECT_EQ(3, observer
.GetStateCount());
455 State
s1(contents1
, 0, MockTabStripModelObserver::INSERT
);
456 s1
.foreground
= true;
457 EXPECT_TRUE(observer
.StateEquals(0, s1
));
458 State
s2(contents1
, 0, MockTabStripModelObserver::ACTIVATE
);
459 EXPECT_TRUE(observer
.StateEquals(1, s2
));
460 State
s3(contents1
, 0, MockTabStripModelObserver::SELECT
);
461 s3
.src_contents
= NULL
;
462 s3
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
463 EXPECT_TRUE(observer
.StateEquals(2, s3
));
464 observer
.ClearStates();
466 EXPECT_EQ("1", GetTabStripStateString(tabstrip
));
468 // Test InsertWebContentsAt, foreground tab.
469 WebContents
* contents2
= CreateWebContentsWithID(2);
471 tabstrip
.InsertWebContentsAt(1, contents2
, TabStripModel::ADD_ACTIVE
);
473 EXPECT_EQ(2, tabstrip
.count());
474 EXPECT_EQ(4, observer
.GetStateCount());
475 State
s1(contents2
, 1, MockTabStripModelObserver::INSERT
);
476 s1
.foreground
= true;
477 EXPECT_TRUE(observer
.StateEquals(0, s1
));
478 State
s2(contents1
, 0, MockTabStripModelObserver::DEACTIVATE
);
479 EXPECT_TRUE(observer
.StateEquals(1, s2
));
480 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
481 s3
.src_contents
= contents1
;
482 EXPECT_TRUE(observer
.StateEquals(2, s3
));
483 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
484 s4
.src_contents
= contents1
;
486 EXPECT_TRUE(observer
.StateEquals(3, s4
));
487 observer
.ClearStates();
489 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
491 // Test InsertWebContentsAt, background tab.
492 WebContents
* contents3
= CreateWebContentsWithID(3);
494 tabstrip
.InsertWebContentsAt(2, contents3
, TabStripModel::ADD_NONE
);
496 EXPECT_EQ(3, tabstrip
.count());
497 EXPECT_EQ(1, observer
.GetStateCount());
498 State
s1(contents3
, 2, MockTabStripModelObserver::INSERT
);
499 s1
.foreground
= false;
500 EXPECT_TRUE(observer
.StateEquals(0, s1
));
501 observer
.ClearStates();
503 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
505 // Test ActivateTabAt
507 tabstrip
.ActivateTabAt(2, true);
508 EXPECT_EQ(3, observer
.GetStateCount());
509 State
s1(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
510 EXPECT_TRUE(observer
.StateEquals(0, s1
));
511 State
s2(contents3
, 2, MockTabStripModelObserver::ACTIVATE
);
512 s2
.src_contents
= contents2
;
513 s2
.change_reason
= TabStripModelObserver::CHANGE_REASON_USER_GESTURE
;
514 EXPECT_TRUE(observer
.StateEquals(1, s2
));
515 State
s3(contents3
, 2, MockTabStripModelObserver::SELECT
);
516 s3
.src_contents
= contents2
;
518 EXPECT_TRUE(observer
.StateEquals(2, s3
));
519 observer
.ClearStates();
521 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
523 // Test DetachWebContentsAt
526 WebContents
* detached
= tabstrip
.DetachWebContentsAt(2);
527 // ... and append again because we want this for later.
528 tabstrip
.AppendWebContents(detached
, true);
529 EXPECT_EQ(8, observer
.GetStateCount());
530 State
s1(detached
, 2, MockTabStripModelObserver::DETACH
);
531 EXPECT_TRUE(observer
.StateEquals(0, s1
));
532 State
s2(detached
, ui::ListSelectionModel::kUnselectedIndex
,
533 MockTabStripModelObserver::DEACTIVATE
);
534 EXPECT_TRUE(observer
.StateEquals(1, s2
));
535 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
536 s3
.src_contents
= contents3
;
537 s3
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
538 EXPECT_TRUE(observer
.StateEquals(2, s3
));
539 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
540 s4
.src_contents
= NULL
;
541 s4
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
542 EXPECT_TRUE(observer
.StateEquals(3, s4
));
543 State
s5(detached
, 2, MockTabStripModelObserver::INSERT
);
544 s5
.foreground
= true;
545 EXPECT_TRUE(observer
.StateEquals(4, s5
));
546 State
s6(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
547 EXPECT_TRUE(observer
.StateEquals(5, s6
));
548 State
s7(detached
, 2, MockTabStripModelObserver::ACTIVATE
);
549 s7
.src_contents
= contents2
;
550 s7
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
551 EXPECT_TRUE(observer
.StateEquals(6, s7
));
552 State
s8(detached
, 2, MockTabStripModelObserver::SELECT
);
553 s8
.src_contents
= contents2
;
555 EXPECT_TRUE(observer
.StateEquals(7, s8
));
556 observer
.ClearStates();
558 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
560 // Test CloseWebContentsAt
562 EXPECT_TRUE(tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
));
563 EXPECT_EQ(2, tabstrip
.count());
565 EXPECT_EQ(5, observer
.GetStateCount());
566 State
s1(contents3
, 2, MockTabStripModelObserver::CLOSE
);
567 EXPECT_TRUE(observer
.StateEquals(0, s1
));
568 State
s2(contents3
, 2, MockTabStripModelObserver::DETACH
);
569 EXPECT_TRUE(observer
.StateEquals(1, s2
));
570 State
s3(contents3
, ui::ListSelectionModel::kUnselectedIndex
,
571 MockTabStripModelObserver::DEACTIVATE
);
572 EXPECT_TRUE(observer
.StateEquals(2, s3
));
573 State
s4(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
574 s4
.src_contents
= contents3
;
575 s4
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
576 EXPECT_TRUE(observer
.StateEquals(3, s4
));
577 State
s5(contents2
, 1, MockTabStripModelObserver::SELECT
);
578 s5
.src_contents
= NULL
;
579 s5
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
580 EXPECT_TRUE(observer
.StateEquals(4, s5
));
581 observer
.ClearStates();
583 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
585 // Test MoveWebContentsAt, select_after_move == true
587 tabstrip
.MoveWebContentsAt(1, 0, true);
589 EXPECT_EQ(1, observer
.GetStateCount());
590 State
s1(contents2
, 0, MockTabStripModelObserver::MOVE
);
592 EXPECT_TRUE(observer
.StateEquals(0, s1
));
593 EXPECT_EQ(0, tabstrip
.active_index());
594 observer
.ClearStates();
596 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
598 // Test MoveWebContentsAt, select_after_move == false
600 tabstrip
.MoveWebContentsAt(1, 0, false);
601 EXPECT_EQ(1, observer
.GetStateCount());
602 State
s1(contents1
, 0, MockTabStripModelObserver::MOVE
);
604 EXPECT_TRUE(observer
.StateEquals(0, s1
));
605 EXPECT_EQ(1, tabstrip
.active_index());
607 tabstrip
.MoveWebContentsAt(0, 1, false);
608 observer
.ClearStates();
610 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
614 EXPECT_EQ(contents2
, tabstrip
.GetActiveWebContents());
615 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(0));
616 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
617 EXPECT_EQ(0, tabstrip
.GetIndexOfWebContents(contents2
));
618 EXPECT_EQ(1, tabstrip
.GetIndexOfWebContents(contents1
));
621 // Test UpdateWebContentsStateAt
623 tabstrip
.UpdateWebContentsStateAt(0, TabStripModelObserver::ALL
);
624 EXPECT_EQ(1, observer
.GetStateCount());
625 State
s1(contents2
, 0, MockTabStripModelObserver::CHANGE
);
626 EXPECT_TRUE(observer
.StateEquals(0, s1
));
627 observer
.ClearStates();
630 // Test SelectNextTab, SelectPreviousTab, SelectLastTab
632 // Make sure the second of the two tabs is selected first...
633 tabstrip
.ActivateTabAt(1, true);
634 tabstrip
.SelectPreviousTab();
635 EXPECT_EQ(0, tabstrip
.active_index());
636 tabstrip
.SelectLastTab();
637 EXPECT_EQ(1, tabstrip
.active_index());
638 tabstrip
.SelectNextTab();
639 EXPECT_EQ(0, tabstrip
.active_index());
642 // Test CloseSelectedTabs
644 tabstrip
.CloseSelectedTabs();
645 // |CloseSelectedTabs| calls CloseWebContentsAt, we already tested that, now
646 // just verify that the count and selected index have changed
648 EXPECT_EQ(1, tabstrip
.count());
649 EXPECT_EQ(0, tabstrip
.active_index());
652 observer
.ClearStates();
653 tabstrip
.CloseAllTabs();
655 int close_all_count
= 0, close_all_canceled_count
= 0;
656 observer
.GetCloseCounts(&close_all_count
, &close_all_canceled_count
);
657 EXPECT_EQ(1, close_all_count
);
658 EXPECT_EQ(0, close_all_canceled_count
);
660 // TabStripModel should now be empty.
661 EXPECT_TRUE(tabstrip
.empty());
663 // Opener methods are tested below...
665 tabstrip
.RemoveObserver(&observer
);
668 TEST_F(TabStripModelTest
, TestBasicOpenerAPI
) {
669 TabStripDummyDelegate delegate
;
670 TabStripModel
tabstrip(&delegate
, profile());
671 EXPECT_TRUE(tabstrip
.empty());
673 // This is a basic test of opener functionality. opener is created
674 // as the first tab in the strip and then we create 5 other tabs in the
675 // background with opener set as their opener.
677 WebContents
* opener
= CreateWebContents();
678 tabstrip
.AppendWebContents(opener
, true);
679 WebContents
* contents1
= CreateWebContents();
680 WebContents
* contents2
= CreateWebContents();
681 WebContents
* contents3
= CreateWebContents();
682 WebContents
* contents4
= CreateWebContents();
683 WebContents
* contents5
= CreateWebContents();
685 // We use |InsertWebContentsAt| here instead of |AppendWebContents| so that
686 // openership relationships are preserved.
687 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents1
,
688 TabStripModel::ADD_INHERIT_GROUP
);
689 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents2
,
690 TabStripModel::ADD_INHERIT_GROUP
);
691 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents3
,
692 TabStripModel::ADD_INHERIT_GROUP
);
693 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents4
,
694 TabStripModel::ADD_INHERIT_GROUP
);
695 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents5
,
696 TabStripModel::ADD_INHERIT_GROUP
);
698 // All the tabs should have the same opener.
699 for (int i
= 1; i
< tabstrip
.count(); ++i
)
700 EXPECT_EQ(opener
, tabstrip
.GetOpenerOfWebContentsAt(i
));
702 // If there is a next adjacent item, then the index should be of that item.
703 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
704 // If the last tab in the group is closed, the preceding tab in the same
705 // group should be selected.
706 EXPECT_EQ(4, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
708 // Tests the method that finds the last tab opened by the same opener in the
709 // strip (this is the insertion index for the next background tab for the
710 // specified opener).
711 EXPECT_EQ(5, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
713 // For a tab that has opened no other tabs, the return value should always be
716 tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents1
, 3, false));
718 tabstrip
.GetIndexOfLastWebContentsOpenedBy(contents1
, 3));
720 // ForgetAllOpeners should destroy all opener relationships.
721 tabstrip
.ForgetAllOpeners();
722 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
723 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
724 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
726 // Specify the last tab as the opener of the others.
727 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
728 tabstrip
.SetOpenerOfWebContentsAt(i
, contents5
);
730 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
731 EXPECT_EQ(contents5
, tabstrip
.GetOpenerOfWebContentsAt(i
));
733 // If there is a next adjacent item, then the index should be of that item.
734 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 1, false));
736 // If the last tab in the group is closed, the preceding tab in the same
737 // group should be selected.
738 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 4, false));
740 tabstrip
.CloseAllTabs();
741 EXPECT_TRUE(tabstrip
.empty());
744 static int GetInsertionIndex(TabStripModel
* tabstrip
) {
745 return tabstrip
->order_controller()->DetermineInsertionIndex(
746 ui::PAGE_TRANSITION_LINK
, false);
749 static void InsertWebContentses(TabStripModel
* tabstrip
,
750 WebContents
* contents1
,
751 WebContents
* contents2
,
752 WebContents
* contents3
) {
753 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
755 TabStripModel::ADD_INHERIT_GROUP
);
756 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
758 TabStripModel::ADD_INHERIT_GROUP
);
759 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
761 TabStripModel::ADD_INHERIT_GROUP
);
764 // Tests opening background tabs.
765 TEST_F(TabStripModelTest
, TestLTRInsertionOptions
) {
766 TabStripDummyDelegate delegate
;
767 TabStripModel
tabstrip(&delegate
, profile());
768 EXPECT_TRUE(tabstrip
.empty());
770 WebContents
* opener
= CreateWebContents();
771 tabstrip
.AppendWebContents(opener
, true);
773 WebContents
* contents1
= CreateWebContents();
774 WebContents
* contents2
= CreateWebContents();
775 WebContents
* contents3
= CreateWebContents();
778 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
779 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
780 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
781 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
783 tabstrip
.CloseAllTabs();
784 EXPECT_TRUE(tabstrip
.empty());
787 // This test constructs a tabstrip, and then simulates loading several tabs in
788 // the background from link clicks on the first tab. Then it simulates opening
789 // a new tab from the first tab in the foreground via a link click, verifies
790 // that this tab is opened adjacent to the opener, then closes it.
791 // Finally it tests that a tab opened for some non-link purpose opens at the
792 // end of the strip, not bundled to any existing context.
793 TEST_F(TabStripModelTest
, TestInsertionIndexDetermination
) {
794 TabStripDummyDelegate delegate
;
795 TabStripModel
tabstrip(&delegate
, profile());
796 EXPECT_TRUE(tabstrip
.empty());
798 WebContents
* opener
= CreateWebContents();
799 tabstrip
.AppendWebContents(opener
, true);
801 // Open some other random unrelated tab in the background to monkey with our
803 WebContents
* other
= CreateWebContents();
804 tabstrip
.AppendWebContents(other
, false);
806 WebContents
* contents1
= CreateWebContents();
807 WebContents
* contents2
= CreateWebContents();
808 WebContents
* contents3
= CreateWebContents();
810 // Start by testing LTR.
811 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
812 EXPECT_EQ(opener
, tabstrip
.GetWebContentsAt(0));
813 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
814 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
815 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
816 EXPECT_EQ(other
, tabstrip
.GetWebContentsAt(4));
818 // The opener API should work...
819 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
820 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
821 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
823 // Now open a foreground tab from a link. It should be opened adjacent to the
825 WebContents
* fg_link_contents
= CreateWebContents();
826 int insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
827 ui::PAGE_TRANSITION_LINK
, true);
828 EXPECT_EQ(1, insert_index
);
829 tabstrip
.InsertWebContentsAt(insert_index
, fg_link_contents
,
830 TabStripModel::ADD_ACTIVE
|
831 TabStripModel::ADD_INHERIT_GROUP
);
832 EXPECT_EQ(1, tabstrip
.active_index());
833 EXPECT_EQ(fg_link_contents
, tabstrip
.GetActiveWebContents());
835 // Now close this contents. The selection should move to the opener contents.
836 tabstrip
.CloseSelectedTabs();
837 EXPECT_EQ(0, tabstrip
.active_index());
839 // Now open a new empty tab. It should open at the end of the strip.
840 WebContents
* fg_nonlink_contents
= CreateWebContents();
841 insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
842 ui::PAGE_TRANSITION_AUTO_BOOKMARK
, true);
843 EXPECT_EQ(tabstrip
.count(), insert_index
);
844 // We break the opener relationship...
845 tabstrip
.InsertWebContentsAt(insert_index
,
847 TabStripModel::ADD_NONE
);
848 // Now select it, so that user_gesture == true causes the opener relationship
849 // to be forgotten...
850 tabstrip
.ActivateTabAt(tabstrip
.count() - 1, true);
851 EXPECT_EQ(tabstrip
.count() - 1, tabstrip
.active_index());
852 EXPECT_EQ(fg_nonlink_contents
, tabstrip
.GetActiveWebContents());
854 // Verify that all opener relationships are forgotten.
855 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
856 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
857 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
858 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
860 tabstrip
.CloseAllTabs();
861 EXPECT_TRUE(tabstrip
.empty());
864 // Tests that non-adjacent tabs with an opener are ignored when deciding where
866 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationAfterDragged
) {
867 TabStripDummyDelegate delegate
;
868 TabStripModel
tabstrip(&delegate
, profile());
869 EXPECT_TRUE(tabstrip
.empty());
871 // Start with three tabs, of which the first is active.
872 WebContents
* opener1
= CreateWebContentsWithID(1);
873 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
874 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
875 tabstrip
.AppendWebContents(CreateWebContentsWithID(3), false);
876 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
877 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
878 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
880 // Open a link in a new background tab.
881 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
882 CreateWebContentsWithID(11),
883 TabStripModel::ADD_INHERIT_GROUP
);
884 EXPECT_EQ("1 11 2 3", GetTabStripStateString(tabstrip
));
885 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
886 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
888 // Drag that tab (which activates it) one to the right.
889 tabstrip
.MoveWebContentsAt(1, 2, true /* select_after_move */);
890 EXPECT_EQ("1 2 11 3", GetTabStripStateString(tabstrip
));
891 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
892 // It should no longer be counted by GetIndexOfLastWebContentsOpenedBy,
893 // since there is a tab in between, even though its opener is unchanged.
894 // TODO(johnme): Maybe its opener should be reset when it's dragged away.
895 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
896 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(2));
898 // Activate the parent tab again.
899 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
900 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
902 // Open another link in a new background tab.
903 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
904 CreateWebContentsWithID(12),
905 TabStripModel::ADD_INHERIT_GROUP
);
906 // Tab 12 should be next to 1, and considered opened by it.
907 EXPECT_EQ("1 12 2 11 3", GetTabStripStateString(tabstrip
));
908 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
909 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
911 tabstrip
.CloseAllTabs();
912 EXPECT_TRUE(tabstrip
.empty());
915 // Tests that grandchild tabs are considered to be opened by their grandparent
916 // tab when deciding where to position tabs.
917 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationNestedOpener
) {
918 TabStripDummyDelegate delegate
;
919 TabStripModel
tabstrip(&delegate
, profile());
920 EXPECT_TRUE(tabstrip
.empty());
922 // Start with two tabs, of which the first is active:
923 WebContents
* opener1
= CreateWebContentsWithID(1);
924 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
925 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
926 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
927 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
928 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
930 // Open a link in a new background child tab.
931 WebContents
* child11
= CreateWebContentsWithID(11);
932 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
934 TabStripModel::ADD_INHERIT_GROUP
);
935 EXPECT_EQ("1 11 2", GetTabStripStateString(tabstrip
));
936 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
937 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
939 // Activate the child tab:
940 tabstrip
.ActivateTabAt(1, true /* user_gesture */);
941 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
943 // Open a link in a new background grandchild tab.
944 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
945 CreateWebContentsWithID(111),
946 TabStripModel::ADD_INHERIT_GROUP
);
947 EXPECT_EQ("1 11 111 2", GetTabStripStateString(tabstrip
));
948 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
949 // The grandchild tab should be counted by GetIndexOfLastWebContentsOpenedBy
950 // as opened by both its parent (child11) and grandparent (opener1).
951 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
952 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
954 // Activate the parent tab again:
955 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
956 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
958 // Open another link in a new background child tab (a sibling of child11).
959 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
960 CreateWebContentsWithID(12),
961 TabStripModel::ADD_INHERIT_GROUP
);
962 EXPECT_EQ("1 11 111 12 2", GetTabStripStateString(tabstrip
));
963 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
964 // opener1 has three adjacent descendants (11, 111, 12)
965 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
966 // child11 has only one adjacent descendant (111)
967 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
969 // Closing a tab should cause its children to inherit the tab's opener.
970 EXPECT_EQ(true, tabstrip
.CloseWebContentsAt(
972 TabStripModel::CLOSE_USER_GESTURE
|
973 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
));
974 EXPECT_EQ("1 111 12 2", GetTabStripStateString(tabstrip
));
975 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
976 // opener1 is now the opener of 111, so has two adjacent descendants (111, 12)
977 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(1));
978 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
980 tabstrip
.CloseAllTabs();
981 EXPECT_TRUE(tabstrip
.empty());
984 // Tests that selection is shifted to the correct tab when a tab is closed.
985 // If a tab is in the background when it is closed, the selection does not
987 // If a tab is in the foreground (selected),
988 // If that tab does not have an opener, selection shifts to the right.
989 // If the tab has an opener,
990 // The next tab (scanning LTR) in the entire strip that has the same opener
992 // If there are no other tabs that have the same opener,
993 // The opener is selected
995 TEST_F(TabStripModelTest
, TestSelectOnClose
) {
996 TabStripDummyDelegate delegate
;
997 TabStripModel
tabstrip(&delegate
, profile());
998 EXPECT_TRUE(tabstrip
.empty());
1000 WebContents
* opener
= CreateWebContents();
1001 tabstrip
.AppendWebContents(opener
, true);
1003 WebContents
* contents1
= CreateWebContents();
1004 WebContents
* contents2
= CreateWebContents();
1005 WebContents
* contents3
= CreateWebContents();
1007 // Note that we use Detach instead of Close throughout this test to avoid
1008 // having to keep reconstructing these WebContentses.
1010 // First test that closing tabs that are in the background doesn't adjust the
1011 // current selection.
1012 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1013 EXPECT_EQ(0, tabstrip
.active_index());
1015 tabstrip
.DetachWebContentsAt(1);
1016 EXPECT_EQ(0, tabstrip
.active_index());
1018 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1019 tabstrip
.DetachWebContentsAt(i
);
1021 // Now test that when a tab doesn't have an opener, selection shifts to the
1022 // right when the tab is closed.
1023 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1024 EXPECT_EQ(0, tabstrip
.active_index());
1026 tabstrip
.ForgetAllOpeners();
1027 tabstrip
.ActivateTabAt(1, true);
1028 EXPECT_EQ(1, tabstrip
.active_index());
1029 tabstrip
.DetachWebContentsAt(1);
1030 EXPECT_EQ(1, tabstrip
.active_index());
1031 tabstrip
.DetachWebContentsAt(1);
1032 EXPECT_EQ(1, tabstrip
.active_index());
1033 tabstrip
.DetachWebContentsAt(1);
1034 EXPECT_EQ(0, tabstrip
.active_index());
1036 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1037 tabstrip
.DetachWebContentsAt(i
);
1039 // Now test that when a tab does have an opener, it selects the next tab
1040 // opened by the same opener scanning LTR when it is closed.
1041 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1042 EXPECT_EQ(0, tabstrip
.active_index());
1043 tabstrip
.ActivateTabAt(2, false);
1044 EXPECT_EQ(2, tabstrip
.active_index());
1045 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1046 EXPECT_EQ(2, tabstrip
.active_index());
1047 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1048 EXPECT_EQ(1, tabstrip
.active_index());
1049 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1050 EXPECT_EQ(0, tabstrip
.active_index());
1051 // Finally test that when a tab has no "siblings" that the opener is
1053 WebContents
* other_contents
= CreateWebContents();
1054 tabstrip
.InsertWebContentsAt(1, other_contents
,
1055 TabStripModel::ADD_NONE
);
1056 EXPECT_EQ(2, tabstrip
.count());
1057 WebContents
* opened_contents
= CreateWebContents();
1058 tabstrip
.InsertWebContentsAt(2, opened_contents
,
1059 TabStripModel::ADD_ACTIVE
|
1060 TabStripModel::ADD_INHERIT_GROUP
);
1061 EXPECT_EQ(2, tabstrip
.active_index());
1062 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1063 EXPECT_EQ(0, tabstrip
.active_index());
1065 tabstrip
.CloseAllTabs();
1066 EXPECT_TRUE(tabstrip
.empty());
1069 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1071 TEST_F(TabStripModelTest
, CommandCloseTab
) {
1072 TabStripDummyDelegate delegate
;
1073 TabStripModel
tabstrip(&delegate
, profile());
1074 EXPECT_TRUE(tabstrip
.empty());
1076 // Make sure can_close is honored.
1077 ASSERT_NO_FATAL_FAILURE(
1078 PrepareTabstripForSelectionTest(&tabstrip
, 1, 0, "0"));
1079 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1080 0, TabStripModel::CommandCloseTab
));
1081 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1082 ASSERT_TRUE(tabstrip
.empty());
1084 // Make sure close on a tab that is selected affects all the selected tabs.
1085 ASSERT_NO_FATAL_FAILURE(
1086 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1087 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1088 0, TabStripModel::CommandCloseTab
));
1089 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1090 // Should have closed tabs 0 and 1.
1091 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1093 tabstrip
.CloseAllTabs();
1094 EXPECT_TRUE(tabstrip
.empty());
1096 // Select two tabs and make close on a tab that isn't selected doesn't affect
1098 ASSERT_NO_FATAL_FAILURE(
1099 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1100 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1101 2, TabStripModel::CommandCloseTab
));
1102 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1103 // Should have closed tab 2.
1104 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1105 tabstrip
.CloseAllTabs();
1106 EXPECT_TRUE(tabstrip
.empty());
1108 // Tests with 3 tabs, one pinned, two tab selected, one of which is pinned.
1109 ASSERT_NO_FATAL_FAILURE(
1110 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1111 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1112 0, TabStripModel::CommandCloseTab
));
1113 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1114 // Should have closed tab 2.
1115 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1116 tabstrip
.CloseAllTabs();
1117 EXPECT_TRUE(tabstrip
.empty());
1120 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1121 // CommandCloseTabs.
1122 TEST_F(TabStripModelTest
, CommandCloseOtherTabs
) {
1123 TabStripDummyDelegate delegate
;
1124 TabStripModel
tabstrip(&delegate
, profile());
1125 EXPECT_TRUE(tabstrip
.empty());
1127 // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
1128 // and close two tabs.
1129 ASSERT_NO_FATAL_FAILURE(
1130 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1131 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1132 0, TabStripModel::CommandCloseOtherTabs
));
1133 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1134 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1135 tabstrip
.CloseAllTabs();
1136 EXPECT_TRUE(tabstrip
.empty());
1138 // Select two tabs, CommandCloseOtherTabs should be enabled and invoking it
1139 // with a non-selected index should close the two other tabs.
1140 ASSERT_NO_FATAL_FAILURE(
1141 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1142 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1143 2, TabStripModel::CommandCloseOtherTabs
));
1144 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1145 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1146 tabstrip
.CloseAllTabs();
1147 EXPECT_TRUE(tabstrip
.empty());
1149 // Select all, CommandCloseOtherTabs should not be enabled.
1150 ASSERT_NO_FATAL_FAILURE(
1151 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1 2"));
1152 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1153 2, TabStripModel::CommandCloseOtherTabs
));
1154 tabstrip
.CloseAllTabs();
1155 EXPECT_TRUE(tabstrip
.empty());
1157 // Three tabs, pin one, select the two non-pinned.
1158 ASSERT_NO_FATAL_FAILURE(
1159 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1 2"));
1160 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1161 1, TabStripModel::CommandCloseOtherTabs
));
1162 // If we don't pass in the pinned index, the command should be enabled.
1163 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1164 0, TabStripModel::CommandCloseOtherTabs
));
1165 tabstrip
.CloseAllTabs();
1166 EXPECT_TRUE(tabstrip
.empty());
1168 // 3 tabs, one pinned.
1169 ASSERT_NO_FATAL_FAILURE(
1170 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1"));
1171 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1172 1, TabStripModel::CommandCloseOtherTabs
));
1173 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1174 0, TabStripModel::CommandCloseOtherTabs
));
1175 tabstrip
.ExecuteContextMenuCommand(1, TabStripModel::CommandCloseOtherTabs
);
1176 // The pinned tab shouldn't be closed.
1177 EXPECT_EQ("0p 1", GetTabStripStateString(tabstrip
));
1178 tabstrip
.CloseAllTabs();
1179 EXPECT_TRUE(tabstrip
.empty());
1182 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1183 // CommandCloseTabsToRight.
1184 TEST_F(TabStripModelTest
, CommandCloseTabsToRight
) {
1185 TabStripDummyDelegate delegate
;
1186 TabStripModel
tabstrip(&delegate
, profile());
1187 EXPECT_TRUE(tabstrip
.empty());
1189 // Create three tabs, select last two tabs, CommandCloseTabsToRight should
1190 // only be enabled for the first tab.
1191 ASSERT_NO_FATAL_FAILURE(
1192 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "1 2"));
1193 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1194 0, TabStripModel::CommandCloseTabsToRight
));
1195 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1196 1, TabStripModel::CommandCloseTabsToRight
));
1197 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1198 2, TabStripModel::CommandCloseTabsToRight
));
1199 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1200 EXPECT_EQ("0", GetTabStripStateString(tabstrip
));
1201 tabstrip
.CloseAllTabs();
1202 EXPECT_TRUE(tabstrip
.empty());
1205 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1206 // CommandTogglePinned.
1207 TEST_F(TabStripModelTest
, CommandTogglePinned
) {
1208 TabStripDummyDelegate delegate
;
1209 TabStripModel
tabstrip(&delegate
, profile());
1210 EXPECT_TRUE(tabstrip
.empty());
1212 // Create three tabs with one pinned, pin the first two.
1213 ASSERT_NO_FATAL_FAILURE(
1214 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1215 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1216 0, TabStripModel::CommandTogglePinned
));
1217 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1218 1, TabStripModel::CommandTogglePinned
));
1219 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1220 2, TabStripModel::CommandTogglePinned
));
1221 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1222 EXPECT_EQ("0p 1p 2", GetTabStripStateString(tabstrip
));
1224 // Execute CommandTogglePinned again, this should unpin.
1225 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1226 EXPECT_EQ("0 1 2", GetTabStripStateString(tabstrip
));
1229 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandTogglePinned
);
1230 EXPECT_EQ("2p 0 1", GetTabStripStateString(tabstrip
));
1232 tabstrip
.CloseAllTabs();
1233 EXPECT_TRUE(tabstrip
.empty());
1236 // Tests the following context menu commands:
1238 // - Close Other Tabs
1239 // - Close Tabs To Right
1240 TEST_F(TabStripModelTest
, TestContextMenuCloseCommands
) {
1241 TabStripDummyDelegate delegate
;
1242 TabStripModel
tabstrip(&delegate
, profile());
1243 EXPECT_TRUE(tabstrip
.empty());
1245 WebContents
* opener
= CreateWebContents();
1246 tabstrip
.AppendWebContents(opener
, true);
1248 WebContents
* contents1
= CreateWebContents();
1249 WebContents
* contents2
= CreateWebContents();
1250 WebContents
* contents3
= CreateWebContents();
1252 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1253 EXPECT_EQ(0, tabstrip
.active_index());
1255 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1256 EXPECT_EQ(3, tabstrip
.count());
1258 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1259 EXPECT_EQ(1, tabstrip
.count());
1260 EXPECT_EQ(opener
, tabstrip
.GetActiveWebContents());
1262 WebContents
* dummy
= CreateWebContents();
1263 tabstrip
.AppendWebContents(dummy
, false);
1265 contents1
= CreateWebContents();
1266 contents2
= CreateWebContents();
1267 contents3
= CreateWebContents();
1268 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1269 EXPECT_EQ(5, tabstrip
.count());
1271 int dummy_index
= tabstrip
.count() - 1;
1272 tabstrip
.ActivateTabAt(dummy_index
, true);
1273 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1275 tabstrip
.ExecuteContextMenuCommand(dummy_index
,
1276 TabStripModel::CommandCloseOtherTabs
);
1277 EXPECT_EQ(1, tabstrip
.count());
1278 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1280 tabstrip
.CloseAllTabs();
1281 EXPECT_TRUE(tabstrip
.empty());
1284 // Tests GetIndicesClosedByCommand.
1285 TEST_F(TabStripModelTest
, GetIndicesClosedByCommand
) {
1286 TabStripDummyDelegate delegate
;
1287 TabStripModel
tabstrip(&delegate
, profile());
1288 EXPECT_TRUE(tabstrip
.empty());
1290 WebContents
* contents1
= CreateWebContents();
1291 WebContents
* contents2
= CreateWebContents();
1292 WebContents
* contents3
= CreateWebContents();
1293 WebContents
* contents4
= CreateWebContents();
1294 WebContents
* contents5
= CreateWebContents();
1296 tabstrip
.AppendWebContents(contents1
, true);
1297 tabstrip
.AppendWebContents(contents2
, true);
1298 tabstrip
.AppendWebContents(contents3
, true);
1299 tabstrip
.AppendWebContents(contents4
, true);
1300 tabstrip
.AppendWebContents(contents5
, true);
1302 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1303 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1304 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1305 tabstrip
, 1, TabStripModel::CommandCloseTabsToRight
));
1307 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1308 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1309 EXPECT_EQ("4 3 2 0", GetIndicesClosedByCommandAsString(
1310 tabstrip
, 1, TabStripModel::CommandCloseOtherTabs
));
1312 // Pin the first two tabs. Pinned tabs shouldn't be closed by the close other
1314 tabstrip
.SetTabPinned(0, true);
1315 tabstrip
.SetTabPinned(1, true);
1317 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1318 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1319 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1320 tabstrip
, 2, TabStripModel::CommandCloseTabsToRight
));
1322 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1323 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1324 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1325 tabstrip
, 2, TabStripModel::CommandCloseOtherTabs
));
1327 tabstrip
.CloseAllTabs();
1328 EXPECT_TRUE(tabstrip
.empty());
1331 // Tests whether or not WebContentses are inserted in the correct position
1332 // using this "smart" function with a simulated middle click action on a series
1333 // of links on the home page.
1334 TEST_F(TabStripModelTest
, AddWebContents_MiddleClickLinksAndClose
) {
1335 TabStripDummyDelegate delegate
;
1336 TabStripModel
tabstrip(&delegate
, profile());
1337 EXPECT_TRUE(tabstrip
.empty());
1339 // Open the Home Page.
1340 WebContents
* homepage_contents
= CreateWebContents();
1341 tabstrip
.AddWebContents(
1342 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1343 TabStripModel::ADD_ACTIVE
);
1345 // Open some other tab, by user typing.
1346 WebContents
* typed_page_contents
= CreateWebContents();
1347 tabstrip
.AddWebContents(
1348 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1349 TabStripModel::ADD_ACTIVE
);
1351 EXPECT_EQ(2, tabstrip
.count());
1353 // Re-select the home page.
1354 tabstrip
.ActivateTabAt(0, true);
1356 // Open a bunch of tabs by simulating middle clicking on links on the home
1358 WebContents
* middle_click_contents1
= CreateWebContents();
1359 tabstrip
.AddWebContents(
1360 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1361 TabStripModel::ADD_NONE
);
1362 WebContents
* middle_click_contents2
= CreateWebContents();
1363 tabstrip
.AddWebContents(
1364 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1365 TabStripModel::ADD_NONE
);
1366 WebContents
* middle_click_contents3
= CreateWebContents();
1367 tabstrip
.AddWebContents(
1368 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1369 TabStripModel::ADD_NONE
);
1371 EXPECT_EQ(5, tabstrip
.count());
1373 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1374 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetWebContentsAt(1));
1375 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetWebContentsAt(2));
1376 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetWebContentsAt(3));
1377 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1379 // Now simulate selecting a tab in the middle of the group of tabs opened from
1380 // the home page and start closing them. Each WebContents in the group
1381 // should be closed, right to left. This test is constructed to start at the
1382 // middle WebContents in the group to make sure the cursor wraps around
1383 // to the first WebContents in the group before closing the opener or
1384 // any other WebContents.
1385 tabstrip
.ActivateTabAt(2, true);
1386 tabstrip
.CloseSelectedTabs();
1387 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1388 tabstrip
.CloseSelectedTabs();
1389 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1390 tabstrip
.CloseSelectedTabs();
1391 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1392 tabstrip
.CloseSelectedTabs();
1393 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1395 EXPECT_EQ(1, tabstrip
.count());
1397 tabstrip
.CloseAllTabs();
1398 EXPECT_TRUE(tabstrip
.empty());
1401 // Tests whether or not a WebContents created by a left click on a link
1402 // that opens a new tab is inserted correctly adjacent to the tab that spawned
1404 TEST_F(TabStripModelTest
, AddWebContents_LeftClickPopup
) {
1405 TabStripDummyDelegate delegate
;
1406 TabStripModel
tabstrip(&delegate
, profile());
1407 EXPECT_TRUE(tabstrip
.empty());
1409 // Open the Home Page.
1410 WebContents
* homepage_contents
= CreateWebContents();
1411 tabstrip
.AddWebContents(
1412 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1413 TabStripModel::ADD_ACTIVE
);
1415 // Open some other tab, by user typing.
1416 WebContents
* typed_page_contents
= CreateWebContents();
1417 tabstrip
.AddWebContents(
1418 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1419 TabStripModel::ADD_ACTIVE
);
1421 EXPECT_EQ(2, tabstrip
.count());
1423 // Re-select the home page.
1424 tabstrip
.ActivateTabAt(0, true);
1426 // Open a tab by simulating a left click on a link that opens in a new tab.
1427 WebContents
* left_click_contents
= CreateWebContents();
1428 tabstrip
.AddWebContents(left_click_contents
, -1,
1429 ui::PAGE_TRANSITION_LINK
,
1430 TabStripModel::ADD_ACTIVE
);
1432 // Verify the state meets our expectations.
1433 EXPECT_EQ(3, tabstrip
.count());
1434 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1435 EXPECT_EQ(left_click_contents
, tabstrip
.GetWebContentsAt(1));
1436 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(2));
1438 // The newly created tab should be selected.
1439 EXPECT_EQ(left_click_contents
, tabstrip
.GetActiveWebContents());
1441 // After closing the selected tab, the selection should move to the left, to
1443 tabstrip
.CloseSelectedTabs();
1444 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1446 EXPECT_EQ(2, tabstrip
.count());
1448 tabstrip
.CloseAllTabs();
1449 EXPECT_TRUE(tabstrip
.empty());
1452 // Tests whether or not new tabs that should split context (typed pages,
1453 // generated urls, also blank tabs) open at the end of the tabstrip instead of
1455 TEST_F(TabStripModelTest
, AddWebContents_CreateNewBlankTab
) {
1456 TabStripDummyDelegate delegate
;
1457 TabStripModel
tabstrip(&delegate
, profile());
1458 EXPECT_TRUE(tabstrip
.empty());
1460 // Open the Home Page.
1461 WebContents
* homepage_contents
= CreateWebContents();
1462 tabstrip
.AddWebContents(
1463 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1464 TabStripModel::ADD_ACTIVE
);
1466 // Open some other tab, by user typing.
1467 WebContents
* typed_page_contents
= CreateWebContents();
1468 tabstrip
.AddWebContents(
1469 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1470 TabStripModel::ADD_ACTIVE
);
1472 EXPECT_EQ(2, tabstrip
.count());
1474 // Re-select the home page.
1475 tabstrip
.ActivateTabAt(0, true);
1477 // Open a new blank tab in the foreground.
1478 WebContents
* new_blank_contents
= CreateWebContents();
1479 tabstrip
.AddWebContents(new_blank_contents
, -1,
1480 ui::PAGE_TRANSITION_TYPED
,
1481 TabStripModel::ADD_ACTIVE
);
1483 // Verify the state of the tabstrip.
1484 EXPECT_EQ(3, tabstrip
.count());
1485 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1486 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1487 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1489 // Now open a couple more blank tabs in the background.
1490 WebContents
* background_blank_contents1
= CreateWebContents();
1491 tabstrip
.AddWebContents(
1492 background_blank_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1493 TabStripModel::ADD_NONE
);
1494 WebContents
* background_blank_contents2
= CreateWebContents();
1495 tabstrip
.AddWebContents(
1496 background_blank_contents2
, -1, ui::PAGE_TRANSITION_GENERATED
,
1497 TabStripModel::ADD_NONE
);
1498 EXPECT_EQ(5, tabstrip
.count());
1499 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1500 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1501 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1502 EXPECT_EQ(background_blank_contents1
, tabstrip
.GetWebContentsAt(3));
1503 EXPECT_EQ(background_blank_contents2
, tabstrip
.GetWebContentsAt(4));
1505 tabstrip
.CloseAllTabs();
1506 EXPECT_TRUE(tabstrip
.empty());
1509 // Tests whether opener state is correctly forgotten when the user switches
1511 TEST_F(TabStripModelTest
, AddWebContents_ForgetOpeners
) {
1512 TabStripDummyDelegate delegate
;
1513 TabStripModel
tabstrip(&delegate
, profile());
1514 EXPECT_TRUE(tabstrip
.empty());
1516 // Open the Home Page
1517 WebContents
* homepage_contents
= CreateWebContents();
1518 tabstrip
.AddWebContents(
1519 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1520 TabStripModel::ADD_ACTIVE
);
1522 // Open some other tab, by user typing.
1523 WebContents
* typed_page_contents
= CreateWebContents();
1524 tabstrip
.AddWebContents(
1525 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1526 TabStripModel::ADD_ACTIVE
);
1528 EXPECT_EQ(2, tabstrip
.count());
1530 // Re-select the home page.
1531 tabstrip
.ActivateTabAt(0, true);
1533 // Open a bunch of tabs by simulating middle clicking on links on the home
1535 WebContents
* middle_click_contents1
= CreateWebContents();
1536 tabstrip
.AddWebContents(
1537 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1538 TabStripModel::ADD_NONE
);
1539 WebContents
* middle_click_contents2
= CreateWebContents();
1540 tabstrip
.AddWebContents(
1541 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1542 TabStripModel::ADD_NONE
);
1543 WebContents
* middle_click_contents3
= CreateWebContents();
1544 tabstrip
.AddWebContents(
1545 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1546 TabStripModel::ADD_NONE
);
1548 // Break out of the context by selecting a tab in a different context.
1549 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1550 tabstrip
.SelectLastTab();
1551 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1553 // Step back into the context by selecting a tab inside it.
1554 tabstrip
.ActivateTabAt(2, true);
1555 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetActiveWebContents());
1557 // Now test that closing tabs selects to the right until there are no more,
1558 // then to the left, as if there were no context (context has been
1559 // successfully forgotten).
1560 tabstrip
.CloseSelectedTabs();
1561 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1562 tabstrip
.CloseSelectedTabs();
1563 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1564 tabstrip
.CloseSelectedTabs();
1565 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1566 tabstrip
.CloseSelectedTabs();
1567 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1569 EXPECT_EQ(1, tabstrip
.count());
1571 tabstrip
.CloseAllTabs();
1572 EXPECT_TRUE(tabstrip
.empty());
1575 // Added for http://b/issue?id=958960
1576 TEST_F(TabStripModelTest
, AppendContentsReselectionTest
) {
1577 TabStripDummyDelegate delegate
;
1578 TabStripModel
tabstrip(&delegate
, profile());
1579 EXPECT_TRUE(tabstrip
.empty());
1581 // Open the Home Page.
1582 WebContents
* homepage_contents
= CreateWebContents();
1583 tabstrip
.AddWebContents(
1584 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1585 TabStripModel::ADD_ACTIVE
);
1587 // Open some other tab, by user typing.
1588 WebContents
* typed_page_contents
= CreateWebContents();
1589 tabstrip
.AddWebContents(
1590 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1591 TabStripModel::ADD_NONE
);
1593 // The selected tab should still be the first.
1594 EXPECT_EQ(0, tabstrip
.active_index());
1596 // Now simulate a link click that opens a new tab (by virtue of target=_blank)
1597 // and make sure the correct tab gets selected when the new tab is closed.
1598 WebContents
* target_blank
= CreateWebContents();
1599 tabstrip
.AppendWebContents(target_blank
, true);
1600 EXPECT_EQ(2, tabstrip
.active_index());
1601 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1602 EXPECT_EQ(0, tabstrip
.active_index());
1604 // Clean up after ourselves.
1605 tabstrip
.CloseAllTabs();
1608 // Added for http://b/issue?id=1027661
1609 TEST_F(TabStripModelTest
, ReselectionConsidersChildrenTest
) {
1610 TabStripDummyDelegate delegate
;
1611 TabStripModel
strip(&delegate
, profile());
1614 WebContents
* page_a_contents
= CreateWebContents();
1615 strip
.AddWebContents(
1616 page_a_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1617 TabStripModel::ADD_ACTIVE
);
1619 // Simulate middle click to open page A.A and A.B
1620 WebContents
* page_a_a_contents
= CreateWebContents();
1621 strip
.AddWebContents(page_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1622 TabStripModel::ADD_NONE
);
1623 WebContents
* page_a_b_contents
= CreateWebContents();
1624 strip
.AddWebContents(page_a_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1625 TabStripModel::ADD_NONE
);
1628 strip
.ActivateTabAt(1, true);
1629 EXPECT_EQ(page_a_a_contents
, strip
.GetActiveWebContents());
1631 // Simulate a middle click to open page A.A.A
1632 WebContents
* page_a_a_a_contents
= CreateWebContents();
1633 strip
.AddWebContents(page_a_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1634 TabStripModel::ADD_NONE
);
1636 EXPECT_EQ(page_a_a_a_contents
, strip
.GetWebContentsAt(2));
1639 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1641 // Page A.A.A should be selected, NOT A.B
1642 EXPECT_EQ(page_a_a_a_contents
, strip
.GetActiveWebContents());
1645 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1647 // Page A.B should be selected
1648 EXPECT_EQ(page_a_b_contents
, strip
.GetActiveWebContents());
1651 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1653 // Page A should be selected
1654 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
1657 strip
.CloseAllTabs();
1660 TEST_F(TabStripModelTest
, AddWebContents_NewTabAtEndOfStripInheritsGroup
) {
1661 TabStripDummyDelegate delegate
;
1662 TabStripModel
strip(&delegate
, profile());
1665 WebContents
* page_a_contents
= CreateWebContents();
1666 strip
.AddWebContents(page_a_contents
, -1,
1667 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1668 TabStripModel::ADD_ACTIVE
);
1670 // Open pages B, C and D in the background from links on page A...
1671 WebContents
* page_b_contents
= CreateWebContents();
1672 WebContents
* page_c_contents
= CreateWebContents();
1673 WebContents
* page_d_contents
= CreateWebContents();
1674 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1675 TabStripModel::ADD_NONE
);
1676 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1677 TabStripModel::ADD_NONE
);
1678 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1679 TabStripModel::ADD_NONE
);
1681 // Switch to page B's tab.
1682 strip
.ActivateTabAt(1, true);
1684 // Open a New Tab at the end of the strip (simulate Ctrl+T)
1685 WebContents
* new_contents
= CreateWebContents();
1686 strip
.AddWebContents(new_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1687 TabStripModel::ADD_ACTIVE
);
1689 EXPECT_EQ(4, strip
.GetIndexOfWebContents(new_contents
));
1690 EXPECT_EQ(4, strip
.active_index());
1692 // Close the New Tab that was just opened. We should be returned to page B's
1694 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1696 EXPECT_EQ(1, strip
.active_index());
1698 // Open a non-New Tab tab at the end of the strip, with a TYPED transition.
1699 // This is like typing a URL in the address bar and pressing Alt+Enter. The
1700 // behavior should be the same as above.
1701 WebContents
* page_e_contents
= CreateWebContents();
1702 strip
.AddWebContents(page_e_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1703 TabStripModel::ADD_ACTIVE
);
1705 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_e_contents
));
1706 EXPECT_EQ(4, strip
.active_index());
1708 // Close the Tab. Selection should shift back to page B's Tab.
1709 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1711 EXPECT_EQ(1, strip
.active_index());
1713 // Open a non-New Tab tab at the end of the strip, with some other
1714 // transition. This is like right clicking on a bookmark and choosing "Open
1715 // in New Tab". No opener relationship should be preserved between this Tab
1716 // and the one that was active when the gesture was performed.
1717 WebContents
* page_f_contents
= CreateWebContents();
1718 strip
.AddWebContents(page_f_contents
, -1,
1719 ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1720 TabStripModel::ADD_ACTIVE
);
1722 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_f_contents
));
1723 EXPECT_EQ(4, strip
.active_index());
1725 // Close the Tab. The next-adjacent should be selected.
1726 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1728 EXPECT_EQ(3, strip
.active_index());
1731 strip
.CloseAllTabs();
1734 // A test of navigations in a tab that is part of a group of opened from some
1735 // parent tab. If the navigations are link clicks, the group relationship of
1736 // the tab to its parent are preserved. If they are of any other type, they are
1738 TEST_F(TabStripModelTest
, NavigationForgetsOpeners
) {
1739 TabStripDummyDelegate delegate
;
1740 TabStripModel
strip(&delegate
, profile());
1743 WebContents
* page_a_contents
= CreateWebContents();
1744 strip
.AddWebContents(page_a_contents
, -1,
1745 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1746 TabStripModel::ADD_ACTIVE
);
1748 // Open pages B, C and D in the background from links on page A...
1749 WebContents
* page_b_contents
= CreateWebContents();
1750 WebContents
* page_c_contents
= CreateWebContents();
1751 WebContents
* page_d_contents
= CreateWebContents();
1752 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1753 TabStripModel::ADD_NONE
);
1754 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1755 TabStripModel::ADD_NONE
);
1756 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1757 TabStripModel::ADD_NONE
);
1759 // Open page E in a different opener group from page A.
1760 WebContents
* page_e_contents
= CreateWebContents();
1761 strip
.AddWebContents(page_e_contents
, -1,
1762 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1763 TabStripModel::ADD_NONE
);
1765 // Tell the TabStripModel that we are navigating page D via a link click.
1766 strip
.ActivateTabAt(3, true);
1767 strip
.TabNavigating(page_d_contents
, ui::PAGE_TRANSITION_LINK
);
1769 // Close page D, page C should be selected. (part of same group).
1770 strip
.CloseWebContentsAt(3, TabStripModel::CLOSE_NONE
);
1771 EXPECT_EQ(2, strip
.active_index());
1773 // Tell the TabStripModel that we are navigating in page C via a bookmark.
1774 strip
.TabNavigating(page_c_contents
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
);
1776 // Close page C, page E should be selected. (C is no longer part of the
1777 // A-B-C-D group, selection moves to the right).
1778 strip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1779 EXPECT_EQ(page_e_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1781 strip
.CloseAllTabs();
1784 // A test that the forgetting behavior tested in NavigationForgetsOpeners above
1785 // doesn't cause the opener relationship for a New Tab opened at the end of the
1786 // TabStrip to be reset (Test 1 below), unless another any other tab is
1787 // selected (Test 2 below).
1788 TEST_F(TabStripModelTest
, NavigationForgettingDoesntAffectNewTab
) {
1789 TabStripDummyDelegate delegate
;
1790 TabStripModel
strip(&delegate
, profile());
1792 // Open a tab and several tabs from it, then select one of the tabs that was
1794 WebContents
* page_a_contents
= CreateWebContents();
1795 strip
.AddWebContents(page_a_contents
, -1,
1796 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1797 TabStripModel::ADD_ACTIVE
);
1799 WebContents
* page_b_contents
= CreateWebContents();
1800 WebContents
* page_c_contents
= CreateWebContents();
1801 WebContents
* page_d_contents
= CreateWebContents();
1802 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1803 TabStripModel::ADD_NONE
);
1804 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1805 TabStripModel::ADD_NONE
);
1806 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1807 TabStripModel::ADD_NONE
);
1809 strip
.ActivateTabAt(2, true);
1811 // TEST 1: If the user is in a group of tabs and opens a new tab at the end
1812 // of the strip, closing that new tab will select the tab that they were
1815 // Now simulate opening a new tab at the end of the TabStrip.
1816 WebContents
* new_contents1
= CreateWebContents();
1817 strip
.AddWebContents(new_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1818 TabStripModel::ADD_ACTIVE
);
1820 // At this point, if we close this tab the last selected one should be
1822 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1823 EXPECT_EQ(page_c_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1825 // TEST 2: If the user is in a group of tabs and opens a new tab at the end
1826 // of the strip, selecting any other tab in the strip will cause that new
1827 // tab's opener relationship to be forgotten.
1829 // Open a new tab again.
1830 WebContents
* new_contents2
= CreateWebContents();
1831 strip
.AddWebContents(new_contents2
, -1, ui::PAGE_TRANSITION_TYPED
,
1832 TabStripModel::ADD_ACTIVE
);
1834 // Now select the first tab.
1835 strip
.ActivateTabAt(0, true);
1837 // Now select the last tab.
1838 strip
.ActivateTabAt(strip
.count() - 1, true);
1840 // Now close the last tab. The next adjacent should be selected.
1841 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1842 EXPECT_EQ(page_d_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1844 strip
.CloseAllTabs();
1847 // This fails on Linux when run with the rest of unit_tests (crbug.com/302156)
1848 // and fails consistently on Mac and Windows.
1849 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
1850 #define MAYBE_FastShutdown \
1851 DISABLED_FastShutdown
1853 #define MAYBE_FastShutdown \
1856 // Tests that fast shutdown is attempted appropriately.
1857 TEST_F(TabStripModelTest
, MAYBE_FastShutdown
) {
1858 TabStripDummyDelegate delegate
;
1859 TabStripModel
tabstrip(&delegate
, profile());
1860 MockTabStripModelObserver
observer(&tabstrip
);
1861 tabstrip
.AddObserver(&observer
);
1863 EXPECT_TRUE(tabstrip
.empty());
1865 // Make sure fast shutdown is attempted when tabs that share a RPH are shut
1868 WebContents
* contents1
= CreateWebContents();
1869 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1871 SetID(contents1
, 1);
1872 SetID(contents2
, 2);
1874 tabstrip
.AppendWebContents(contents1
, true);
1875 tabstrip
.AppendWebContents(contents2
, true);
1877 // Turn on the fake unload listener so the tabs don't actually get shut
1878 // down when we call CloseAllTabs()---we need to be able to check that
1879 // fast shutdown was attempted.
1880 delegate
.set_run_unload_listener(true);
1881 tabstrip
.CloseAllTabs();
1882 // On a mock RPH this checks whether we *attempted* fast shutdown.
1883 // A real RPH would reject our attempt since there is an unload handler.
1884 EXPECT_TRUE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1885 EXPECT_EQ(2, tabstrip
.count());
1887 delegate
.set_run_unload_listener(false);
1888 tabstrip
.CloseAllTabs();
1889 EXPECT_TRUE(tabstrip
.empty());
1892 // Make sure fast shutdown is not attempted when only some tabs that share a
1893 // RPH are shut down.
1895 WebContents
* contents1
= CreateWebContents();
1896 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1898 SetID(contents1
, 1);
1899 SetID(contents2
, 2);
1901 tabstrip
.AppendWebContents(contents1
, true);
1902 tabstrip
.AppendWebContents(contents2
, true);
1904 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1905 EXPECT_FALSE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1906 EXPECT_EQ(1, tabstrip
.count());
1908 tabstrip
.CloseAllTabs();
1909 EXPECT_TRUE(tabstrip
.empty());
1913 // Tests various permutations of pinning tabs.
1914 TEST_F(TabStripModelTest
, Pinning
) {
1915 TabStripDummyDelegate delegate
;
1916 TabStripModel
tabstrip(&delegate
, profile());
1917 MockTabStripModelObserver
observer(&tabstrip
);
1918 tabstrip
.AddObserver(&observer
);
1920 EXPECT_TRUE(tabstrip
.empty());
1922 typedef MockTabStripModelObserver::State State
;
1924 WebContents
* contents1
= CreateWebContentsWithID(1);
1925 WebContents
* contents2
= CreateWebContentsWithID(2);
1926 WebContents
* contents3
= CreateWebContentsWithID(3);
1928 // Note! The ordering of these tests is important, each subsequent test
1929 // builds on the state established in the previous. This is important if you
1930 // ever insert tests rather than append.
1932 // Initial state, three tabs, first selected.
1933 tabstrip
.AppendWebContents(contents1
, true);
1934 tabstrip
.AppendWebContents(contents2
, false);
1935 tabstrip
.AppendWebContents(contents3
, false);
1937 observer
.ClearStates();
1939 // Pin the first tab, this shouldn't visually reorder anything.
1941 tabstrip
.SetTabPinned(0, true);
1943 // As the order didn't change, we should get a pinned notification.
1944 ASSERT_EQ(1, observer
.GetStateCount());
1945 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
1946 EXPECT_TRUE(observer
.StateEquals(0, state
));
1948 // And verify the state.
1949 EXPECT_EQ("1p 2 3", GetTabStripStateString(tabstrip
));
1951 observer
.ClearStates();
1954 // Unpin the first tab.
1956 tabstrip
.SetTabPinned(0, false);
1958 // As the order didn't change, we should get a pinned notification.
1959 ASSERT_EQ(1, observer
.GetStateCount());
1960 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
1961 EXPECT_TRUE(observer
.StateEquals(0, state
));
1963 // And verify the state.
1964 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
1966 observer
.ClearStates();
1969 // Pin the 3rd tab, which should move it to the front.
1971 tabstrip
.SetTabPinned(2, true);
1973 // The pinning should have resulted in a move and a pinned notification.
1974 ASSERT_EQ(2, observer
.GetStateCount());
1975 State
state(contents3
, 0, MockTabStripModelObserver::MOVE
);
1976 state
.src_index
= 2;
1977 EXPECT_TRUE(observer
.StateEquals(0, state
));
1979 state
= State(contents3
, 0, MockTabStripModelObserver::PINNED
);
1980 EXPECT_TRUE(observer
.StateEquals(1, state
));
1982 // And verify the state.
1983 EXPECT_EQ("3p 1 2", GetTabStripStateString(tabstrip
));
1985 observer
.ClearStates();
1988 // Pin the tab "1", which shouldn't move anything.
1990 tabstrip
.SetTabPinned(1, true);
1992 // As the order didn't change, we should get a pinned notification.
1993 ASSERT_EQ(1, observer
.GetStateCount());
1994 State
state(contents1
, 1, MockTabStripModelObserver::PINNED
);
1995 EXPECT_TRUE(observer
.StateEquals(0, state
));
1997 // And verify the state.
1998 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
2000 observer
.ClearStates();
2003 // Try to move tab "2" to the front, it should be ignored.
2005 tabstrip
.MoveWebContentsAt(2, 0, false);
2007 // As the order didn't change, we should get a pinned notification.
2008 ASSERT_EQ(0, observer
.GetStateCount());
2010 // And verify the state.
2011 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
2013 observer
.ClearStates();
2016 // Unpin tab "3", which implicitly moves it to the end.
2018 tabstrip
.SetTabPinned(0, false);
2020 ASSERT_EQ(2, observer
.GetStateCount());
2021 State
state(contents3
, 1, MockTabStripModelObserver::MOVE
);
2022 state
.src_index
= 0;
2023 EXPECT_TRUE(observer
.StateEquals(0, state
));
2025 state
= State(contents3
, 1, MockTabStripModelObserver::PINNED
);
2026 EXPECT_TRUE(observer
.StateEquals(1, state
));
2028 // And verify the state.
2029 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2031 observer
.ClearStates();
2034 // Unpin tab "3", nothing should happen.
2036 tabstrip
.SetTabPinned(1, false);
2038 ASSERT_EQ(0, observer
.GetStateCount());
2040 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2042 observer
.ClearStates();
2047 tabstrip
.SetTabPinned(0, true);
2048 tabstrip
.SetTabPinned(1, true);
2050 EXPECT_EQ("1p 3p 2", GetTabStripStateString(tabstrip
));
2052 observer
.ClearStates();
2055 WebContents
* contents4
= CreateWebContentsWithID(4);
2057 // Insert "4" between "1" and "3". As "1" and "4" are pinned, "4" should end
2060 tabstrip
.InsertWebContentsAt(1, contents4
, TabStripModel::ADD_NONE
);
2062 ASSERT_EQ(1, observer
.GetStateCount());
2063 State
state(contents4
, 2, MockTabStripModelObserver::INSERT
);
2064 EXPECT_TRUE(observer
.StateEquals(0, state
));
2066 EXPECT_EQ("1p 3p 4 2", GetTabStripStateString(tabstrip
));
2069 tabstrip
.CloseAllTabs();
2072 // Makes sure the TabStripModel calls the right observer methods during a
2074 TEST_F(TabStripModelTest
, ReplaceSendsSelected
) {
2075 typedef MockTabStripModelObserver::State State
;
2077 TabStripDummyDelegate delegate
;
2078 TabStripModel
strip(&delegate
, profile());
2080 WebContents
* first_contents
= CreateWebContents();
2081 strip
.AddWebContents(first_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
2082 TabStripModel::ADD_ACTIVE
);
2084 MockTabStripModelObserver
tabstrip_observer(&strip
);
2085 strip
.AddObserver(&tabstrip_observer
);
2087 WebContents
* new_contents
= CreateWebContents();
2088 delete strip
.ReplaceWebContentsAt(0, new_contents
);
2090 ASSERT_EQ(2, tabstrip_observer
.GetStateCount());
2092 // First event should be for replaced.
2093 State
state(new_contents
, 0, MockTabStripModelObserver::REPLACED
);
2094 state
.src_contents
= first_contents
;
2095 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2097 // And the second for selected.
2098 state
= State(new_contents
, 0, MockTabStripModelObserver::ACTIVATE
);
2099 state
.src_contents
= first_contents
;
2100 state
.change_reason
= TabStripModelObserver::CHANGE_REASON_REPLACED
;
2101 EXPECT_TRUE(tabstrip_observer
.StateEquals(1, state
));
2103 // Now add another tab and replace it, making sure we don't get a selected
2105 WebContents
* third_contents
= CreateWebContents();
2106 strip
.AddWebContents(third_contents
, 1, ui::PAGE_TRANSITION_TYPED
,
2107 TabStripModel::ADD_NONE
);
2109 tabstrip_observer
.ClearStates();
2112 new_contents
= CreateWebContents();
2113 delete strip
.ReplaceWebContentsAt(1, new_contents
);
2115 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2117 state
= State(new_contents
, 1, MockTabStripModelObserver::REPLACED
);
2118 state
.src_contents
= third_contents
;
2119 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2121 strip
.CloseAllTabs();
2124 // Ensures discarding tabs leaves TabStripModel in a good state.
2125 TEST_F(TabStripModelTest
, DiscardWebContentsAt
) {
2126 typedef MockTabStripModelObserver::State State
;
2128 TabStripDummyDelegate delegate
;
2129 TabStripModel
tabstrip(&delegate
, profile());
2131 // Fill it with some tabs.
2132 WebContents
* contents1
= CreateWebContents();
2133 tabstrip
.AppendWebContents(contents1
, true);
2134 WebContents
* contents2
= CreateWebContents();
2135 tabstrip
.AppendWebContents(contents2
, true);
2137 // Start watching for events after the appends to avoid observing state
2138 // transitions that aren't relevant to this test.
2139 MockTabStripModelObserver
tabstrip_observer(&tabstrip
);
2140 tabstrip
.AddObserver(&tabstrip_observer
);
2142 // Discard one of the tabs.
2143 WebContents
* null_contents1
= tabstrip
.DiscardWebContentsAt(0);
2144 ASSERT_EQ(2, tabstrip
.count());
2145 EXPECT_TRUE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(0)));
2146 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2147 ASSERT_EQ(null_contents1
, tabstrip
.GetWebContentsAt(0));
2148 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2149 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2150 State
state1(null_contents1
, 0, MockTabStripModelObserver::REPLACED
);
2151 state1
.src_contents
= contents1
;
2152 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state1
));
2153 tabstrip_observer
.ClearStates();
2155 // Discard the same tab again.
2156 WebContents
* null_contents2
= tabstrip
.DiscardWebContentsAt(0);
2157 ASSERT_EQ(2, tabstrip
.count());
2158 EXPECT_TRUE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(0)));
2159 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2160 ASSERT_EQ(null_contents2
, tabstrip
.GetWebContentsAt(0));
2161 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2162 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2163 State
state2(null_contents2
, 0, MockTabStripModelObserver::REPLACED
);
2164 state2
.src_contents
= null_contents1
;
2165 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state2
));
2166 tabstrip_observer
.ClearStates();
2168 // Activating the tab should clear its discard state.
2169 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
2170 ASSERT_EQ(2, tabstrip
.count());
2171 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(0)));
2172 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2174 // Don't discard active tab.
2175 tabstrip
.DiscardWebContentsAt(0);
2176 ASSERT_EQ(2, tabstrip
.count());
2177 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(0)));
2178 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2180 tabstrip
.CloseAllTabs();
2183 // Makes sure that reloading a discarded tab without activating it unmarks the
2184 // tab as discarded so it won't reload on activation.
2185 TEST_F(TabStripModelTest
, ReloadDiscardedTabContextMenu
) {
2186 TabStripDummyDelegate delegate
;
2187 TabStripModel
tabstrip(&delegate
, profile());
2189 // Create 2 tabs because the active tab cannot be discarded.
2190 tabstrip
.AppendWebContents(CreateWebContents(), true);
2191 content::WebContents
* test_contents
=
2192 WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
2193 tabstrip
.AppendWebContents(test_contents
, false); // Opened in background.
2195 // Navigate to a web page. This is necessary to set a current entry in memory
2196 // so the reload can happen.
2197 WebContentsTester::For(test_contents
)
2198 ->NavigateAndCommit(GURL("chrome://newtab"));
2199 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2201 tabstrip
.DiscardWebContentsAt(1);
2202 EXPECT_TRUE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2204 tabstrip
.GetWebContentsAt(1)->GetController().Reload(false);
2205 EXPECT_FALSE(TabDiscardState::IsDiscarded(tabstrip
.GetWebContentsAt(1)));
2207 tabstrip
.CloseAllTabs();
2210 // Makes sure that the last active time property is saved even though the tab is
2212 TEST_F(TabStripModelTest
, DiscardedTabKeepsLastActiveTime
) {
2213 TabStripDummyDelegate delegate
;
2214 TabStripModel
tabstrip(&delegate
, profile());
2216 tabstrip
.AppendWebContents(CreateWebContents(), true);
2217 WebContents
* test_contents
= CreateWebContents();
2218 tabstrip
.AppendWebContents(test_contents
, false);
2220 // Simulate an old inactive tab about to get discarded.
2221 base::TimeTicks new_last_active_time
=
2222 base::TimeTicks::Now() - base::TimeDelta::FromMinutes(35);
2223 test_contents
->SetLastActiveTime(new_last_active_time
);
2224 EXPECT_EQ(new_last_active_time
, test_contents
->GetLastActiveTime());
2226 WebContents
* null_contents
= tabstrip
.DiscardWebContentsAt(1);
2227 EXPECT_EQ(new_last_active_time
, null_contents
->GetLastActiveTime());
2229 tabstrip
.CloseAllTabs();
2232 // Makes sure TabStripModel handles the case of deleting a tab while removing
2234 TEST_F(TabStripModelTest
, DeleteFromDestroy
) {
2235 TabStripDummyDelegate delegate
;
2236 TabStripModel
strip(&delegate
, profile());
2237 WebContents
* contents1
= CreateWebContents();
2238 WebContents
* contents2
= CreateWebContents();
2239 MockTabStripModelObserver
tab_strip_model_observer(&strip
);
2240 strip
.AppendWebContents(contents1
, true);
2241 strip
.AppendWebContents(contents2
, true);
2242 // DeleteWebContentsOnDestroyedObserver deletes contents1 when contents2 sends
2243 // out notification that it is being destroyed.
2244 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, NULL
);
2245 strip
.AddObserver(&tab_strip_model_observer
);
2246 strip
.CloseAllTabs();
2248 int close_all_count
= 0, close_all_canceled_count
= 0;
2249 tab_strip_model_observer
.GetCloseCounts(&close_all_count
,
2250 &close_all_canceled_count
);
2251 EXPECT_EQ(1, close_all_count
);
2252 EXPECT_EQ(0, close_all_canceled_count
);
2254 strip
.RemoveObserver(&tab_strip_model_observer
);
2257 // Makes sure TabStripModel handles the case of deleting another tab and the
2258 // TabStrip while removing another tab.
2259 TEST_F(TabStripModelTest
, DeleteTabStripFromDestroy
) {
2260 TabStripDummyDelegate delegate
;
2261 TabStripModel
* strip
= new TabStripModel(&delegate
, profile());
2262 MockTabStripModelObserver
tab_strip_model_observer(strip
);
2263 strip
->AddObserver(&tab_strip_model_observer
);
2264 WebContents
* contents1
= CreateWebContents();
2265 WebContents
* contents2
= CreateWebContents();
2266 strip
->AppendWebContents(contents1
, true);
2267 strip
->AppendWebContents(contents2
, true);
2268 // DeleteWebContentsOnDestroyedObserver deletes |contents1| and |strip| when
2269 // |contents2| sends out notification that it is being destroyed.
2270 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, strip
);
2271 strip
->CloseAllTabs();
2272 EXPECT_TRUE(tab_strip_model_observer
.empty());
2273 EXPECT_TRUE(tab_strip_model_observer
.deleted());
2276 TEST_F(TabStripModelTest
, MoveSelectedTabsTo
) {
2278 // Number of tabs the tab strip should have.
2279 const int tab_count
;
2281 // Number of pinned tabs.
2282 const int pinned_count
;
2284 // Index of the tabs to select.
2285 const std::string selected_tabs
;
2287 // Index to move the tabs to.
2288 const int target_index
;
2290 // Expected state after the move (space separated list of indices).
2291 const std::string state_after_move
;
2294 { 2, 0, "0", 1, "1 0" },
2295 { 3, 0, "0", 2, "1 2 0" },
2296 { 3, 0, "2", 0, "2 0 1" },
2297 { 3, 0, "2", 1, "0 2 1" },
2298 { 3, 0, "0 1", 0, "0 1 2" },
2301 { 6, 0, "4 5", 1, "0 4 5 1 2 3" },
2302 { 3, 0, "0 1", 1, "2 0 1" },
2303 { 4, 0, "0 2", 1, "1 0 2 3" },
2304 { 6, 0, "0 1", 3, "2 3 4 0 1 5" },
2307 { 6, 0, "0 2 3", 3, "1 4 5 0 2 3" },
2308 { 7, 0, "4 5 6", 1, "0 4 5 6 1 2 3" },
2309 { 7, 0, "1 5 6", 4, "0 2 3 4 1 5 6" },
2312 { 8, 0, "0 2 3 6 7", 3, "1 4 5 0 2 3 6 7" },
2315 { 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" },
2317 // With pinned tabs.
2318 { 6, 2, "2 3", 2, "0p 1p 2 3 4 5" },
2319 { 6, 2, "0 4", 3, "1p 0p 2 3 4 5" },
2320 { 6, 3, "1 2 4", 0, "1p 2p 0p 4 3 5" },
2321 { 8, 3, "1 3 4", 4, "0p 2p 1p 5 6 3 4 7" },
2323 { 7, 4, "2 3 4", 3, "0p 1p 2p 3p 5 4 6" },
2326 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
2327 TabStripDummyDelegate delegate
;
2328 TabStripModel
strip(&delegate
, profile());
2329 ASSERT_NO_FATAL_FAILURE(
2330 PrepareTabstripForSelectionTest(&strip
, test_data
[i
].tab_count
,
2331 test_data
[i
].pinned_count
,
2332 test_data
[i
].selected_tabs
));
2333 strip
.MoveSelectedTabsTo(test_data
[i
].target_index
);
2334 EXPECT_EQ(test_data
[i
].state_after_move
,
2335 GetTabStripStateString(strip
)) << i
;
2336 strip
.CloseAllTabs();
2340 // Tests that moving a tab forgets all groups referencing it.
2341 TEST_F(TabStripModelTest
, MoveSelectedTabsTo_ForgetGroups
) {
2342 TabStripDummyDelegate delegate
;
2343 TabStripModel
strip(&delegate
, profile());
2345 // Open page A as a new tab and then A1 in the background from A.
2346 WebContents
* page_a_contents
= CreateWebContents();
2347 strip
.AddWebContents(page_a_contents
, -1,
2348 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2349 TabStripModel::ADD_ACTIVE
);
2350 WebContents
* page_a1_contents
= CreateWebContents();
2351 strip
.AddWebContents(page_a1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2352 TabStripModel::ADD_NONE
);
2354 // Likewise, open pages B and B1.
2355 WebContents
* page_b_contents
= CreateWebContents();
2356 strip
.AddWebContents(page_b_contents
, -1,
2357 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2358 TabStripModel::ADD_ACTIVE
);
2359 WebContents
* page_b1_contents
= CreateWebContents();
2360 strip
.AddWebContents(page_b1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2361 TabStripModel::ADD_NONE
);
2363 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(0));
2364 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(1));
2365 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(2));
2366 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(3));
2368 // Move page B to the start of the tab strip.
2369 strip
.MoveSelectedTabsTo(0);
2371 // Open page B2 in the background from B. It should end up after B.
2372 WebContents
* page_b2_contents
= CreateWebContents();
2373 strip
.AddWebContents(page_b2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2374 TabStripModel::ADD_NONE
);
2375 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2376 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2377 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2378 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2379 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(4));
2382 strip
.ActivateTabAt(2, true);
2383 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
2385 // Open page A2 in the background from A. It should end up after A1.
2386 WebContents
* page_a2_contents
= CreateWebContents();
2387 strip
.AddWebContents(page_a2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2388 TabStripModel::ADD_NONE
);
2389 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2390 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2391 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2392 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2393 EXPECT_EQ(page_a2_contents
, strip
.GetWebContentsAt(4));
2394 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(5));
2396 strip
.CloseAllTabs();
2399 TEST_F(TabStripModelTest
, CloseSelectedTabs
) {
2400 TabStripDummyDelegate delegate
;
2401 TabStripModel
strip(&delegate
, profile());
2402 WebContents
* contents1
= CreateWebContents();
2403 WebContents
* contents2
= CreateWebContents();
2404 WebContents
* contents3
= CreateWebContents();
2405 strip
.AppendWebContents(contents1
, true);
2406 strip
.AppendWebContents(contents2
, true);
2407 strip
.AppendWebContents(contents3
, true);
2408 strip
.ToggleSelectionAt(1);
2409 strip
.CloseSelectedTabs();
2410 EXPECT_EQ(1, strip
.count());
2411 EXPECT_EQ(0, strip
.active_index());
2412 strip
.CloseAllTabs();
2415 TEST_F(TabStripModelTest
, MultipleSelection
) {
2416 typedef MockTabStripModelObserver::State State
;
2418 TabStripDummyDelegate delegate
;
2419 TabStripModel
strip(&delegate
, profile());
2420 MockTabStripModelObserver
observer(&strip
);
2421 WebContents
* contents0
= CreateWebContents();
2422 WebContents
* contents1
= CreateWebContents();
2423 WebContents
* contents2
= CreateWebContents();
2424 WebContents
* contents3
= CreateWebContents();
2425 strip
.AppendWebContents(contents0
, false);
2426 strip
.AppendWebContents(contents1
, false);
2427 strip
.AppendWebContents(contents2
, false);
2428 strip
.AppendWebContents(contents3
, false);
2429 strip
.AddObserver(&observer
);
2431 // Selection and active tab change.
2432 strip
.ActivateTabAt(3, true);
2433 ASSERT_EQ(2, observer
.GetStateCount());
2434 ASSERT_EQ(observer
.GetStateAt(0).action
,
2435 MockTabStripModelObserver::ACTIVATE
);
2436 State
s1(contents3
, 3, MockTabStripModelObserver::SELECT
);
2437 EXPECT_TRUE(observer
.StateEquals(1, s1
));
2438 observer
.ClearStates();
2440 // Adding all tabs to selection, active tab is now at 0.
2441 strip
.ExtendSelectionTo(0);
2442 ASSERT_EQ(3, observer
.GetStateCount());
2443 ASSERT_EQ(observer
.GetStateAt(0).action
,
2444 MockTabStripModelObserver::DEACTIVATE
);
2445 ASSERT_EQ(observer
.GetStateAt(1).action
,
2446 MockTabStripModelObserver::ACTIVATE
);
2447 State
s2(contents0
, 0, MockTabStripModelObserver::SELECT
);
2448 s2
.src_contents
= contents3
;
2450 EXPECT_TRUE(observer
.StateEquals(2, s2
));
2451 observer
.ClearStates();
2453 // Toggle the active tab, should make the next index active.
2454 strip
.ToggleSelectionAt(0);
2455 EXPECT_EQ(1, strip
.active_index());
2456 EXPECT_EQ(3U, strip
.selection_model().size());
2457 EXPECT_EQ(4, strip
.count());
2458 ASSERT_EQ(3, observer
.GetStateCount());
2459 ASSERT_EQ(observer
.GetStateAt(0).action
,
2460 MockTabStripModelObserver::DEACTIVATE
);
2461 ASSERT_EQ(observer
.GetStateAt(1).action
,
2462 MockTabStripModelObserver::ACTIVATE
);
2463 ASSERT_EQ(observer
.GetStateAt(2).action
,
2464 MockTabStripModelObserver::SELECT
);
2465 observer
.ClearStates();
2467 // Toggle the first tab back to selected and active.
2468 strip
.ToggleSelectionAt(0);
2469 EXPECT_EQ(0, strip
.active_index());
2470 EXPECT_EQ(4U, strip
.selection_model().size());
2471 EXPECT_EQ(4, strip
.count());
2472 ASSERT_EQ(3, observer
.GetStateCount());
2473 ASSERT_EQ(observer
.GetStateAt(0).action
,
2474 MockTabStripModelObserver::DEACTIVATE
);
2475 ASSERT_EQ(observer
.GetStateAt(1).action
,
2476 MockTabStripModelObserver::ACTIVATE
);
2477 ASSERT_EQ(observer
.GetStateAt(2).action
,
2478 MockTabStripModelObserver::SELECT
);
2479 observer
.ClearStates();
2481 // Closing one of the selected tabs, not the active one.
2482 strip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
2483 EXPECT_EQ(3, strip
.count());
2484 ASSERT_EQ(3, observer
.GetStateCount());
2485 ASSERT_EQ(observer
.GetStateAt(0).action
,
2486 MockTabStripModelObserver::CLOSE
);
2487 ASSERT_EQ(observer
.GetStateAt(1).action
,
2488 MockTabStripModelObserver::DETACH
);
2489 ASSERT_EQ(observer
.GetStateAt(2).action
,
2490 MockTabStripModelObserver::SELECT
);
2491 observer
.ClearStates();
2493 // Closing the active tab, while there are others tabs selected.
2494 strip
.CloseWebContentsAt(0, TabStripModel::CLOSE_NONE
);
2495 EXPECT_EQ(2, strip
.count());
2496 ASSERT_EQ(5, observer
.GetStateCount());
2497 ASSERT_EQ(observer
.GetStateAt(0).action
,
2498 MockTabStripModelObserver::CLOSE
);
2499 ASSERT_EQ(observer
.GetStateAt(1).action
,
2500 MockTabStripModelObserver::DETACH
);
2501 ASSERT_EQ(observer
.GetStateAt(2).action
,
2502 MockTabStripModelObserver::DEACTIVATE
);
2503 ASSERT_EQ(observer
.GetStateAt(3).action
,
2504 MockTabStripModelObserver::ACTIVATE
);
2505 ASSERT_EQ(observer
.GetStateAt(4).action
,
2506 MockTabStripModelObserver::SELECT
);
2507 observer
.ClearStates();
2509 // Active tab is at 0, deselecting all but the active tab.
2510 strip
.ToggleSelectionAt(1);
2511 ASSERT_EQ(1, observer
.GetStateCount());
2512 ASSERT_EQ(observer
.GetStateAt(0).action
,
2513 MockTabStripModelObserver::SELECT
);
2514 observer
.ClearStates();
2516 // Attempting to deselect the only selected and therefore active tab,
2517 // it is ignored (no notifications being sent) and tab at 0 remains selected
2519 strip
.ToggleSelectionAt(0);
2520 ASSERT_EQ(0, observer
.GetStateCount());
2522 strip
.RemoveObserver(&observer
);
2523 strip
.CloseAllTabs();
2526 // Verifies that if we change the selection from a multi selection to a single
2527 // selection, but not in a way that changes the selected_index that
2528 // TabSelectionChanged is invoked.
2529 TEST_F(TabStripModelTest
, MultipleToSingle
) {
2530 typedef MockTabStripModelObserver::State State
;
2532 TabStripDummyDelegate delegate
;
2533 TabStripModel
strip(&delegate
, profile());
2534 WebContents
* contents1
= CreateWebContents();
2535 WebContents
* contents2
= CreateWebContents();
2536 strip
.AppendWebContents(contents1
, false);
2537 strip
.AppendWebContents(contents2
, false);
2538 strip
.ToggleSelectionAt(0);
2539 strip
.ToggleSelectionAt(1);
2541 MockTabStripModelObserver
observer(&strip
);
2542 strip
.AddObserver(&observer
);
2543 // This changes the selection (0 is no longer selected) but the selected_index
2544 // still remains at 1.
2545 strip
.ActivateTabAt(1, true);
2546 ASSERT_EQ(1, observer
.GetStateCount());
2547 State
s(contents2
, 1, MockTabStripModelObserver::SELECT
);
2548 s
.src_contents
= contents2
;
2550 s
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
2551 EXPECT_TRUE(observer
.StateEquals(0, s
));
2552 strip
.RemoveObserver(&observer
);
2553 strip
.CloseAllTabs();
2556 // Verifies a newly inserted tab retains its previous blocked state.
2557 // http://crbug.com/276334
2558 TEST_F(TabStripModelTest
, TabBlockedState
) {
2559 // Start with a source tab strip.
2560 TabStripDummyDelegate dummy_tab_strip_delegate
;
2561 TabStripModel
strip_src(&dummy_tab_strip_delegate
, profile());
2562 TabBlockedStateTestBrowser
browser_src(&strip_src
);
2565 WebContents
* contents1
= CreateWebContents();
2566 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents1
);
2567 strip_src
.AppendWebContents(contents1
, false);
2570 WebContents
* contents2
= CreateWebContents();
2571 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents2
);
2572 strip_src
.AppendWebContents(contents2
, false);
2574 // Create a destination tab strip.
2575 TabStripModel
strip_dst(&dummy_tab_strip_delegate
, profile());
2576 TabBlockedStateTestBrowser
browser_dst(&strip_dst
);
2578 // Setup a SingleWebContentsDialogManager for tab |contents2|.
2579 web_modal::WebContentsModalDialogManager
* modal_dialog_manager
=
2580 web_modal::WebContentsModalDialogManager::FromWebContents(contents2
);
2582 // Show a dialog that blocks tab |contents2|.
2583 // DummySingleWebContentsDialogManager doesn't care about the
2584 // dialog window value, so any dummy value works.
2585 DummySingleWebContentsDialogManager
* native_manager
=
2586 new DummySingleWebContentsDialogManager(
2587 reinterpret_cast<gfx::NativeWindow
>(0), modal_dialog_manager
);
2588 modal_dialog_manager
->ShowDialogWithManager(
2589 reinterpret_cast<gfx::NativeWindow
>(0),
2590 scoped_ptr
<web_modal::SingleWebContentsDialogManager
>(
2591 native_manager
).Pass());
2592 EXPECT_TRUE(strip_src
.IsTabBlocked(1));
2595 WebContents
* moved_contents
= strip_src
.DetachWebContentsAt(1);
2596 EXPECT_EQ(contents2
, moved_contents
);
2598 // Attach the tab to the destination tab strip.
2599 strip_dst
.AppendWebContents(moved_contents
, true);
2600 EXPECT_TRUE(strip_dst
.IsTabBlocked(0));
2602 strip_dst
.CloseAllTabs();
2603 strip_src
.CloseAllTabs();
2606 // Verifies ordering of tabs opened via a link from a pinned tab with a
2607 // subsequent pinned tab.
2608 TEST_F(TabStripModelTest
, LinkClicksWithPinnedTabOrdering
) {
2609 TabStripDummyDelegate delegate
;
2610 TabStripModel
strip(&delegate
, profile());
2612 // Open two pages, pinned.
2613 WebContents
* page_a_contents
= CreateWebContents();
2614 strip
.AddWebContents(page_a_contents
, -1,
2615 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2616 TabStripModel::ADD_ACTIVE
| TabStripModel::ADD_PINNED
);
2617 WebContents
* page_b_contents
= CreateWebContents();
2618 strip
.AddWebContents(page_b_contents
, -1,
2619 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2620 TabStripModel::ADD_ACTIVE
| TabStripModel::ADD_PINNED
);
2622 // Activate the first tab (a).
2623 strip
.ActivateTabAt(0, true);
2625 // Open two more tabs as link clicks. The first tab, c, should appear after
2626 // the pinned tabs followed by the second tab (d).
2627 WebContents
* page_c_contents
= CreateWebContents();
2628 WebContents
* page_d_contents
= CreateWebContents();
2629 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2630 TabStripModel::ADD_NONE
);
2631 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2632 TabStripModel::ADD_NONE
);
2634 EXPECT_EQ(2, strip
.GetIndexOfWebContents(page_c_contents
));
2635 EXPECT_EQ(3, strip
.GetIndexOfWebContents(page_d_contents
));
2636 strip
.CloseAllTabs();