1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/tabs/tab_strip_model.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/defaults.h"
18 #include "chrome/browser/extensions/tab_helper.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_tabstrip.h"
22 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
24 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
25 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "components/web_modal/web_contents_modal_dialog_manager.h"
30 #include "content/public/browser/navigation_controller.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/render_process_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/browser/web_contents_observer.h"
35 #include "content/public/test/web_contents_tester.h"
36 #include "extensions/common/extension.h"
37 #include "testing/gtest/include/gtest/gtest.h"
39 using content::SiteInstance
;
40 using content::WebContents
;
41 using content::WebContentsTester
;
42 using extensions::Extension
;
46 // Class used to delete a WebContents and TabStripModel when another WebContents
48 class DeleteWebContentsOnDestroyedObserver
49 : public content::WebContentsObserver
{
51 // When |source| is deleted both |tab_to_delete| and |tab_strip| are deleted.
52 // |tab_to_delete| and |tab_strip| may be NULL.
53 DeleteWebContentsOnDestroyedObserver(WebContents
* source
,
54 WebContents
* tab_to_delete
,
55 TabStripModel
* tab_strip
)
56 : WebContentsObserver(source
),
57 tab_to_delete_(tab_to_delete
),
58 tab_strip_(tab_strip
) {
61 void WebContentsDestroyed() override
{
62 WebContents
* tab_to_delete
= tab_to_delete_
;
63 tab_to_delete_
= NULL
;
64 TabStripModel
* tab_strip_to_delete
= tab_strip_
;
67 delete tab_strip_to_delete
;
71 WebContents
* tab_to_delete_
;
72 TabStripModel
* tab_strip_
;
74 DISALLOW_COPY_AND_ASSIGN(DeleteWebContentsOnDestroyedObserver
);
77 class TabStripDummyDelegate
: public TestTabStripModelDelegate
{
79 TabStripDummyDelegate() : run_unload_(false) {}
80 ~TabStripDummyDelegate() override
{}
82 void set_run_unload_listener(bool value
) { run_unload_
= value
; }
84 bool RunUnloadListenerBeforeClosing(WebContents
* contents
) override
{
89 // Whether to report that we need to run an unload listener before closing.
92 DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate
);
95 const char kTabStripModelTestIDUserDataKey
[] = "TabStripModelTestIDUserData";
97 class TabStripModelTestIDUserData
: public base::SupportsUserData::Data
{
99 explicit TabStripModelTestIDUserData(int id
) : id_(id
) {}
100 ~TabStripModelTestIDUserData() override
{}
101 int id() { return id_
; }
107 class DummySingleWebContentsDialogManager
108 : public web_modal::SingleWebContentsDialogManager
{
110 explicit DummySingleWebContentsDialogManager(
111 gfx::NativeWindow dialog
,
112 web_modal::SingleWebContentsDialogManagerDelegate
* delegate
)
113 : delegate_(delegate
),
115 ~DummySingleWebContentsDialogManager() override
{}
117 void Show() override
{}
118 void Hide() override
{}
119 void Close() override
{ delegate_
->WillClose(dialog_
); }
120 void Focus() override
{}
121 void Pulse() override
{}
122 void HostChanged(web_modal::WebContentsModalDialogHost
* new_host
) override
{}
123 gfx::NativeWindow
dialog() override
{ return dialog_
; }
126 web_modal::SingleWebContentsDialogManagerDelegate
* delegate_
;
127 gfx::NativeWindow dialog_
;
129 DISALLOW_COPY_AND_ASSIGN(DummySingleWebContentsDialogManager
);
132 // Test Browser-like class for TabStripModelTest.TabBlockedState.
133 class TabBlockedStateTestBrowser
134 : public TabStripModelObserver
,
135 public web_modal::WebContentsModalDialogManagerDelegate
{
137 explicit TabBlockedStateTestBrowser(TabStripModel
* tab_strip_model
)
138 : tab_strip_model_(tab_strip_model
) {
139 tab_strip_model_
->AddObserver(this);
142 ~TabBlockedStateTestBrowser() override
{
143 tab_strip_model_
->RemoveObserver(this);
147 // TabStripModelObserver
148 void TabInsertedAt(WebContents
* contents
,
150 bool foreground
) override
{
151 web_modal::WebContentsModalDialogManager
* manager
=
152 web_modal::WebContentsModalDialogManager::FromWebContents(contents
);
154 manager
->SetDelegate(this);
157 // WebContentsModalDialogManagerDelegate
158 void SetWebContentsBlocked(content::WebContents
* contents
,
159 bool blocked
) override
{
160 int index
= tab_strip_model_
->GetIndexOfWebContents(contents
);
162 tab_strip_model_
->SetTabBlocked(index
, blocked
);
165 TabStripModel
* tab_strip_model_
;
167 DISALLOW_COPY_AND_ASSIGN(TabBlockedStateTestBrowser
);
172 class TabStripModelTest
: public ChromeRenderViewHostTestHarness
{
174 WebContents
* CreateWebContents() {
175 return WebContents::Create(WebContents::CreateParams(profile()));
178 WebContents
* CreateWebContentsWithSharedRPH(WebContents
* web_contents
) {
179 WebContents::CreateParams
create_params(
180 profile(), web_contents
->GetRenderViewHost()->GetSiteInstance());
181 WebContents
* retval
= WebContents::Create(create_params
);
182 EXPECT_EQ(retval
->GetRenderProcessHost(),
183 web_contents
->GetRenderProcessHost());
187 WebContents
* CreateWebContentsWithID(int id
) {
188 WebContents
* contents
= CreateWebContents();
193 // Sets the id of the specified contents.
194 void SetID(WebContents
* contents
, int id
) {
195 contents
->SetUserData(&kTabStripModelTestIDUserDataKey
,
196 new TabStripModelTestIDUserData(id
));
199 // Returns the id of the specified contents.
200 int GetID(WebContents
* contents
) {
201 TabStripModelTestIDUserData
* user_data
=
202 static_cast<TabStripModelTestIDUserData
*>(
203 contents
->GetUserData(&kTabStripModelTestIDUserDataKey
));
205 return user_data
? user_data
->id() : -1;
208 // Returns the state of the given tab strip as a string. The state consists
209 // of the ID of each web contents followed by a 'p' if pinned. For example,
210 // if the model consists of two tabs with ids 2 and 1, with the first
211 // tab pinned, this returns "2p 1".
212 std::string
GetTabStripStateString(const TabStripModel
& model
) {
214 for (int i
= 0; i
< model
.count(); ++i
) {
218 actual
+= base::IntToString(GetID(model
.GetWebContentsAt(i
)));
220 if (model
.IsTabPinned(i
))
226 std::string
GetIndicesClosedByCommandAsString(
227 const TabStripModel
& model
,
229 TabStripModel::ContextMenuCommand id
) const {
230 std::vector
<int> indices
= model
.GetIndicesClosedByCommand(index
, id
);
232 for (size_t i
= 0; i
< indices
.size(); ++i
) {
235 result
+= base::IntToString(indices
[i
]);
240 void PrepareTabstripForSelectionTest(TabStripModel
* model
,
243 const std::string
& selected_tabs
) {
244 for (int i
= 0; i
< tab_count
; ++i
)
245 model
->AppendWebContents(CreateWebContentsWithID(i
), true);
246 for (int i
= 0; i
< pinned_count
; ++i
)
247 model
->SetTabPinned(i
, true);
249 ui::ListSelectionModel selection_model
;
250 for (const base::StringPiece
& sel
: base::SplitStringPiece(
251 selected_tabs
, base::kWhitespaceASCII
,
252 base::TRIM_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
)) {
254 ASSERT_TRUE(base::StringToInt(sel
, &value
));
255 selection_model
.AddIndexToSelection(value
);
257 selection_model
.set_active(selection_model
.selected_indices()[0]);
258 model
->SetSelectionFromModel(selection_model
);
262 class MockTabStripModelObserver
: public TabStripModelObserver
{
264 explicit MockTabStripModelObserver(TabStripModel
* model
)
268 ~MockTabStripModelObserver() override
{}
270 enum TabStripModelObserverAction
{
286 State(WebContents
* a_dst_contents
,
288 TabStripModelObserverAction a_action
)
289 : src_contents(NULL
),
290 dst_contents(a_dst_contents
),
292 dst_index(a_dst_index
),
293 change_reason(CHANGE_REASON_NONE
),
298 WebContents
* src_contents
;
299 WebContents
* dst_contents
;
304 TabStripModelObserverAction action
;
307 int GetStateCount() const {
308 return static_cast<int>(states_
.size());
311 // Returns (by way of parameters) the number of state's with CLOSE_ALL and
312 // CLOSE_ALL_CANCELED.
313 void GetCloseCounts(int* close_all_count
,
314 int* close_all_canceled_count
) {
315 *close_all_count
= *close_all_canceled_count
= 0;
316 for (int i
= 0; i
< GetStateCount(); ++i
) {
317 switch (GetStateAt(i
).action
) {
319 (*close_all_count
)++;
321 case CLOSE_ALL_CANCELED
:
322 (*close_all_canceled_count
)++;
330 const State
& GetStateAt(int index
) const {
331 DCHECK(index
>= 0 && index
< GetStateCount());
332 return states_
[index
];
335 bool StateEquals(int index
, const State
& state
) {
336 const State
& s
= GetStateAt(index
);
337 return (s
.src_contents
== state
.src_contents
&&
338 s
.dst_contents
== state
.dst_contents
&&
339 s
.src_index
== state
.src_index
&&
340 s
.dst_index
== state
.dst_index
&&
341 s
.change_reason
== state
.change_reason
&&
342 s
.foreground
== state
.foreground
&&
343 s
.action
== state
.action
);
346 // TabStripModelObserver implementation:
347 void TabInsertedAt(WebContents
* contents
,
349 bool foreground
) override
{
351 State
s(contents
, index
, INSERT
);
352 s
.foreground
= foreground
;
353 states_
.push_back(s
);
355 void ActiveTabChanged(WebContents
* old_contents
,
356 WebContents
* new_contents
,
358 int reason
) override
{
359 State
s(new_contents
, index
, ACTIVATE
);
360 s
.src_contents
= old_contents
;
361 s
.change_reason
= reason
;
362 states_
.push_back(s
);
364 void TabSelectionChanged(TabStripModel
* tab_strip_model
,
365 const ui::ListSelectionModel
& old_model
) override
{
366 State
s(model()->GetActiveWebContents(), model()->active_index(), SELECT
);
367 s
.src_contents
= model()->GetWebContentsAt(old_model
.active());
368 s
.src_index
= old_model
.active();
369 states_
.push_back(s
);
371 void TabMoved(WebContents
* contents
, int from_index
, int to_index
) override
{
372 State
s(contents
, to_index
, MOVE
);
373 s
.src_index
= from_index
;
374 states_
.push_back(s
);
377 void TabClosingAt(TabStripModel
* tab_strip_model
,
378 WebContents
* contents
,
379 int index
) override
{
380 states_
.push_back(State(contents
, index
, CLOSE
));
382 void TabDetachedAt(WebContents
* contents
, int index
) override
{
383 states_
.push_back(State(contents
, index
, DETACH
));
385 void TabDeactivated(WebContents
* contents
) override
{
386 states_
.push_back(State(contents
, model()->active_index(), DEACTIVATE
));
388 void TabChangedAt(WebContents
* contents
,
390 TabChangeType change_type
) override
{
391 states_
.push_back(State(contents
, index
, CHANGE
));
393 void TabReplacedAt(TabStripModel
* tab_strip_model
,
394 WebContents
* old_contents
,
395 WebContents
* new_contents
,
396 int index
) override
{
397 State
s(new_contents
, index
, REPLACED
);
398 s
.src_contents
= old_contents
;
399 states_
.push_back(s
);
401 void TabPinnedStateChanged(WebContents
* contents
, int index
) override
{
402 states_
.push_back(State(contents
, index
, PINNED
));
404 void TabStripEmpty() override
{ empty_
= true; }
405 void WillCloseAllTabs() override
{
406 states_
.push_back(State(NULL
, -1, CLOSE_ALL
));
408 void CloseAllTabsCanceled() override
{
409 states_
.push_back(State(NULL
, -1, CLOSE_ALL_CANCELED
));
411 void TabStripModelDeleted() override
{ deleted_
= true; }
417 bool empty() const { return empty_
; }
418 bool deleted() const { return deleted_
; }
419 TabStripModel
* model() { return model_
; }
422 std::vector
<State
> states_
;
426 TabStripModel
* model_
;
428 DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver
);
431 TEST_F(TabStripModelTest
, TestBasicAPI
) {
432 TabStripDummyDelegate delegate
;
433 TabStripModel
tabstrip(&delegate
, profile());
434 MockTabStripModelObserver
observer(&tabstrip
);
435 tabstrip
.AddObserver(&observer
);
437 EXPECT_TRUE(tabstrip
.empty());
439 typedef MockTabStripModelObserver::State State
;
441 WebContents
* contents1
= CreateWebContentsWithID(1);
443 // Note! The ordering of these tests is important, each subsequent test
444 // builds on the state established in the previous. This is important if you
445 // ever insert tests rather than append.
447 // Test AppendWebContents, ContainsIndex
449 EXPECT_FALSE(tabstrip
.ContainsIndex(0));
450 tabstrip
.AppendWebContents(contents1
, true);
451 EXPECT_TRUE(tabstrip
.ContainsIndex(0));
452 EXPECT_EQ(1, tabstrip
.count());
453 EXPECT_EQ(3, observer
.GetStateCount());
454 State
s1(contents1
, 0, MockTabStripModelObserver::INSERT
);
455 s1
.foreground
= true;
456 EXPECT_TRUE(observer
.StateEquals(0, s1
));
457 State
s2(contents1
, 0, MockTabStripModelObserver::ACTIVATE
);
458 EXPECT_TRUE(observer
.StateEquals(1, s2
));
459 State
s3(contents1
, 0, MockTabStripModelObserver::SELECT
);
460 s3
.src_contents
= NULL
;
461 s3
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
462 EXPECT_TRUE(observer
.StateEquals(2, s3
));
463 observer
.ClearStates();
465 EXPECT_EQ("1", GetTabStripStateString(tabstrip
));
467 // Test InsertWebContentsAt, foreground tab.
468 WebContents
* contents2
= CreateWebContentsWithID(2);
470 tabstrip
.InsertWebContentsAt(1, contents2
, TabStripModel::ADD_ACTIVE
);
472 EXPECT_EQ(2, tabstrip
.count());
473 EXPECT_EQ(4, observer
.GetStateCount());
474 State
s1(contents2
, 1, MockTabStripModelObserver::INSERT
);
475 s1
.foreground
= true;
476 EXPECT_TRUE(observer
.StateEquals(0, s1
));
477 State
s2(contents1
, 0, MockTabStripModelObserver::DEACTIVATE
);
478 EXPECT_TRUE(observer
.StateEquals(1, s2
));
479 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
480 s3
.src_contents
= contents1
;
481 EXPECT_TRUE(observer
.StateEquals(2, s3
));
482 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
483 s4
.src_contents
= contents1
;
485 EXPECT_TRUE(observer
.StateEquals(3, s4
));
486 observer
.ClearStates();
488 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
490 // Test InsertWebContentsAt, background tab.
491 WebContents
* contents3
= CreateWebContentsWithID(3);
493 tabstrip
.InsertWebContentsAt(2, contents3
, TabStripModel::ADD_NONE
);
495 EXPECT_EQ(3, tabstrip
.count());
496 EXPECT_EQ(1, observer
.GetStateCount());
497 State
s1(contents3
, 2, MockTabStripModelObserver::INSERT
);
498 s1
.foreground
= false;
499 EXPECT_TRUE(observer
.StateEquals(0, s1
));
500 observer
.ClearStates();
502 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
504 // Test ActivateTabAt
506 tabstrip
.ActivateTabAt(2, true);
507 EXPECT_EQ(3, observer
.GetStateCount());
508 State
s1(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
509 EXPECT_TRUE(observer
.StateEquals(0, s1
));
510 State
s2(contents3
, 2, MockTabStripModelObserver::ACTIVATE
);
511 s2
.src_contents
= contents2
;
512 s2
.change_reason
= TabStripModelObserver::CHANGE_REASON_USER_GESTURE
;
513 EXPECT_TRUE(observer
.StateEquals(1, s2
));
514 State
s3(contents3
, 2, MockTabStripModelObserver::SELECT
);
515 s3
.src_contents
= contents2
;
517 EXPECT_TRUE(observer
.StateEquals(2, s3
));
518 observer
.ClearStates();
520 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
522 // Test DetachWebContentsAt
525 WebContents
* detached
= tabstrip
.DetachWebContentsAt(2);
526 // ... and append again because we want this for later.
527 tabstrip
.AppendWebContents(detached
, true);
528 EXPECT_EQ(8, observer
.GetStateCount());
529 State
s1(detached
, 2, MockTabStripModelObserver::DETACH
);
530 EXPECT_TRUE(observer
.StateEquals(0, s1
));
531 State
s2(detached
, ui::ListSelectionModel::kUnselectedIndex
,
532 MockTabStripModelObserver::DEACTIVATE
);
533 EXPECT_TRUE(observer
.StateEquals(1, s2
));
534 State
s3(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
535 s3
.src_contents
= contents3
;
536 s3
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
537 EXPECT_TRUE(observer
.StateEquals(2, s3
));
538 State
s4(contents2
, 1, MockTabStripModelObserver::SELECT
);
539 s4
.src_contents
= NULL
;
540 s4
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
541 EXPECT_TRUE(observer
.StateEquals(3, s4
));
542 State
s5(detached
, 2, MockTabStripModelObserver::INSERT
);
543 s5
.foreground
= true;
544 EXPECT_TRUE(observer
.StateEquals(4, s5
));
545 State
s6(contents2
, 1, MockTabStripModelObserver::DEACTIVATE
);
546 EXPECT_TRUE(observer
.StateEquals(5, s6
));
547 State
s7(detached
, 2, MockTabStripModelObserver::ACTIVATE
);
548 s7
.src_contents
= contents2
;
549 s7
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
550 EXPECT_TRUE(observer
.StateEquals(6, s7
));
551 State
s8(detached
, 2, MockTabStripModelObserver::SELECT
);
552 s8
.src_contents
= contents2
;
554 EXPECT_TRUE(observer
.StateEquals(7, s8
));
555 observer
.ClearStates();
557 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
559 // Test CloseWebContentsAt
561 EXPECT_TRUE(tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
));
562 EXPECT_EQ(2, tabstrip
.count());
564 EXPECT_EQ(5, observer
.GetStateCount());
565 State
s1(contents3
, 2, MockTabStripModelObserver::CLOSE
);
566 EXPECT_TRUE(observer
.StateEquals(0, s1
));
567 State
s2(contents3
, 2, MockTabStripModelObserver::DETACH
);
568 EXPECT_TRUE(observer
.StateEquals(1, s2
));
569 State
s3(contents3
, ui::ListSelectionModel::kUnselectedIndex
,
570 MockTabStripModelObserver::DEACTIVATE
);
571 EXPECT_TRUE(observer
.StateEquals(2, s3
));
572 State
s4(contents2
, 1, MockTabStripModelObserver::ACTIVATE
);
573 s4
.src_contents
= contents3
;
574 s4
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
575 EXPECT_TRUE(observer
.StateEquals(3, s4
));
576 State
s5(contents2
, 1, MockTabStripModelObserver::SELECT
);
577 s5
.src_contents
= NULL
;
578 s5
.src_index
= ui::ListSelectionModel::kUnselectedIndex
;
579 EXPECT_TRUE(observer
.StateEquals(4, s5
));
580 observer
.ClearStates();
582 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
584 // Test MoveWebContentsAt, select_after_move == true
586 tabstrip
.MoveWebContentsAt(1, 0, true);
588 EXPECT_EQ(1, observer
.GetStateCount());
589 State
s1(contents2
, 0, MockTabStripModelObserver::MOVE
);
591 EXPECT_TRUE(observer
.StateEquals(0, s1
));
592 EXPECT_EQ(0, tabstrip
.active_index());
593 observer
.ClearStates();
595 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
597 // Test MoveWebContentsAt, select_after_move == false
599 tabstrip
.MoveWebContentsAt(1, 0, false);
600 EXPECT_EQ(1, observer
.GetStateCount());
601 State
s1(contents1
, 0, MockTabStripModelObserver::MOVE
);
603 EXPECT_TRUE(observer
.StateEquals(0, s1
));
604 EXPECT_EQ(1, tabstrip
.active_index());
606 tabstrip
.MoveWebContentsAt(0, 1, false);
607 observer
.ClearStates();
609 EXPECT_EQ("2 1", GetTabStripStateString(tabstrip
));
613 EXPECT_EQ(contents2
, tabstrip
.GetActiveWebContents());
614 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(0));
615 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
616 EXPECT_EQ(0, tabstrip
.GetIndexOfWebContents(contents2
));
617 EXPECT_EQ(1, tabstrip
.GetIndexOfWebContents(contents1
));
620 // Test UpdateWebContentsStateAt
622 tabstrip
.UpdateWebContentsStateAt(0, TabStripModelObserver::ALL
);
623 EXPECT_EQ(1, observer
.GetStateCount());
624 State
s1(contents2
, 0, MockTabStripModelObserver::CHANGE
);
625 EXPECT_TRUE(observer
.StateEquals(0, s1
));
626 observer
.ClearStates();
629 // Test SelectNextTab, SelectPreviousTab, SelectLastTab
631 // Make sure the second of the two tabs is selected first...
632 tabstrip
.ActivateTabAt(1, true);
633 tabstrip
.SelectPreviousTab();
634 EXPECT_EQ(0, tabstrip
.active_index());
635 tabstrip
.SelectLastTab();
636 EXPECT_EQ(1, tabstrip
.active_index());
637 tabstrip
.SelectNextTab();
638 EXPECT_EQ(0, tabstrip
.active_index());
641 // Test CloseSelectedTabs
643 tabstrip
.CloseSelectedTabs();
644 // |CloseSelectedTabs| calls CloseWebContentsAt, we already tested that, now
645 // just verify that the count and selected index have changed
647 EXPECT_EQ(1, tabstrip
.count());
648 EXPECT_EQ(0, tabstrip
.active_index());
651 observer
.ClearStates();
652 tabstrip
.CloseAllTabs();
654 int close_all_count
= 0, close_all_canceled_count
= 0;
655 observer
.GetCloseCounts(&close_all_count
, &close_all_canceled_count
);
656 EXPECT_EQ(1, close_all_count
);
657 EXPECT_EQ(0, close_all_canceled_count
);
659 // TabStripModel should now be empty.
660 EXPECT_TRUE(tabstrip
.empty());
662 // Opener methods are tested below...
664 tabstrip
.RemoveObserver(&observer
);
667 TEST_F(TabStripModelTest
, TestBasicOpenerAPI
) {
668 TabStripDummyDelegate delegate
;
669 TabStripModel
tabstrip(&delegate
, profile());
670 EXPECT_TRUE(tabstrip
.empty());
672 // This is a basic test of opener functionality. opener is created
673 // as the first tab in the strip and then we create 5 other tabs in the
674 // background with opener set as their opener.
676 WebContents
* opener
= CreateWebContents();
677 tabstrip
.AppendWebContents(opener
, true);
678 WebContents
* contents1
= CreateWebContents();
679 WebContents
* contents2
= CreateWebContents();
680 WebContents
* contents3
= CreateWebContents();
681 WebContents
* contents4
= CreateWebContents();
682 WebContents
* contents5
= CreateWebContents();
684 // We use |InsertWebContentsAt| here instead of |AppendWebContents| so that
685 // openership relationships are preserved.
686 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents1
,
687 TabStripModel::ADD_INHERIT_GROUP
);
688 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents2
,
689 TabStripModel::ADD_INHERIT_GROUP
);
690 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents3
,
691 TabStripModel::ADD_INHERIT_GROUP
);
692 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents4
,
693 TabStripModel::ADD_INHERIT_GROUP
);
694 tabstrip
.InsertWebContentsAt(tabstrip
.count(), contents5
,
695 TabStripModel::ADD_INHERIT_GROUP
);
697 // All the tabs should have the same opener.
698 for (int i
= 1; i
< tabstrip
.count(); ++i
)
699 EXPECT_EQ(opener
, tabstrip
.GetOpenerOfWebContentsAt(i
));
701 // If there is a next adjacent item, then the index should be of that item.
702 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
703 // If the last tab in the group is closed, the preceding tab in the same
704 // group should be selected.
705 EXPECT_EQ(4, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
707 // Tests the method that finds the last tab opened by the same opener in the
708 // strip (this is the insertion index for the next background tab for the
709 // specified opener).
710 EXPECT_EQ(5, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
712 // For a tab that has opened no other tabs, the return value should always be
715 tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents1
, 3, false));
717 tabstrip
.GetIndexOfLastWebContentsOpenedBy(contents1
, 3));
719 // ForgetAllOpeners should destroy all opener relationships.
720 tabstrip
.ForgetAllOpeners();
721 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 1, false));
722 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 5, false));
723 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
725 // Specify the last tab as the opener of the others.
726 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
727 tabstrip
.SetOpenerOfWebContentsAt(i
, contents5
);
729 for (int i
= 0; i
< tabstrip
.count() - 1; ++i
)
730 EXPECT_EQ(contents5
, tabstrip
.GetOpenerOfWebContentsAt(i
));
732 // If there is a next adjacent item, then the index should be of that item.
733 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 1, false));
735 // If the last tab in the group is closed, the preceding tab in the same
736 // group should be selected.
737 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(contents5
, 4, false));
739 tabstrip
.CloseAllTabs();
740 EXPECT_TRUE(tabstrip
.empty());
743 static int GetInsertionIndex(TabStripModel
* tabstrip
) {
744 return tabstrip
->order_controller()->DetermineInsertionIndex(
745 ui::PAGE_TRANSITION_LINK
, false);
748 static void InsertWebContentses(TabStripModel
* tabstrip
,
749 WebContents
* contents1
,
750 WebContents
* contents2
,
751 WebContents
* contents3
) {
752 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
754 TabStripModel::ADD_INHERIT_GROUP
);
755 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
757 TabStripModel::ADD_INHERIT_GROUP
);
758 tabstrip
->InsertWebContentsAt(GetInsertionIndex(tabstrip
),
760 TabStripModel::ADD_INHERIT_GROUP
);
763 // Tests opening background tabs.
764 TEST_F(TabStripModelTest
, TestLTRInsertionOptions
) {
765 TabStripDummyDelegate delegate
;
766 TabStripModel
tabstrip(&delegate
, profile());
767 EXPECT_TRUE(tabstrip
.empty());
769 WebContents
* opener
= CreateWebContents();
770 tabstrip
.AppendWebContents(opener
, true);
772 WebContents
* contents1
= CreateWebContents();
773 WebContents
* contents2
= CreateWebContents();
774 WebContents
* contents3
= CreateWebContents();
777 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
778 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
779 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
780 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
782 tabstrip
.CloseAllTabs();
783 EXPECT_TRUE(tabstrip
.empty());
786 // This test constructs a tabstrip, and then simulates loading several tabs in
787 // the background from link clicks on the first tab. Then it simulates opening
788 // a new tab from the first tab in the foreground via a link click, verifies
789 // that this tab is opened adjacent to the opener, then closes it.
790 // Finally it tests that a tab opened for some non-link purpose opens at the
791 // end of the strip, not bundled to any existing context.
792 TEST_F(TabStripModelTest
, TestInsertionIndexDetermination
) {
793 TabStripDummyDelegate delegate
;
794 TabStripModel
tabstrip(&delegate
, profile());
795 EXPECT_TRUE(tabstrip
.empty());
797 WebContents
* opener
= CreateWebContents();
798 tabstrip
.AppendWebContents(opener
, true);
800 // Open some other random unrelated tab in the background to monkey with our
802 WebContents
* other
= CreateWebContents();
803 tabstrip
.AppendWebContents(other
, false);
805 WebContents
* contents1
= CreateWebContents();
806 WebContents
* contents2
= CreateWebContents();
807 WebContents
* contents3
= CreateWebContents();
809 // Start by testing LTR.
810 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
811 EXPECT_EQ(opener
, tabstrip
.GetWebContentsAt(0));
812 EXPECT_EQ(contents1
, tabstrip
.GetWebContentsAt(1));
813 EXPECT_EQ(contents2
, tabstrip
.GetWebContentsAt(2));
814 EXPECT_EQ(contents3
, tabstrip
.GetWebContentsAt(3));
815 EXPECT_EQ(other
, tabstrip
.GetWebContentsAt(4));
817 // The opener API should work...
818 EXPECT_EQ(3, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
819 EXPECT_EQ(2, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
820 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
822 // Now open a foreground tab from a link. It should be opened adjacent to the
824 WebContents
* fg_link_contents
= CreateWebContents();
825 int insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
826 ui::PAGE_TRANSITION_LINK
, true);
827 EXPECT_EQ(1, insert_index
);
828 tabstrip
.InsertWebContentsAt(insert_index
, fg_link_contents
,
829 TabStripModel::ADD_ACTIVE
|
830 TabStripModel::ADD_INHERIT_GROUP
);
831 EXPECT_EQ(1, tabstrip
.active_index());
832 EXPECT_EQ(fg_link_contents
, tabstrip
.GetActiveWebContents());
834 // Now close this contents. The selection should move to the opener contents.
835 tabstrip
.CloseSelectedTabs();
836 EXPECT_EQ(0, tabstrip
.active_index());
838 // Now open a new empty tab. It should open at the end of the strip.
839 WebContents
* fg_nonlink_contents
= CreateWebContents();
840 insert_index
= tabstrip
.order_controller()->DetermineInsertionIndex(
841 ui::PAGE_TRANSITION_AUTO_BOOKMARK
, true);
842 EXPECT_EQ(tabstrip
.count(), insert_index
);
843 // We break the opener relationship...
844 tabstrip
.InsertWebContentsAt(insert_index
,
846 TabStripModel::ADD_NONE
);
847 // Now select it, so that user_gesture == true causes the opener relationship
848 // to be forgotten...
849 tabstrip
.ActivateTabAt(tabstrip
.count() - 1, true);
850 EXPECT_EQ(tabstrip
.count() - 1, tabstrip
.active_index());
851 EXPECT_EQ(fg_nonlink_contents
, tabstrip
.GetActiveWebContents());
853 // Verify that all opener relationships are forgotten.
854 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 2, false));
855 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
856 EXPECT_EQ(-1, tabstrip
.GetIndexOfNextWebContentsOpenedBy(opener
, 3, false));
857 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener
, 1));
859 tabstrip
.CloseAllTabs();
860 EXPECT_TRUE(tabstrip
.empty());
863 // Tests that non-adjacent tabs with an opener are ignored when deciding where
865 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationAfterDragged
) {
866 TabStripDummyDelegate delegate
;
867 TabStripModel
tabstrip(&delegate
, profile());
868 EXPECT_TRUE(tabstrip
.empty());
870 // Start with three tabs, of which the first is active.
871 WebContents
* opener1
= CreateWebContentsWithID(1);
872 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
873 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
874 tabstrip
.AppendWebContents(CreateWebContentsWithID(3), false);
875 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
876 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
877 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
879 // Open a link in a new background tab.
880 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
881 CreateWebContentsWithID(11),
882 TabStripModel::ADD_INHERIT_GROUP
);
883 EXPECT_EQ("1 11 2 3", GetTabStripStateString(tabstrip
));
884 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
885 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
887 // Drag that tab (which activates it) one to the right.
888 tabstrip
.MoveWebContentsAt(1, 2, true /* select_after_move */);
889 EXPECT_EQ("1 2 11 3", GetTabStripStateString(tabstrip
));
890 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
891 // It should no longer be counted by GetIndexOfLastWebContentsOpenedBy,
892 // since there is a tab in between, even though its opener is unchanged.
893 // TODO(johnme): Maybe its opener should be reset when it's dragged away.
894 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
895 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(2));
897 // Activate the parent tab again.
898 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
899 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
901 // Open another link in a new background tab.
902 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
903 CreateWebContentsWithID(12),
904 TabStripModel::ADD_INHERIT_GROUP
);
905 // Tab 12 should be next to 1, and considered opened by it.
906 EXPECT_EQ("1 12 2 11 3", GetTabStripStateString(tabstrip
));
907 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
908 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
910 tabstrip
.CloseAllTabs();
911 EXPECT_TRUE(tabstrip
.empty());
914 // Tests that grandchild tabs are considered to be opened by their grandparent
915 // tab when deciding where to position tabs.
916 TEST_F(TabStripModelTest
, TestInsertionIndexDeterminationNestedOpener
) {
917 TabStripDummyDelegate delegate
;
918 TabStripModel
tabstrip(&delegate
, profile());
919 EXPECT_TRUE(tabstrip
.empty());
921 // Start with two tabs, of which the first is active:
922 WebContents
* opener1
= CreateWebContentsWithID(1);
923 tabstrip
.AppendWebContents(opener1
, true /* foreground */);
924 tabstrip
.AppendWebContents(CreateWebContentsWithID(2), false);
925 EXPECT_EQ("1 2", GetTabStripStateString(tabstrip
));
926 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
927 EXPECT_EQ(-1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
929 // Open a link in a new background child tab.
930 WebContents
* child11
= CreateWebContentsWithID(11);
931 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
933 TabStripModel::ADD_INHERIT_GROUP
);
934 EXPECT_EQ("1 11 2", GetTabStripStateString(tabstrip
));
935 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
936 EXPECT_EQ(1, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
938 // Activate the child tab:
939 tabstrip
.ActivateTabAt(1, true /* user_gesture */);
940 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
942 // Open a link in a new background grandchild tab.
943 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
944 CreateWebContentsWithID(111),
945 TabStripModel::ADD_INHERIT_GROUP
);
946 EXPECT_EQ("1 11 111 2", GetTabStripStateString(tabstrip
));
947 EXPECT_EQ(11, GetID(tabstrip
.GetActiveWebContents()));
948 // The grandchild tab should be counted by GetIndexOfLastWebContentsOpenedBy
949 // as opened by both its parent (child11) and grandparent (opener1).
950 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
951 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
953 // Activate the parent tab again:
954 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
955 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
957 // Open another link in a new background child tab (a sibling of child11).
958 tabstrip
.InsertWebContentsAt(GetInsertionIndex(&tabstrip
),
959 CreateWebContentsWithID(12),
960 TabStripModel::ADD_INHERIT_GROUP
);
961 EXPECT_EQ("1 11 111 12 2", GetTabStripStateString(tabstrip
));
962 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
963 // opener1 has three adjacent descendants (11, 111, 12)
964 EXPECT_EQ(3, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
965 // child11 has only one adjacent descendant (111)
966 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(child11
, 1));
968 // Closing a tab should cause its children to inherit the tab's opener.
969 EXPECT_EQ(true, tabstrip
.CloseWebContentsAt(
971 TabStripModel::CLOSE_USER_GESTURE
|
972 TabStripModel::CLOSE_CREATE_HISTORICAL_TAB
));
973 EXPECT_EQ("1 111 12 2", GetTabStripStateString(tabstrip
));
974 EXPECT_EQ(1, GetID(tabstrip
.GetActiveWebContents()));
975 // opener1 is now the opener of 111, so has two adjacent descendants (111, 12)
976 EXPECT_EQ(opener1
, tabstrip
.GetOpenerOfWebContentsAt(1));
977 EXPECT_EQ(2, tabstrip
.GetIndexOfLastWebContentsOpenedBy(opener1
, 0));
979 tabstrip
.CloseAllTabs();
980 EXPECT_TRUE(tabstrip
.empty());
983 // Tests that selection is shifted to the correct tab when a tab is closed.
984 // If a tab is in the background when it is closed, the selection does not
986 // If a tab is in the foreground (selected),
987 // If that tab does not have an opener, selection shifts to the right.
988 // If the tab has an opener,
989 // The next tab (scanning LTR) in the entire strip that has the same opener
991 // If there are no other tabs that have the same opener,
992 // The opener is selected
994 TEST_F(TabStripModelTest
, TestSelectOnClose
) {
995 TabStripDummyDelegate delegate
;
996 TabStripModel
tabstrip(&delegate
, profile());
997 EXPECT_TRUE(tabstrip
.empty());
999 WebContents
* opener
= CreateWebContents();
1000 tabstrip
.AppendWebContents(opener
, true);
1002 WebContents
* contents1
= CreateWebContents();
1003 WebContents
* contents2
= CreateWebContents();
1004 WebContents
* contents3
= CreateWebContents();
1006 // Note that we use Detach instead of Close throughout this test to avoid
1007 // having to keep reconstructing these WebContentses.
1009 // First test that closing tabs that are in the background doesn't adjust the
1010 // current selection.
1011 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1012 EXPECT_EQ(0, tabstrip
.active_index());
1014 tabstrip
.DetachWebContentsAt(1);
1015 EXPECT_EQ(0, tabstrip
.active_index());
1017 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1018 tabstrip
.DetachWebContentsAt(i
);
1020 // Now test that when a tab doesn't have an opener, selection shifts to the
1021 // right when the tab is closed.
1022 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1023 EXPECT_EQ(0, tabstrip
.active_index());
1025 tabstrip
.ForgetAllOpeners();
1026 tabstrip
.ActivateTabAt(1, true);
1027 EXPECT_EQ(1, tabstrip
.active_index());
1028 tabstrip
.DetachWebContentsAt(1);
1029 EXPECT_EQ(1, tabstrip
.active_index());
1030 tabstrip
.DetachWebContentsAt(1);
1031 EXPECT_EQ(1, tabstrip
.active_index());
1032 tabstrip
.DetachWebContentsAt(1);
1033 EXPECT_EQ(0, tabstrip
.active_index());
1035 for (int i
= tabstrip
.count() - 1; i
>= 1; --i
)
1036 tabstrip
.DetachWebContentsAt(i
);
1038 // Now test that when a tab does have an opener, it selects the next tab
1039 // opened by the same opener scanning LTR when it is closed.
1040 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1041 EXPECT_EQ(0, tabstrip
.active_index());
1042 tabstrip
.ActivateTabAt(2, false);
1043 EXPECT_EQ(2, tabstrip
.active_index());
1044 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1045 EXPECT_EQ(2, tabstrip
.active_index());
1046 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1047 EXPECT_EQ(1, tabstrip
.active_index());
1048 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1049 EXPECT_EQ(0, tabstrip
.active_index());
1050 // Finally test that when a tab has no "siblings" that the opener is
1052 WebContents
* other_contents
= CreateWebContents();
1053 tabstrip
.InsertWebContentsAt(1, other_contents
,
1054 TabStripModel::ADD_NONE
);
1055 EXPECT_EQ(2, tabstrip
.count());
1056 WebContents
* opened_contents
= CreateWebContents();
1057 tabstrip
.InsertWebContentsAt(2, opened_contents
,
1058 TabStripModel::ADD_ACTIVE
|
1059 TabStripModel::ADD_INHERIT_GROUP
);
1060 EXPECT_EQ(2, tabstrip
.active_index());
1061 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1062 EXPECT_EQ(0, tabstrip
.active_index());
1064 tabstrip
.CloseAllTabs();
1065 EXPECT_TRUE(tabstrip
.empty());
1068 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1070 TEST_F(TabStripModelTest
, CommandCloseTab
) {
1071 TabStripDummyDelegate delegate
;
1072 TabStripModel
tabstrip(&delegate
, profile());
1073 EXPECT_TRUE(tabstrip
.empty());
1075 // Make sure can_close is honored.
1076 ASSERT_NO_FATAL_FAILURE(
1077 PrepareTabstripForSelectionTest(&tabstrip
, 1, 0, "0"));
1078 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1079 0, TabStripModel::CommandCloseTab
));
1080 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1081 ASSERT_TRUE(tabstrip
.empty());
1083 // Make sure close on a tab that is selected affects all the selected tabs.
1084 ASSERT_NO_FATAL_FAILURE(
1085 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1086 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1087 0, TabStripModel::CommandCloseTab
));
1088 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1089 // Should have closed tabs 0 and 1.
1090 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1092 tabstrip
.CloseAllTabs();
1093 EXPECT_TRUE(tabstrip
.empty());
1095 // Select two tabs and make close on a tab that isn't selected doesn't affect
1097 ASSERT_NO_FATAL_FAILURE(
1098 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1099 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1100 2, TabStripModel::CommandCloseTab
));
1101 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1102 // Should have closed tab 2.
1103 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1104 tabstrip
.CloseAllTabs();
1105 EXPECT_TRUE(tabstrip
.empty());
1107 // Tests with 3 tabs, one pinned, two tab selected, one of which is pinned.
1108 ASSERT_NO_FATAL_FAILURE(
1109 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1110 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1111 0, TabStripModel::CommandCloseTab
));
1112 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab
);
1113 // Should have closed tab 2.
1114 EXPECT_EQ("2", GetTabStripStateString(tabstrip
));
1115 tabstrip
.CloseAllTabs();
1116 EXPECT_TRUE(tabstrip
.empty());
1119 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1120 // CommandCloseTabs.
1121 TEST_F(TabStripModelTest
, CommandCloseOtherTabs
) {
1122 TabStripDummyDelegate delegate
;
1123 TabStripModel
tabstrip(&delegate
, profile());
1124 EXPECT_TRUE(tabstrip
.empty());
1126 // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
1127 // and close two tabs.
1128 ASSERT_NO_FATAL_FAILURE(
1129 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1130 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1131 0, TabStripModel::CommandCloseOtherTabs
));
1132 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1133 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1134 tabstrip
.CloseAllTabs();
1135 EXPECT_TRUE(tabstrip
.empty());
1137 // Select two tabs, CommandCloseOtherTabs should be enabled and invoking it
1138 // with a non-selected index should close the two other tabs.
1139 ASSERT_NO_FATAL_FAILURE(
1140 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1"));
1141 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1142 2, TabStripModel::CommandCloseOtherTabs
));
1143 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs
);
1144 EXPECT_EQ("0 1", GetTabStripStateString(tabstrip
));
1145 tabstrip
.CloseAllTabs();
1146 EXPECT_TRUE(tabstrip
.empty());
1148 // Select all, CommandCloseOtherTabs should not be enabled.
1149 ASSERT_NO_FATAL_FAILURE(
1150 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "0 1 2"));
1151 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1152 2, TabStripModel::CommandCloseOtherTabs
));
1153 tabstrip
.CloseAllTabs();
1154 EXPECT_TRUE(tabstrip
.empty());
1156 // Three tabs, pin one, select the two non-pinned.
1157 ASSERT_NO_FATAL_FAILURE(
1158 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1 2"));
1159 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1160 1, TabStripModel::CommandCloseOtherTabs
));
1161 // If we don't pass in the pinned index, the command should be enabled.
1162 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1163 0, TabStripModel::CommandCloseOtherTabs
));
1164 tabstrip
.CloseAllTabs();
1165 EXPECT_TRUE(tabstrip
.empty());
1167 // 3 tabs, one pinned.
1168 ASSERT_NO_FATAL_FAILURE(
1169 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "1"));
1170 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1171 1, TabStripModel::CommandCloseOtherTabs
));
1172 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1173 0, TabStripModel::CommandCloseOtherTabs
));
1174 tabstrip
.ExecuteContextMenuCommand(1, TabStripModel::CommandCloseOtherTabs
);
1175 // The pinned tab shouldn't be closed.
1176 EXPECT_EQ("0p 1", GetTabStripStateString(tabstrip
));
1177 tabstrip
.CloseAllTabs();
1178 EXPECT_TRUE(tabstrip
.empty());
1181 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1182 // CommandCloseTabsToRight.
1183 TEST_F(TabStripModelTest
, CommandCloseTabsToRight
) {
1184 TabStripDummyDelegate delegate
;
1185 TabStripModel
tabstrip(&delegate
, profile());
1186 EXPECT_TRUE(tabstrip
.empty());
1188 // Create three tabs, select last two tabs, CommandCloseTabsToRight should
1189 // only be enabled for the first tab.
1190 ASSERT_NO_FATAL_FAILURE(
1191 PrepareTabstripForSelectionTest(&tabstrip
, 3, 0, "1 2"));
1192 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1193 0, TabStripModel::CommandCloseTabsToRight
));
1194 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1195 1, TabStripModel::CommandCloseTabsToRight
));
1196 EXPECT_FALSE(tabstrip
.IsContextMenuCommandEnabled(
1197 2, TabStripModel::CommandCloseTabsToRight
));
1198 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1199 EXPECT_EQ("0", GetTabStripStateString(tabstrip
));
1200 tabstrip
.CloseAllTabs();
1201 EXPECT_TRUE(tabstrip
.empty());
1204 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
1205 // CommandTogglePinned.
1206 TEST_F(TabStripModelTest
, CommandTogglePinned
) {
1207 TabStripDummyDelegate delegate
;
1208 TabStripModel
tabstrip(&delegate
, profile());
1209 EXPECT_TRUE(tabstrip
.empty());
1211 // Create three tabs with one pinned, pin the first two.
1212 ASSERT_NO_FATAL_FAILURE(
1213 PrepareTabstripForSelectionTest(&tabstrip
, 3, 1, "0 1"));
1214 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1215 0, TabStripModel::CommandTogglePinned
));
1216 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1217 1, TabStripModel::CommandTogglePinned
));
1218 EXPECT_TRUE(tabstrip
.IsContextMenuCommandEnabled(
1219 2, TabStripModel::CommandTogglePinned
));
1220 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1221 EXPECT_EQ("0p 1p 2", GetTabStripStateString(tabstrip
));
1223 // Execute CommandTogglePinned again, this should unpin.
1224 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned
);
1225 EXPECT_EQ("0 1 2", GetTabStripStateString(tabstrip
));
1228 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandTogglePinned
);
1229 EXPECT_EQ("2p 0 1", GetTabStripStateString(tabstrip
));
1231 tabstrip
.CloseAllTabs();
1232 EXPECT_TRUE(tabstrip
.empty());
1235 // Tests the following context menu commands:
1237 // - Close Other Tabs
1238 // - Close Tabs To Right
1239 TEST_F(TabStripModelTest
, TestContextMenuCloseCommands
) {
1240 TabStripDummyDelegate delegate
;
1241 TabStripModel
tabstrip(&delegate
, profile());
1242 EXPECT_TRUE(tabstrip
.empty());
1244 WebContents
* opener
= CreateWebContents();
1245 tabstrip
.AppendWebContents(opener
, true);
1247 WebContents
* contents1
= CreateWebContents();
1248 WebContents
* contents2
= CreateWebContents();
1249 WebContents
* contents3
= CreateWebContents();
1251 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1252 EXPECT_EQ(0, tabstrip
.active_index());
1254 tabstrip
.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab
);
1255 EXPECT_EQ(3, tabstrip
.count());
1257 tabstrip
.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight
);
1258 EXPECT_EQ(1, tabstrip
.count());
1259 EXPECT_EQ(opener
, tabstrip
.GetActiveWebContents());
1261 WebContents
* dummy
= CreateWebContents();
1262 tabstrip
.AppendWebContents(dummy
, false);
1264 contents1
= CreateWebContents();
1265 contents2
= CreateWebContents();
1266 contents3
= CreateWebContents();
1267 InsertWebContentses(&tabstrip
, contents1
, contents2
, contents3
);
1268 EXPECT_EQ(5, tabstrip
.count());
1270 int dummy_index
= tabstrip
.count() - 1;
1271 tabstrip
.ActivateTabAt(dummy_index
, true);
1272 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1274 tabstrip
.ExecuteContextMenuCommand(dummy_index
,
1275 TabStripModel::CommandCloseOtherTabs
);
1276 EXPECT_EQ(1, tabstrip
.count());
1277 EXPECT_EQ(dummy
, tabstrip
.GetActiveWebContents());
1279 tabstrip
.CloseAllTabs();
1280 EXPECT_TRUE(tabstrip
.empty());
1283 // Tests GetIndicesClosedByCommand.
1284 TEST_F(TabStripModelTest
, GetIndicesClosedByCommand
) {
1285 TabStripDummyDelegate delegate
;
1286 TabStripModel
tabstrip(&delegate
, profile());
1287 EXPECT_TRUE(tabstrip
.empty());
1289 WebContents
* contents1
= CreateWebContents();
1290 WebContents
* contents2
= CreateWebContents();
1291 WebContents
* contents3
= CreateWebContents();
1292 WebContents
* contents4
= CreateWebContents();
1293 WebContents
* contents5
= CreateWebContents();
1295 tabstrip
.AppendWebContents(contents1
, true);
1296 tabstrip
.AppendWebContents(contents2
, true);
1297 tabstrip
.AppendWebContents(contents3
, true);
1298 tabstrip
.AppendWebContents(contents4
, true);
1299 tabstrip
.AppendWebContents(contents5
, true);
1301 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1302 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1303 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1304 tabstrip
, 1, TabStripModel::CommandCloseTabsToRight
));
1306 EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
1307 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1308 EXPECT_EQ("4 3 2 0", GetIndicesClosedByCommandAsString(
1309 tabstrip
, 1, TabStripModel::CommandCloseOtherTabs
));
1311 // Pin the first two tabs. Pinned tabs shouldn't be closed by the close other
1313 tabstrip
.SetTabPinned(0, true);
1314 tabstrip
.SetTabPinned(1, true);
1316 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1317 tabstrip
, 0, TabStripModel::CommandCloseTabsToRight
));
1318 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1319 tabstrip
, 2, TabStripModel::CommandCloseTabsToRight
));
1321 EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
1322 tabstrip
, 0, TabStripModel::CommandCloseOtherTabs
));
1323 EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
1324 tabstrip
, 2, TabStripModel::CommandCloseOtherTabs
));
1326 tabstrip
.CloseAllTabs();
1327 EXPECT_TRUE(tabstrip
.empty());
1330 // Tests whether or not WebContentses are inserted in the correct position
1331 // using this "smart" function with a simulated middle click action on a series
1332 // of links on the home page.
1333 TEST_F(TabStripModelTest
, AddWebContents_MiddleClickLinksAndClose
) {
1334 TabStripDummyDelegate delegate
;
1335 TabStripModel
tabstrip(&delegate
, profile());
1336 EXPECT_TRUE(tabstrip
.empty());
1338 // Open the Home Page.
1339 WebContents
* homepage_contents
= CreateWebContents();
1340 tabstrip
.AddWebContents(
1341 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1342 TabStripModel::ADD_ACTIVE
);
1344 // Open some other tab, by user typing.
1345 WebContents
* typed_page_contents
= CreateWebContents();
1346 tabstrip
.AddWebContents(
1347 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1348 TabStripModel::ADD_ACTIVE
);
1350 EXPECT_EQ(2, tabstrip
.count());
1352 // Re-select the home page.
1353 tabstrip
.ActivateTabAt(0, true);
1355 // Open a bunch of tabs by simulating middle clicking on links on the home
1357 WebContents
* middle_click_contents1
= CreateWebContents();
1358 tabstrip
.AddWebContents(
1359 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1360 TabStripModel::ADD_NONE
);
1361 WebContents
* middle_click_contents2
= CreateWebContents();
1362 tabstrip
.AddWebContents(
1363 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1364 TabStripModel::ADD_NONE
);
1365 WebContents
* middle_click_contents3
= CreateWebContents();
1366 tabstrip
.AddWebContents(
1367 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1368 TabStripModel::ADD_NONE
);
1370 EXPECT_EQ(5, tabstrip
.count());
1372 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1373 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetWebContentsAt(1));
1374 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetWebContentsAt(2));
1375 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetWebContentsAt(3));
1376 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1378 // Now simulate selecting a tab in the middle of the group of tabs opened from
1379 // the home page and start closing them. Each WebContents in the group
1380 // should be closed, right to left. This test is constructed to start at the
1381 // middle WebContents in the group to make sure the cursor wraps around
1382 // to the first WebContents in the group before closing the opener or
1383 // any other WebContents.
1384 tabstrip
.ActivateTabAt(2, true);
1385 tabstrip
.CloseSelectedTabs();
1386 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1387 tabstrip
.CloseSelectedTabs();
1388 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1389 tabstrip
.CloseSelectedTabs();
1390 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1391 tabstrip
.CloseSelectedTabs();
1392 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1394 EXPECT_EQ(1, tabstrip
.count());
1396 tabstrip
.CloseAllTabs();
1397 EXPECT_TRUE(tabstrip
.empty());
1400 // Tests whether or not a WebContents created by a left click on a link
1401 // that opens a new tab is inserted correctly adjacent to the tab that spawned
1403 TEST_F(TabStripModelTest
, AddWebContents_LeftClickPopup
) {
1404 TabStripDummyDelegate delegate
;
1405 TabStripModel
tabstrip(&delegate
, profile());
1406 EXPECT_TRUE(tabstrip
.empty());
1408 // Open the Home Page.
1409 WebContents
* homepage_contents
= CreateWebContents();
1410 tabstrip
.AddWebContents(
1411 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1412 TabStripModel::ADD_ACTIVE
);
1414 // Open some other tab, by user typing.
1415 WebContents
* typed_page_contents
= CreateWebContents();
1416 tabstrip
.AddWebContents(
1417 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1418 TabStripModel::ADD_ACTIVE
);
1420 EXPECT_EQ(2, tabstrip
.count());
1422 // Re-select the home page.
1423 tabstrip
.ActivateTabAt(0, true);
1425 // Open a tab by simulating a left click on a link that opens in a new tab.
1426 WebContents
* left_click_contents
= CreateWebContents();
1427 tabstrip
.AddWebContents(left_click_contents
, -1,
1428 ui::PAGE_TRANSITION_LINK
,
1429 TabStripModel::ADD_ACTIVE
);
1431 // Verify the state meets our expectations.
1432 EXPECT_EQ(3, tabstrip
.count());
1433 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1434 EXPECT_EQ(left_click_contents
, tabstrip
.GetWebContentsAt(1));
1435 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(2));
1437 // The newly created tab should be selected.
1438 EXPECT_EQ(left_click_contents
, tabstrip
.GetActiveWebContents());
1440 // After closing the selected tab, the selection should move to the left, to
1442 tabstrip
.CloseSelectedTabs();
1443 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1445 EXPECT_EQ(2, tabstrip
.count());
1447 tabstrip
.CloseAllTabs();
1448 EXPECT_TRUE(tabstrip
.empty());
1451 // Tests whether or not new tabs that should split context (typed pages,
1452 // generated urls, also blank tabs) open at the end of the tabstrip instead of
1454 TEST_F(TabStripModelTest
, AddWebContents_CreateNewBlankTab
) {
1455 TabStripDummyDelegate delegate
;
1456 TabStripModel
tabstrip(&delegate
, profile());
1457 EXPECT_TRUE(tabstrip
.empty());
1459 // Open the Home Page.
1460 WebContents
* homepage_contents
= CreateWebContents();
1461 tabstrip
.AddWebContents(
1462 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1463 TabStripModel::ADD_ACTIVE
);
1465 // Open some other tab, by user typing.
1466 WebContents
* typed_page_contents
= CreateWebContents();
1467 tabstrip
.AddWebContents(
1468 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1469 TabStripModel::ADD_ACTIVE
);
1471 EXPECT_EQ(2, tabstrip
.count());
1473 // Re-select the home page.
1474 tabstrip
.ActivateTabAt(0, true);
1476 // Open a new blank tab in the foreground.
1477 WebContents
* new_blank_contents
= CreateWebContents();
1478 tabstrip
.AddWebContents(new_blank_contents
, -1,
1479 ui::PAGE_TRANSITION_TYPED
,
1480 TabStripModel::ADD_ACTIVE
);
1482 // Verify the state of the tabstrip.
1483 EXPECT_EQ(3, tabstrip
.count());
1484 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1485 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1486 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1488 // Now open a couple more blank tabs in the background.
1489 WebContents
* background_blank_contents1
= CreateWebContents();
1490 tabstrip
.AddWebContents(
1491 background_blank_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1492 TabStripModel::ADD_NONE
);
1493 WebContents
* background_blank_contents2
= CreateWebContents();
1494 tabstrip
.AddWebContents(
1495 background_blank_contents2
, -1, ui::PAGE_TRANSITION_GENERATED
,
1496 TabStripModel::ADD_NONE
);
1497 EXPECT_EQ(5, tabstrip
.count());
1498 EXPECT_EQ(homepage_contents
, tabstrip
.GetWebContentsAt(0));
1499 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(1));
1500 EXPECT_EQ(new_blank_contents
, tabstrip
.GetWebContentsAt(2));
1501 EXPECT_EQ(background_blank_contents1
, tabstrip
.GetWebContentsAt(3));
1502 EXPECT_EQ(background_blank_contents2
, tabstrip
.GetWebContentsAt(4));
1504 tabstrip
.CloseAllTabs();
1505 EXPECT_TRUE(tabstrip
.empty());
1508 // Tests whether opener state is correctly forgotten when the user switches
1510 TEST_F(TabStripModelTest
, AddWebContents_ForgetOpeners
) {
1511 TabStripDummyDelegate delegate
;
1512 TabStripModel
tabstrip(&delegate
, profile());
1513 EXPECT_TRUE(tabstrip
.empty());
1515 // Open the Home Page
1516 WebContents
* homepage_contents
= CreateWebContents();
1517 tabstrip
.AddWebContents(
1518 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1519 TabStripModel::ADD_ACTIVE
);
1521 // Open some other tab, by user typing.
1522 WebContents
* typed_page_contents
= CreateWebContents();
1523 tabstrip
.AddWebContents(
1524 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1525 TabStripModel::ADD_ACTIVE
);
1527 EXPECT_EQ(2, tabstrip
.count());
1529 // Re-select the home page.
1530 tabstrip
.ActivateTabAt(0, true);
1532 // Open a bunch of tabs by simulating middle clicking on links on the home
1534 WebContents
* middle_click_contents1
= CreateWebContents();
1535 tabstrip
.AddWebContents(
1536 middle_click_contents1
, -1, ui::PAGE_TRANSITION_LINK
,
1537 TabStripModel::ADD_NONE
);
1538 WebContents
* middle_click_contents2
= CreateWebContents();
1539 tabstrip
.AddWebContents(
1540 middle_click_contents2
, -1, ui::PAGE_TRANSITION_LINK
,
1541 TabStripModel::ADD_NONE
);
1542 WebContents
* middle_click_contents3
= CreateWebContents();
1543 tabstrip
.AddWebContents(
1544 middle_click_contents3
, -1, ui::PAGE_TRANSITION_LINK
,
1545 TabStripModel::ADD_NONE
);
1547 // Break out of the context by selecting a tab in a different context.
1548 EXPECT_EQ(typed_page_contents
, tabstrip
.GetWebContentsAt(4));
1549 tabstrip
.SelectLastTab();
1550 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1552 // Step back into the context by selecting a tab inside it.
1553 tabstrip
.ActivateTabAt(2, true);
1554 EXPECT_EQ(middle_click_contents2
, tabstrip
.GetActiveWebContents());
1556 // Now test that closing tabs selects to the right until there are no more,
1557 // then to the left, as if there were no context (context has been
1558 // successfully forgotten).
1559 tabstrip
.CloseSelectedTabs();
1560 EXPECT_EQ(middle_click_contents3
, tabstrip
.GetActiveWebContents());
1561 tabstrip
.CloseSelectedTabs();
1562 EXPECT_EQ(typed_page_contents
, tabstrip
.GetActiveWebContents());
1563 tabstrip
.CloseSelectedTabs();
1564 EXPECT_EQ(middle_click_contents1
, tabstrip
.GetActiveWebContents());
1565 tabstrip
.CloseSelectedTabs();
1566 EXPECT_EQ(homepage_contents
, tabstrip
.GetActiveWebContents());
1568 EXPECT_EQ(1, tabstrip
.count());
1570 tabstrip
.CloseAllTabs();
1571 EXPECT_TRUE(tabstrip
.empty());
1574 // Added for http://b/issue?id=958960
1575 TEST_F(TabStripModelTest
, AppendContentsReselectionTest
) {
1576 TabStripDummyDelegate delegate
;
1577 TabStripModel
tabstrip(&delegate
, profile());
1578 EXPECT_TRUE(tabstrip
.empty());
1580 // Open the Home Page.
1581 WebContents
* homepage_contents
= CreateWebContents();
1582 tabstrip
.AddWebContents(
1583 homepage_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1584 TabStripModel::ADD_ACTIVE
);
1586 // Open some other tab, by user typing.
1587 WebContents
* typed_page_contents
= CreateWebContents();
1588 tabstrip
.AddWebContents(
1589 typed_page_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1590 TabStripModel::ADD_NONE
);
1592 // The selected tab should still be the first.
1593 EXPECT_EQ(0, tabstrip
.active_index());
1595 // Now simulate a link click that opens a new tab (by virtue of target=_blank)
1596 // and make sure the correct tab gets selected when the new tab is closed.
1597 WebContents
* target_blank
= CreateWebContents();
1598 tabstrip
.AppendWebContents(target_blank
, true);
1599 EXPECT_EQ(2, tabstrip
.active_index());
1600 tabstrip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1601 EXPECT_EQ(0, tabstrip
.active_index());
1603 // Clean up after ourselves.
1604 tabstrip
.CloseAllTabs();
1607 // Added for http://b/issue?id=1027661
1608 TEST_F(TabStripModelTest
, ReselectionConsidersChildrenTest
) {
1609 TabStripDummyDelegate delegate
;
1610 TabStripModel
strip(&delegate
, profile());
1613 WebContents
* page_a_contents
= CreateWebContents();
1614 strip
.AddWebContents(
1615 page_a_contents
, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1616 TabStripModel::ADD_ACTIVE
);
1618 // Simulate middle click to open page A.A and A.B
1619 WebContents
* page_a_a_contents
= CreateWebContents();
1620 strip
.AddWebContents(page_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1621 TabStripModel::ADD_NONE
);
1622 WebContents
* page_a_b_contents
= CreateWebContents();
1623 strip
.AddWebContents(page_a_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1624 TabStripModel::ADD_NONE
);
1627 strip
.ActivateTabAt(1, true);
1628 EXPECT_EQ(page_a_a_contents
, strip
.GetActiveWebContents());
1630 // Simulate a middle click to open page A.A.A
1631 WebContents
* page_a_a_a_contents
= CreateWebContents();
1632 strip
.AddWebContents(page_a_a_a_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1633 TabStripModel::ADD_NONE
);
1635 EXPECT_EQ(page_a_a_a_contents
, strip
.GetWebContentsAt(2));
1638 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1640 // Page A.A.A should be selected, NOT A.B
1641 EXPECT_EQ(page_a_a_a_contents
, strip
.GetActiveWebContents());
1644 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1646 // Page A.B should be selected
1647 EXPECT_EQ(page_a_b_contents
, strip
.GetActiveWebContents());
1650 strip
.CloseWebContentsAt(strip
.active_index(), TabStripModel::CLOSE_NONE
);
1652 // Page A should be selected
1653 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
1656 strip
.CloseAllTabs();
1659 TEST_F(TabStripModelTest
, AddWebContents_NewTabAtEndOfStripInheritsGroup
) {
1660 TabStripDummyDelegate delegate
;
1661 TabStripModel
strip(&delegate
, profile());
1664 WebContents
* page_a_contents
= CreateWebContents();
1665 strip
.AddWebContents(page_a_contents
, -1,
1666 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1667 TabStripModel::ADD_ACTIVE
);
1669 // Open pages B, C and D in the background from links on page A...
1670 WebContents
* page_b_contents
= CreateWebContents();
1671 WebContents
* page_c_contents
= CreateWebContents();
1672 WebContents
* page_d_contents
= CreateWebContents();
1673 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1674 TabStripModel::ADD_NONE
);
1675 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1676 TabStripModel::ADD_NONE
);
1677 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1678 TabStripModel::ADD_NONE
);
1680 // Switch to page B's tab.
1681 strip
.ActivateTabAt(1, true);
1683 // Open a New Tab at the end of the strip (simulate Ctrl+T)
1684 WebContents
* new_contents
= CreateWebContents();
1685 strip
.AddWebContents(new_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1686 TabStripModel::ADD_ACTIVE
);
1688 EXPECT_EQ(4, strip
.GetIndexOfWebContents(new_contents
));
1689 EXPECT_EQ(4, strip
.active_index());
1691 // Close the New Tab that was just opened. We should be returned to page B's
1693 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1695 EXPECT_EQ(1, strip
.active_index());
1697 // Open a non-New Tab tab at the end of the strip, with a TYPED transition.
1698 // This is like typing a URL in the address bar and pressing Alt+Enter. The
1699 // behavior should be the same as above.
1700 WebContents
* page_e_contents
= CreateWebContents();
1701 strip
.AddWebContents(page_e_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
1702 TabStripModel::ADD_ACTIVE
);
1704 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_e_contents
));
1705 EXPECT_EQ(4, strip
.active_index());
1707 // Close the Tab. Selection should shift back to page B's Tab.
1708 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1710 EXPECT_EQ(1, strip
.active_index());
1712 // Open a non-New Tab tab at the end of the strip, with some other
1713 // transition. This is like right clicking on a bookmark and choosing "Open
1714 // in New Tab". No opener relationship should be preserved between this Tab
1715 // and the one that was active when the gesture was performed.
1716 WebContents
* page_f_contents
= CreateWebContents();
1717 strip
.AddWebContents(page_f_contents
, -1,
1718 ui::PAGE_TRANSITION_AUTO_BOOKMARK
,
1719 TabStripModel::ADD_ACTIVE
);
1721 EXPECT_EQ(4, strip
.GetIndexOfWebContents(page_f_contents
));
1722 EXPECT_EQ(4, strip
.active_index());
1724 // Close the Tab. The next-adjacent should be selected.
1725 strip
.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE
);
1727 EXPECT_EQ(3, strip
.active_index());
1730 strip
.CloseAllTabs();
1733 // A test of navigations in a tab that is part of a group of opened from some
1734 // parent tab. If the navigations are link clicks, the group relationship of
1735 // the tab to its parent are preserved. If they are of any other type, they are
1737 TEST_F(TabStripModelTest
, NavigationForgetsOpeners
) {
1738 TabStripDummyDelegate delegate
;
1739 TabStripModel
strip(&delegate
, profile());
1742 WebContents
* page_a_contents
= CreateWebContents();
1743 strip
.AddWebContents(page_a_contents
, -1,
1744 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1745 TabStripModel::ADD_ACTIVE
);
1747 // Open pages B, C and D in the background from links on page A...
1748 WebContents
* page_b_contents
= CreateWebContents();
1749 WebContents
* page_c_contents
= CreateWebContents();
1750 WebContents
* page_d_contents
= CreateWebContents();
1751 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1752 TabStripModel::ADD_NONE
);
1753 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1754 TabStripModel::ADD_NONE
);
1755 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1756 TabStripModel::ADD_NONE
);
1758 // Open page E in a different opener group from page A.
1759 WebContents
* page_e_contents
= CreateWebContents();
1760 strip
.AddWebContents(page_e_contents
, -1,
1761 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1762 TabStripModel::ADD_NONE
);
1764 // Tell the TabStripModel that we are navigating page D via a link click.
1765 strip
.ActivateTabAt(3, true);
1766 strip
.TabNavigating(page_d_contents
, ui::PAGE_TRANSITION_LINK
);
1768 // Close page D, page C should be selected. (part of same group).
1769 strip
.CloseWebContentsAt(3, TabStripModel::CLOSE_NONE
);
1770 EXPECT_EQ(2, strip
.active_index());
1772 // Tell the TabStripModel that we are navigating in page C via a bookmark.
1773 strip
.TabNavigating(page_c_contents
, ui::PAGE_TRANSITION_AUTO_BOOKMARK
);
1775 // Close page C, page E should be selected. (C is no longer part of the
1776 // A-B-C-D group, selection moves to the right).
1777 strip
.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE
);
1778 EXPECT_EQ(page_e_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1780 strip
.CloseAllTabs();
1783 // A test that the forgetting behavior tested in NavigationForgetsOpeners above
1784 // doesn't cause the opener relationship for a New Tab opened at the end of the
1785 // TabStrip to be reset (Test 1 below), unless another any other tab is
1786 // selected (Test 2 below).
1787 TEST_F(TabStripModelTest
, NavigationForgettingDoesntAffectNewTab
) {
1788 TabStripDummyDelegate delegate
;
1789 TabStripModel
strip(&delegate
, profile());
1791 // Open a tab and several tabs from it, then select one of the tabs that was
1793 WebContents
* page_a_contents
= CreateWebContents();
1794 strip
.AddWebContents(page_a_contents
, -1,
1795 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
1796 TabStripModel::ADD_ACTIVE
);
1798 WebContents
* page_b_contents
= CreateWebContents();
1799 WebContents
* page_c_contents
= CreateWebContents();
1800 WebContents
* page_d_contents
= CreateWebContents();
1801 strip
.AddWebContents(page_b_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1802 TabStripModel::ADD_NONE
);
1803 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1804 TabStripModel::ADD_NONE
);
1805 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
1806 TabStripModel::ADD_NONE
);
1808 strip
.ActivateTabAt(2, true);
1810 // TEST 1: If the user is in a group of tabs and opens a new tab at the end
1811 // of the strip, closing that new tab will select the tab that they were
1814 // Now simulate opening a new tab at the end of the TabStrip.
1815 WebContents
* new_contents1
= CreateWebContents();
1816 strip
.AddWebContents(new_contents1
, -1, ui::PAGE_TRANSITION_TYPED
,
1817 TabStripModel::ADD_ACTIVE
);
1819 // At this point, if we close this tab the last selected one should be
1821 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1822 EXPECT_EQ(page_c_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1824 // TEST 2: If the user is in a group of tabs and opens a new tab at the end
1825 // of the strip, selecting any other tab in the strip will cause that new
1826 // tab's opener relationship to be forgotten.
1828 // Open a new tab again.
1829 WebContents
* new_contents2
= CreateWebContents();
1830 strip
.AddWebContents(new_contents2
, -1, ui::PAGE_TRANSITION_TYPED
,
1831 TabStripModel::ADD_ACTIVE
);
1833 // Now select the first tab.
1834 strip
.ActivateTabAt(0, true);
1836 // Now select the last tab.
1837 strip
.ActivateTabAt(strip
.count() - 1, true);
1839 // Now close the last tab. The next adjacent should be selected.
1840 strip
.CloseWebContentsAt(strip
.count() - 1, TabStripModel::CLOSE_NONE
);
1841 EXPECT_EQ(page_d_contents
, strip
.GetWebContentsAt(strip
.active_index()));
1843 strip
.CloseAllTabs();
1846 // This fails on Linux when run with the rest of unit_tests (crbug.com/302156)
1847 // and fails consistently on Mac and Windows.
1848 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
1849 #define MAYBE_FastShutdown \
1850 DISABLED_FastShutdown
1852 #define MAYBE_FastShutdown \
1855 // Tests that fast shutdown is attempted appropriately.
1856 TEST_F(TabStripModelTest
, MAYBE_FastShutdown
) {
1857 TabStripDummyDelegate delegate
;
1858 TabStripModel
tabstrip(&delegate
, profile());
1859 MockTabStripModelObserver
observer(&tabstrip
);
1860 tabstrip
.AddObserver(&observer
);
1862 EXPECT_TRUE(tabstrip
.empty());
1864 // Make sure fast shutdown is attempted when tabs that share a RPH are shut
1867 WebContents
* contents1
= CreateWebContents();
1868 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1870 SetID(contents1
, 1);
1871 SetID(contents2
, 2);
1873 tabstrip
.AppendWebContents(contents1
, true);
1874 tabstrip
.AppendWebContents(contents2
, true);
1876 // Turn on the fake unload listener so the tabs don't actually get shut
1877 // down when we call CloseAllTabs()---we need to be able to check that
1878 // fast shutdown was attempted.
1879 delegate
.set_run_unload_listener(true);
1880 tabstrip
.CloseAllTabs();
1881 // On a mock RPH this checks whether we *attempted* fast shutdown.
1882 // A real RPH would reject our attempt since there is an unload handler.
1883 EXPECT_TRUE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1884 EXPECT_EQ(2, tabstrip
.count());
1886 delegate
.set_run_unload_listener(false);
1887 tabstrip
.CloseAllTabs();
1888 EXPECT_TRUE(tabstrip
.empty());
1891 // Make sure fast shutdown is not attempted when only some tabs that share a
1892 // RPH are shut down.
1894 WebContents
* contents1
= CreateWebContents();
1895 WebContents
* contents2
= CreateWebContentsWithSharedRPH(contents1
);
1897 SetID(contents1
, 1);
1898 SetID(contents2
, 2);
1900 tabstrip
.AppendWebContents(contents1
, true);
1901 tabstrip
.AppendWebContents(contents2
, true);
1903 tabstrip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
1904 EXPECT_FALSE(contents1
->GetRenderProcessHost()->FastShutdownStarted());
1905 EXPECT_EQ(1, tabstrip
.count());
1907 tabstrip
.CloseAllTabs();
1908 EXPECT_TRUE(tabstrip
.empty());
1912 // Tests various permutations of pinning tabs.
1913 TEST_F(TabStripModelTest
, Pinning
) {
1914 TabStripDummyDelegate delegate
;
1915 TabStripModel
tabstrip(&delegate
, profile());
1916 MockTabStripModelObserver
observer(&tabstrip
);
1917 tabstrip
.AddObserver(&observer
);
1919 EXPECT_TRUE(tabstrip
.empty());
1921 typedef MockTabStripModelObserver::State State
;
1923 WebContents
* contents1
= CreateWebContentsWithID(1);
1924 WebContents
* contents2
= CreateWebContentsWithID(2);
1925 WebContents
* contents3
= CreateWebContentsWithID(3);
1927 // Note! The ordering of these tests is important, each subsequent test
1928 // builds on the state established in the previous. This is important if you
1929 // ever insert tests rather than append.
1931 // Initial state, three tabs, first selected.
1932 tabstrip
.AppendWebContents(contents1
, true);
1933 tabstrip
.AppendWebContents(contents2
, false);
1934 tabstrip
.AppendWebContents(contents3
, false);
1936 observer
.ClearStates();
1938 // Pin the first tab, this shouldn't visually reorder anything.
1940 tabstrip
.SetTabPinned(0, true);
1942 // As the order didn't change, we should get a pinned notification.
1943 ASSERT_EQ(1, observer
.GetStateCount());
1944 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
1945 EXPECT_TRUE(observer
.StateEquals(0, state
));
1947 // And verify the state.
1948 EXPECT_EQ("1p 2 3", GetTabStripStateString(tabstrip
));
1950 observer
.ClearStates();
1953 // Unpin the first tab.
1955 tabstrip
.SetTabPinned(0, false);
1957 // As the order didn't change, we should get a pinned notification.
1958 ASSERT_EQ(1, observer
.GetStateCount());
1959 State
state(contents1
, 0, MockTabStripModelObserver::PINNED
);
1960 EXPECT_TRUE(observer
.StateEquals(0, state
));
1962 // And verify the state.
1963 EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip
));
1965 observer
.ClearStates();
1968 // Pin the 3rd tab, which should move it to the front.
1970 tabstrip
.SetTabPinned(2, true);
1972 // The pinning should have resulted in a move and a pinned notification.
1973 ASSERT_EQ(2, observer
.GetStateCount());
1974 State
state(contents3
, 0, MockTabStripModelObserver::MOVE
);
1975 state
.src_index
= 2;
1976 EXPECT_TRUE(observer
.StateEquals(0, state
));
1978 state
= State(contents3
, 0, MockTabStripModelObserver::PINNED
);
1979 EXPECT_TRUE(observer
.StateEquals(1, state
));
1981 // And verify the state.
1982 EXPECT_EQ("3p 1 2", GetTabStripStateString(tabstrip
));
1984 observer
.ClearStates();
1987 // Pin the tab "1", which shouldn't move anything.
1989 tabstrip
.SetTabPinned(1, true);
1991 // As the order didn't change, we should get a pinned notification.
1992 ASSERT_EQ(1, observer
.GetStateCount());
1993 State
state(contents1
, 1, MockTabStripModelObserver::PINNED
);
1994 EXPECT_TRUE(observer
.StateEquals(0, state
));
1996 // And verify the state.
1997 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
1999 observer
.ClearStates();
2002 // Try to move tab "2" to the front, it should be ignored.
2004 tabstrip
.MoveWebContentsAt(2, 0, false);
2006 // As the order didn't change, we should get a pinned notification.
2007 ASSERT_EQ(0, observer
.GetStateCount());
2009 // And verify the state.
2010 EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip
));
2012 observer
.ClearStates();
2015 // Unpin tab "3", which implicitly moves it to the end.
2017 tabstrip
.SetTabPinned(0, false);
2019 ASSERT_EQ(2, observer
.GetStateCount());
2020 State
state(contents3
, 1, MockTabStripModelObserver::MOVE
);
2021 state
.src_index
= 0;
2022 EXPECT_TRUE(observer
.StateEquals(0, state
));
2024 state
= State(contents3
, 1, MockTabStripModelObserver::PINNED
);
2025 EXPECT_TRUE(observer
.StateEquals(1, state
));
2027 // And verify the state.
2028 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2030 observer
.ClearStates();
2033 // Unpin tab "3", nothing should happen.
2035 tabstrip
.SetTabPinned(1, false);
2037 ASSERT_EQ(0, observer
.GetStateCount());
2039 EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip
));
2041 observer
.ClearStates();
2046 tabstrip
.SetTabPinned(0, true);
2047 tabstrip
.SetTabPinned(1, true);
2049 EXPECT_EQ("1p 3p 2", GetTabStripStateString(tabstrip
));
2051 observer
.ClearStates();
2054 WebContents
* contents4
= CreateWebContentsWithID(4);
2056 // Insert "4" between "1" and "3". As "1" and "4" are pinned, "4" should end
2059 tabstrip
.InsertWebContentsAt(1, contents4
, TabStripModel::ADD_NONE
);
2061 ASSERT_EQ(1, observer
.GetStateCount());
2062 State
state(contents4
, 2, MockTabStripModelObserver::INSERT
);
2063 EXPECT_TRUE(observer
.StateEquals(0, state
));
2065 EXPECT_EQ("1p 3p 4 2", GetTabStripStateString(tabstrip
));
2068 tabstrip
.CloseAllTabs();
2071 // Makes sure the TabStripModel calls the right observer methods during a
2073 TEST_F(TabStripModelTest
, ReplaceSendsSelected
) {
2074 typedef MockTabStripModelObserver::State State
;
2076 TabStripDummyDelegate delegate
;
2077 TabStripModel
strip(&delegate
, profile());
2079 WebContents
* first_contents
= CreateWebContents();
2080 strip
.AddWebContents(first_contents
, -1, ui::PAGE_TRANSITION_TYPED
,
2081 TabStripModel::ADD_ACTIVE
);
2083 MockTabStripModelObserver
tabstrip_observer(&strip
);
2084 strip
.AddObserver(&tabstrip_observer
);
2086 WebContents
* new_contents
= CreateWebContents();
2087 delete strip
.ReplaceWebContentsAt(0, new_contents
);
2089 ASSERT_EQ(2, tabstrip_observer
.GetStateCount());
2091 // First event should be for replaced.
2092 State
state(new_contents
, 0, MockTabStripModelObserver::REPLACED
);
2093 state
.src_contents
= first_contents
;
2094 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2096 // And the second for selected.
2097 state
= State(new_contents
, 0, MockTabStripModelObserver::ACTIVATE
);
2098 state
.src_contents
= first_contents
;
2099 state
.change_reason
= TabStripModelObserver::CHANGE_REASON_REPLACED
;
2100 EXPECT_TRUE(tabstrip_observer
.StateEquals(1, state
));
2102 // Now add another tab and replace it, making sure we don't get a selected
2104 WebContents
* third_contents
= CreateWebContents();
2105 strip
.AddWebContents(third_contents
, 1, ui::PAGE_TRANSITION_TYPED
,
2106 TabStripModel::ADD_NONE
);
2108 tabstrip_observer
.ClearStates();
2111 new_contents
= CreateWebContents();
2112 delete strip
.ReplaceWebContentsAt(1, new_contents
);
2114 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2116 state
= State(new_contents
, 1, MockTabStripModelObserver::REPLACED
);
2117 state
.src_contents
= third_contents
;
2118 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state
));
2120 strip
.CloseAllTabs();
2123 // Ensures discarding tabs leaves TabStripModel in a good state.
2124 TEST_F(TabStripModelTest
, DiscardWebContentsAt
) {
2125 typedef MockTabStripModelObserver::State State
;
2127 TabStripDummyDelegate delegate
;
2128 TabStripModel
tabstrip(&delegate
, profile());
2130 // Fill it with some tabs.
2131 WebContents
* contents1
= CreateWebContents();
2132 tabstrip
.AppendWebContents(contents1
, true);
2133 WebContents
* contents2
= CreateWebContents();
2134 tabstrip
.AppendWebContents(contents2
, true);
2136 // Start watching for events after the appends to avoid observing state
2137 // transitions that aren't relevant to this test.
2138 MockTabStripModelObserver
tabstrip_observer(&tabstrip
);
2139 tabstrip
.AddObserver(&tabstrip_observer
);
2141 // Discard one of the tabs.
2142 WebContents
* null_contents1
= tabstrip
.DiscardWebContentsAt(0);
2143 ASSERT_EQ(2, tabstrip
.count());
2144 EXPECT_TRUE(tabstrip
.IsTabDiscarded(0));
2145 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2146 ASSERT_EQ(null_contents1
, tabstrip
.GetWebContentsAt(0));
2147 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2148 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2149 State
state1(null_contents1
, 0, MockTabStripModelObserver::REPLACED
);
2150 state1
.src_contents
= contents1
;
2151 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state1
));
2152 tabstrip_observer
.ClearStates();
2154 // Discard the same tab again.
2155 WebContents
* null_contents2
= tabstrip
.DiscardWebContentsAt(0);
2156 ASSERT_EQ(2, tabstrip
.count());
2157 EXPECT_TRUE(tabstrip
.IsTabDiscarded(0));
2158 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2159 ASSERT_EQ(null_contents2
, tabstrip
.GetWebContentsAt(0));
2160 ASSERT_EQ(contents2
, tabstrip
.GetWebContentsAt(1));
2161 ASSERT_EQ(1, tabstrip_observer
.GetStateCount());
2162 State
state2(null_contents2
, 0, MockTabStripModelObserver::REPLACED
);
2163 state2
.src_contents
= null_contents1
;
2164 EXPECT_TRUE(tabstrip_observer
.StateEquals(0, state2
));
2165 tabstrip_observer
.ClearStates();
2167 // Activating the tab should clear its discard state.
2168 tabstrip
.ActivateTabAt(0, true /* user_gesture */);
2169 ASSERT_EQ(2, tabstrip
.count());
2170 EXPECT_FALSE(tabstrip
.IsTabDiscarded(0));
2171 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2173 // Don't discard active tab.
2174 tabstrip
.DiscardWebContentsAt(0);
2175 ASSERT_EQ(2, tabstrip
.count());
2176 EXPECT_FALSE(tabstrip
.IsTabDiscarded(0));
2177 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2179 tabstrip
.CloseAllTabs();
2182 // Makes sure that reloading a discarded tab without activating it unmarks the
2183 // tab as discarded so it won't reload on activation.
2184 TEST_F(TabStripModelTest
, ReloadDiscardedTabContextMenu
) {
2185 TabStripDummyDelegate delegate
;
2186 TabStripModel
tabstrip(&delegate
, profile());
2188 // Create 2 tabs because the active tab cannot be discarded.
2189 tabstrip
.AppendWebContents(CreateWebContents(), true);
2190 content::WebContents
* test_contents
=
2191 WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
2192 tabstrip
.AppendWebContents(test_contents
, false); // Opened in background.
2194 // Navigate to a web page. This is necessary to set a current entry in memory
2195 // so the reload can happen.
2196 WebContentsTester::For(test_contents
)
2197 ->NavigateAndCommit(GURL("chrome://newtab"));
2198 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2200 tabstrip
.DiscardWebContentsAt(1);
2201 EXPECT_TRUE(tabstrip
.IsTabDiscarded(1));
2203 tabstrip
.GetWebContentsAt(1)->GetController().Reload(false);
2204 EXPECT_FALSE(tabstrip
.IsTabDiscarded(1));
2206 tabstrip
.CloseAllTabs();
2209 // Makes sure that the last active time property is saved even though the tab is
2211 TEST_F(TabStripModelTest
, DiscardedTabKeepsLastActiveTime
) {
2212 TabStripDummyDelegate delegate
;
2213 TabStripModel
tabstrip(&delegate
, profile());
2215 tabstrip
.AppendWebContents(CreateWebContents(), true);
2216 WebContents
* test_contents
= CreateWebContents();
2217 tabstrip
.AppendWebContents(test_contents
, false);
2219 // Simulate an old inactive tab about to get discarded.
2220 base::TimeTicks new_last_active_time
=
2221 base::TimeTicks::Now() - base::TimeDelta::FromMinutes(35);
2222 test_contents
->SetLastActiveTime(new_last_active_time
);
2223 EXPECT_EQ(new_last_active_time
, test_contents
->GetLastActiveTime());
2225 WebContents
* null_contents
= tabstrip
.DiscardWebContentsAt(1);
2226 EXPECT_EQ(new_last_active_time
, null_contents
->GetLastActiveTime());
2228 tabstrip
.CloseAllTabs();
2231 // Makes sure TabStripModel handles the case of deleting a tab while removing
2233 TEST_F(TabStripModelTest
, DeleteFromDestroy
) {
2234 TabStripDummyDelegate delegate
;
2235 TabStripModel
strip(&delegate
, profile());
2236 WebContents
* contents1
= CreateWebContents();
2237 WebContents
* contents2
= CreateWebContents();
2238 MockTabStripModelObserver
tab_strip_model_observer(&strip
);
2239 strip
.AppendWebContents(contents1
, true);
2240 strip
.AppendWebContents(contents2
, true);
2241 // DeleteWebContentsOnDestroyedObserver deletes contents1 when contents2 sends
2242 // out notification that it is being destroyed.
2243 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, NULL
);
2244 strip
.AddObserver(&tab_strip_model_observer
);
2245 strip
.CloseAllTabs();
2247 int close_all_count
= 0, close_all_canceled_count
= 0;
2248 tab_strip_model_observer
.GetCloseCounts(&close_all_count
,
2249 &close_all_canceled_count
);
2250 EXPECT_EQ(1, close_all_count
);
2251 EXPECT_EQ(0, close_all_canceled_count
);
2253 strip
.RemoveObserver(&tab_strip_model_observer
);
2256 // Makes sure TabStripModel handles the case of deleting another tab and the
2257 // TabStrip while removing another tab.
2258 TEST_F(TabStripModelTest
, DeleteTabStripFromDestroy
) {
2259 TabStripDummyDelegate delegate
;
2260 TabStripModel
* strip
= new TabStripModel(&delegate
, profile());
2261 MockTabStripModelObserver
tab_strip_model_observer(strip
);
2262 strip
->AddObserver(&tab_strip_model_observer
);
2263 WebContents
* contents1
= CreateWebContents();
2264 WebContents
* contents2
= CreateWebContents();
2265 strip
->AppendWebContents(contents1
, true);
2266 strip
->AppendWebContents(contents2
, true);
2267 // DeleteWebContentsOnDestroyedObserver deletes |contents1| and |strip| when
2268 // |contents2| sends out notification that it is being destroyed.
2269 DeleteWebContentsOnDestroyedObserver
observer(contents2
, contents1
, strip
);
2270 strip
->CloseAllTabs();
2271 EXPECT_TRUE(tab_strip_model_observer
.empty());
2272 EXPECT_TRUE(tab_strip_model_observer
.deleted());
2275 TEST_F(TabStripModelTest
, MoveSelectedTabsTo
) {
2277 // Number of tabs the tab strip should have.
2278 const int tab_count
;
2280 // Number of pinned tabs.
2281 const int pinned_count
;
2283 // Index of the tabs to select.
2284 const std::string selected_tabs
;
2286 // Index to move the tabs to.
2287 const int target_index
;
2289 // Expected state after the move (space separated list of indices).
2290 const std::string state_after_move
;
2293 { 2, 0, "0", 1, "1 0" },
2294 { 3, 0, "0", 2, "1 2 0" },
2295 { 3, 0, "2", 0, "2 0 1" },
2296 { 3, 0, "2", 1, "0 2 1" },
2297 { 3, 0, "0 1", 0, "0 1 2" },
2300 { 6, 0, "4 5", 1, "0 4 5 1 2 3" },
2301 { 3, 0, "0 1", 1, "2 0 1" },
2302 { 4, 0, "0 2", 1, "1 0 2 3" },
2303 { 6, 0, "0 1", 3, "2 3 4 0 1 5" },
2306 { 6, 0, "0 2 3", 3, "1 4 5 0 2 3" },
2307 { 7, 0, "4 5 6", 1, "0 4 5 6 1 2 3" },
2308 { 7, 0, "1 5 6", 4, "0 2 3 4 1 5 6" },
2311 { 8, 0, "0 2 3 6 7", 3, "1 4 5 0 2 3 6 7" },
2314 { 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" },
2316 // With pinned tabs.
2317 { 6, 2, "2 3", 2, "0p 1p 2 3 4 5" },
2318 { 6, 2, "0 4", 3, "1p 0p 2 3 4 5" },
2319 { 6, 3, "1 2 4", 0, "1p 2p 0p 4 3 5" },
2320 { 8, 3, "1 3 4", 4, "0p 2p 1p 5 6 3 4 7" },
2322 { 7, 4, "2 3 4", 3, "0p 1p 2p 3p 5 4 6" },
2325 for (size_t i
= 0; i
< arraysize(test_data
); ++i
) {
2326 TabStripDummyDelegate delegate
;
2327 TabStripModel
strip(&delegate
, profile());
2328 ASSERT_NO_FATAL_FAILURE(
2329 PrepareTabstripForSelectionTest(&strip
, test_data
[i
].tab_count
,
2330 test_data
[i
].pinned_count
,
2331 test_data
[i
].selected_tabs
));
2332 strip
.MoveSelectedTabsTo(test_data
[i
].target_index
);
2333 EXPECT_EQ(test_data
[i
].state_after_move
,
2334 GetTabStripStateString(strip
)) << i
;
2335 strip
.CloseAllTabs();
2339 // Tests that moving a tab forgets all groups referencing it.
2340 TEST_F(TabStripModelTest
, MoveSelectedTabsTo_ForgetGroups
) {
2341 TabStripDummyDelegate delegate
;
2342 TabStripModel
strip(&delegate
, profile());
2344 // Open page A as a new tab and then A1 in the background from A.
2345 WebContents
* page_a_contents
= CreateWebContents();
2346 strip
.AddWebContents(page_a_contents
, -1,
2347 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2348 TabStripModel::ADD_ACTIVE
);
2349 WebContents
* page_a1_contents
= CreateWebContents();
2350 strip
.AddWebContents(page_a1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2351 TabStripModel::ADD_NONE
);
2353 // Likewise, open pages B and B1.
2354 WebContents
* page_b_contents
= CreateWebContents();
2355 strip
.AddWebContents(page_b_contents
, -1,
2356 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2357 TabStripModel::ADD_ACTIVE
);
2358 WebContents
* page_b1_contents
= CreateWebContents();
2359 strip
.AddWebContents(page_b1_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2360 TabStripModel::ADD_NONE
);
2362 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(0));
2363 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(1));
2364 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(2));
2365 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(3));
2367 // Move page B to the start of the tab strip.
2368 strip
.MoveSelectedTabsTo(0);
2370 // Open page B2 in the background from B. It should end up after B.
2371 WebContents
* page_b2_contents
= CreateWebContents();
2372 strip
.AddWebContents(page_b2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2373 TabStripModel::ADD_NONE
);
2374 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2375 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2376 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2377 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2378 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(4));
2381 strip
.ActivateTabAt(2, true);
2382 EXPECT_EQ(page_a_contents
, strip
.GetActiveWebContents());
2384 // Open page A2 in the background from A. It should end up after A1.
2385 WebContents
* page_a2_contents
= CreateWebContents();
2386 strip
.AddWebContents(page_a2_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2387 TabStripModel::ADD_NONE
);
2388 EXPECT_EQ(page_b_contents
, strip
.GetWebContentsAt(0));
2389 EXPECT_EQ(page_b2_contents
, strip
.GetWebContentsAt(1));
2390 EXPECT_EQ(page_a_contents
, strip
.GetWebContentsAt(2));
2391 EXPECT_EQ(page_a1_contents
, strip
.GetWebContentsAt(3));
2392 EXPECT_EQ(page_a2_contents
, strip
.GetWebContentsAt(4));
2393 EXPECT_EQ(page_b1_contents
, strip
.GetWebContentsAt(5));
2395 strip
.CloseAllTabs();
2398 TEST_F(TabStripModelTest
, CloseSelectedTabs
) {
2399 TabStripDummyDelegate delegate
;
2400 TabStripModel
strip(&delegate
, profile());
2401 WebContents
* contents1
= CreateWebContents();
2402 WebContents
* contents2
= CreateWebContents();
2403 WebContents
* contents3
= CreateWebContents();
2404 strip
.AppendWebContents(contents1
, true);
2405 strip
.AppendWebContents(contents2
, true);
2406 strip
.AppendWebContents(contents3
, true);
2407 strip
.ToggleSelectionAt(1);
2408 strip
.CloseSelectedTabs();
2409 EXPECT_EQ(1, strip
.count());
2410 EXPECT_EQ(0, strip
.active_index());
2411 strip
.CloseAllTabs();
2414 TEST_F(TabStripModelTest
, MultipleSelection
) {
2415 typedef MockTabStripModelObserver::State State
;
2417 TabStripDummyDelegate delegate
;
2418 TabStripModel
strip(&delegate
, profile());
2419 MockTabStripModelObserver
observer(&strip
);
2420 WebContents
* contents0
= CreateWebContents();
2421 WebContents
* contents1
= CreateWebContents();
2422 WebContents
* contents2
= CreateWebContents();
2423 WebContents
* contents3
= CreateWebContents();
2424 strip
.AppendWebContents(contents0
, false);
2425 strip
.AppendWebContents(contents1
, false);
2426 strip
.AppendWebContents(contents2
, false);
2427 strip
.AppendWebContents(contents3
, false);
2428 strip
.AddObserver(&observer
);
2430 // Selection and active tab change.
2431 strip
.ActivateTabAt(3, true);
2432 ASSERT_EQ(2, observer
.GetStateCount());
2433 ASSERT_EQ(observer
.GetStateAt(0).action
,
2434 MockTabStripModelObserver::ACTIVATE
);
2435 State
s1(contents3
, 3, MockTabStripModelObserver::SELECT
);
2436 EXPECT_TRUE(observer
.StateEquals(1, s1
));
2437 observer
.ClearStates();
2439 // Adding all tabs to selection, active tab is now at 0.
2440 strip
.ExtendSelectionTo(0);
2441 ASSERT_EQ(3, observer
.GetStateCount());
2442 ASSERT_EQ(observer
.GetStateAt(0).action
,
2443 MockTabStripModelObserver::DEACTIVATE
);
2444 ASSERT_EQ(observer
.GetStateAt(1).action
,
2445 MockTabStripModelObserver::ACTIVATE
);
2446 State
s2(contents0
, 0, MockTabStripModelObserver::SELECT
);
2447 s2
.src_contents
= contents3
;
2449 EXPECT_TRUE(observer
.StateEquals(2, s2
));
2450 observer
.ClearStates();
2452 // Toggle the active tab, should make the next index active.
2453 strip
.ToggleSelectionAt(0);
2454 EXPECT_EQ(1, strip
.active_index());
2455 EXPECT_EQ(3U, strip
.selection_model().size());
2456 EXPECT_EQ(4, strip
.count());
2457 ASSERT_EQ(3, observer
.GetStateCount());
2458 ASSERT_EQ(observer
.GetStateAt(0).action
,
2459 MockTabStripModelObserver::DEACTIVATE
);
2460 ASSERT_EQ(observer
.GetStateAt(1).action
,
2461 MockTabStripModelObserver::ACTIVATE
);
2462 ASSERT_EQ(observer
.GetStateAt(2).action
,
2463 MockTabStripModelObserver::SELECT
);
2464 observer
.ClearStates();
2466 // Toggle the first tab back to selected and active.
2467 strip
.ToggleSelectionAt(0);
2468 EXPECT_EQ(0, strip
.active_index());
2469 EXPECT_EQ(4U, strip
.selection_model().size());
2470 EXPECT_EQ(4, strip
.count());
2471 ASSERT_EQ(3, observer
.GetStateCount());
2472 ASSERT_EQ(observer
.GetStateAt(0).action
,
2473 MockTabStripModelObserver::DEACTIVATE
);
2474 ASSERT_EQ(observer
.GetStateAt(1).action
,
2475 MockTabStripModelObserver::ACTIVATE
);
2476 ASSERT_EQ(observer
.GetStateAt(2).action
,
2477 MockTabStripModelObserver::SELECT
);
2478 observer
.ClearStates();
2480 // Closing one of the selected tabs, not the active one.
2481 strip
.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE
);
2482 EXPECT_EQ(3, strip
.count());
2483 ASSERT_EQ(3, observer
.GetStateCount());
2484 ASSERT_EQ(observer
.GetStateAt(0).action
,
2485 MockTabStripModelObserver::CLOSE
);
2486 ASSERT_EQ(observer
.GetStateAt(1).action
,
2487 MockTabStripModelObserver::DETACH
);
2488 ASSERT_EQ(observer
.GetStateAt(2).action
,
2489 MockTabStripModelObserver::SELECT
);
2490 observer
.ClearStates();
2492 // Closing the active tab, while there are others tabs selected.
2493 strip
.CloseWebContentsAt(0, TabStripModel::CLOSE_NONE
);
2494 EXPECT_EQ(2, strip
.count());
2495 ASSERT_EQ(5, observer
.GetStateCount());
2496 ASSERT_EQ(observer
.GetStateAt(0).action
,
2497 MockTabStripModelObserver::CLOSE
);
2498 ASSERT_EQ(observer
.GetStateAt(1).action
,
2499 MockTabStripModelObserver::DETACH
);
2500 ASSERT_EQ(observer
.GetStateAt(2).action
,
2501 MockTabStripModelObserver::DEACTIVATE
);
2502 ASSERT_EQ(observer
.GetStateAt(3).action
,
2503 MockTabStripModelObserver::ACTIVATE
);
2504 ASSERT_EQ(observer
.GetStateAt(4).action
,
2505 MockTabStripModelObserver::SELECT
);
2506 observer
.ClearStates();
2508 // Active tab is at 0, deselecting all but the active tab.
2509 strip
.ToggleSelectionAt(1);
2510 ASSERT_EQ(1, observer
.GetStateCount());
2511 ASSERT_EQ(observer
.GetStateAt(0).action
,
2512 MockTabStripModelObserver::SELECT
);
2513 observer
.ClearStates();
2515 // Attempting to deselect the only selected and therefore active tab,
2516 // it is ignored (no notifications being sent) and tab at 0 remains selected
2518 strip
.ToggleSelectionAt(0);
2519 ASSERT_EQ(0, observer
.GetStateCount());
2521 strip
.RemoveObserver(&observer
);
2522 strip
.CloseAllTabs();
2525 // Verifies that if we change the selection from a multi selection to a single
2526 // selection, but not in a way that changes the selected_index that
2527 // TabSelectionChanged is invoked.
2528 TEST_F(TabStripModelTest
, MultipleToSingle
) {
2529 typedef MockTabStripModelObserver::State State
;
2531 TabStripDummyDelegate delegate
;
2532 TabStripModel
strip(&delegate
, profile());
2533 WebContents
* contents1
= CreateWebContents();
2534 WebContents
* contents2
= CreateWebContents();
2535 strip
.AppendWebContents(contents1
, false);
2536 strip
.AppendWebContents(contents2
, false);
2537 strip
.ToggleSelectionAt(0);
2538 strip
.ToggleSelectionAt(1);
2540 MockTabStripModelObserver
observer(&strip
);
2541 strip
.AddObserver(&observer
);
2542 // This changes the selection (0 is no longer selected) but the selected_index
2543 // still remains at 1.
2544 strip
.ActivateTabAt(1, true);
2545 ASSERT_EQ(1, observer
.GetStateCount());
2546 State
s(contents2
, 1, MockTabStripModelObserver::SELECT
);
2547 s
.src_contents
= contents2
;
2549 s
.change_reason
= TabStripModelObserver::CHANGE_REASON_NONE
;
2550 EXPECT_TRUE(observer
.StateEquals(0, s
));
2551 strip
.RemoveObserver(&observer
);
2552 strip
.CloseAllTabs();
2555 // Verifies a newly inserted tab retains its previous blocked state.
2556 // http://crbug.com/276334
2557 TEST_F(TabStripModelTest
, TabBlockedState
) {
2558 // Start with a source tab strip.
2559 TabStripDummyDelegate dummy_tab_strip_delegate
;
2560 TabStripModel
strip_src(&dummy_tab_strip_delegate
, profile());
2561 TabBlockedStateTestBrowser
browser_src(&strip_src
);
2564 WebContents
* contents1
= CreateWebContents();
2565 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents1
);
2566 strip_src
.AppendWebContents(contents1
, false);
2569 WebContents
* contents2
= CreateWebContents();
2570 web_modal::WebContentsModalDialogManager::CreateForWebContents(contents2
);
2571 strip_src
.AppendWebContents(contents2
, false);
2573 // Create a destination tab strip.
2574 TabStripModel
strip_dst(&dummy_tab_strip_delegate
, profile());
2575 TabBlockedStateTestBrowser
browser_dst(&strip_dst
);
2577 // Setup a SingleWebContentsDialogManager for tab |contents2|.
2578 web_modal::WebContentsModalDialogManager
* modal_dialog_manager
=
2579 web_modal::WebContentsModalDialogManager::FromWebContents(contents2
);
2581 // Show a dialog that blocks tab |contents2|.
2582 // DummySingleWebContentsDialogManager doesn't care about the
2583 // dialog window value, so any dummy value works.
2584 DummySingleWebContentsDialogManager
* native_manager
=
2585 new DummySingleWebContentsDialogManager(
2586 reinterpret_cast<gfx::NativeWindow
>(0), modal_dialog_manager
);
2587 modal_dialog_manager
->ShowDialogWithManager(
2588 reinterpret_cast<gfx::NativeWindow
>(0),
2589 scoped_ptr
<web_modal::SingleWebContentsDialogManager
>(
2590 native_manager
).Pass());
2591 EXPECT_TRUE(strip_src
.IsTabBlocked(1));
2594 WebContents
* moved_contents
= strip_src
.DetachWebContentsAt(1);
2595 EXPECT_EQ(contents2
, moved_contents
);
2597 // Attach the tab to the destination tab strip.
2598 strip_dst
.AppendWebContents(moved_contents
, true);
2599 EXPECT_TRUE(strip_dst
.IsTabBlocked(0));
2601 strip_dst
.CloseAllTabs();
2602 strip_src
.CloseAllTabs();
2605 // Verifies ordering of tabs opened via a link from a pinned tab with a
2606 // subsequent pinned tab.
2607 TEST_F(TabStripModelTest
, LinkClicksWithPinnedTabOrdering
) {
2608 TabStripDummyDelegate delegate
;
2609 TabStripModel
strip(&delegate
, profile());
2611 // Open two pages, pinned.
2612 WebContents
* page_a_contents
= CreateWebContents();
2613 strip
.AddWebContents(page_a_contents
, -1,
2614 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2615 TabStripModel::ADD_ACTIVE
| TabStripModel::ADD_PINNED
);
2616 WebContents
* page_b_contents
= CreateWebContents();
2617 strip
.AddWebContents(page_b_contents
, -1,
2618 ui::PAGE_TRANSITION_AUTO_TOPLEVEL
,
2619 TabStripModel::ADD_ACTIVE
| TabStripModel::ADD_PINNED
);
2621 // Activate the first tab (a).
2622 strip
.ActivateTabAt(0, true);
2624 // Open two more tabs as link clicks. The first tab, c, should appear after
2625 // the pinned tabs followed by the second tab (d).
2626 WebContents
* page_c_contents
= CreateWebContents();
2627 WebContents
* page_d_contents
= CreateWebContents();
2628 strip
.AddWebContents(page_c_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2629 TabStripModel::ADD_NONE
);
2630 strip
.AddWebContents(page_d_contents
, -1, ui::PAGE_TRANSITION_LINK
,
2631 TabStripModel::ADD_NONE
);
2633 EXPECT_EQ(2, strip
.GetIndexOfWebContents(page_c_contents
));
2634 EXPECT_EQ(3, strip
.GetIndexOfWebContents(page_d_contents
));
2635 strip
.CloseAllTabs();