Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2011 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.
      4 
      5 #include <map>
      6 #include <string>
      7 
      8 #include "base/file_path.h"
      9 #include "base/file_util.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/path_service.h"
     12 #include "base/stl_util-inl.h"
     13 #include "base/string_number_conversions.h"
     14 #include "base/string_split.h"
     15 #include "base/string_util.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "chrome/browser/defaults.h"
     18 #include "chrome/browser/extensions/extension_tab_helper.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "chrome/browser/profiles/profile_manager.h"
     21 #include "chrome/browser/tabs/tab_strip_model.h"
     22 #include "chrome/browser/tabs/tab_strip_model_delegate.h"
     23 #include "chrome/browser/tabs/tab_strip_model_order_controller.h"
     24 #include "chrome/browser/ui/browser.h"
     25 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     26 #include "chrome/browser/ui/webui/new_tab_ui.h"
     27 #include "chrome/common/extensions/extension.h"
     28 #include "chrome/common/url_constants.h"
     29 #include "chrome/test/testing_profile.h"
     30 #include "content/browser/renderer_host/test_render_view_host.h"
     31 #include "content/browser/tab_contents/navigation_controller.h"
     32 #include "content/browser/tab_contents/navigation_entry.h"
     33 #include "content/browser/tab_contents/tab_contents.h"
     34 #include "content/common/notification_details.h"
     35 #include "content/common/notification_observer_mock.h"
     36 #include "content/common/notification_registrar.h"
     37 #include "content/common/notification_source.h"
     38 #include "content/common/property_bag.h"
     39 #include "testing/gtest/include/gtest/gtest.h"
     40 #include "ui/base/system_monitor/system_monitor.h"
     41 
     42 using testing::_;
     43 
     44 namespace {
     45 
     46 // Class used to delete a TabContents when another TabContents is destroyed.
     47 class DeleteTabContentsOnDestroyedObserver : public NotificationObserver {
     48  public:
     49   DeleteTabContentsOnDestroyedObserver(TabContentsWrapper* source,
     50                                        TabContentsWrapper* tab_to_delete)
     51       : source_(source),
     52         tab_to_delete_(tab_to_delete) {
     53     registrar_.Add(this,
     54                    NotificationType::TAB_CONTENTS_DESTROYED,
     55                    Source<TabContents>(source->tab_contents()));
     56   }
     57 
     58   virtual void Observe(NotificationType type,
     59                        const NotificationSource& source,
     60                        const NotificationDetails& details) {
     61     TabContentsWrapper* tab_to_delete = tab_to_delete_;
     62     tab_to_delete_ = NULL;
     63     delete tab_to_delete;
     64   }
     65 
     66  private:
     67   TabContentsWrapper* source_;
     68   TabContentsWrapper* tab_to_delete_;
     69   NotificationRegistrar registrar_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(DeleteTabContentsOnDestroyedObserver);
     72 };
     73 
     74 }  // namespace
     75 
     76 class TabStripDummyDelegate : public TabStripModelDelegate {
     77  public:
     78   explicit TabStripDummyDelegate(TabContentsWrapper* dummy)
     79       : dummy_contents_(dummy), can_close_(true), run_unload_(false) {}
     80   virtual ~TabStripDummyDelegate() {}
     81 
     82   void set_can_close(bool value) { can_close_ = value; }
     83   void set_run_unload_listener(bool value) { run_unload_ = value; }
     84 
     85   // Overridden from TabStripModelDelegate:
     86   virtual TabContentsWrapper* AddBlankTab(bool foreground) {
     87     return NULL;
     88   }
     89   virtual TabContentsWrapper* AddBlankTabAt(int index, bool foreground) {
     90     return NULL;
     91   }
     92   virtual Browser* CreateNewStripWithContents(TabContentsWrapper* contents,
     93                                               const gfx::Rect& window_bounds,
     94                                               const DockInfo& dock_info,
     95                                               bool maximize) {
     96     return NULL;
     97   }
     98   virtual void ContinueDraggingDetachedTab(TabContentsWrapper* contents,
     99                                            const gfx::Rect& window_bounds,
    100                                            const gfx::Rect& tab_bounds) {
    101   }
    102   virtual int GetDragActions() const { return 0; }
    103   virtual TabContentsWrapper* CreateTabContentsForURL(
    104       const GURL& url,
    105       const GURL& referrer,
    106       Profile* profile,
    107       PageTransition::Type transition,
    108       bool defer_load,
    109       SiteInstance* instance) const {
    110     if (url == GURL(chrome::kChromeUINewTabURL))
    111       return dummy_contents_;
    112     return NULL;
    113   }
    114   virtual bool CanDuplicateContentsAt(int index) { return false; }
    115   virtual void DuplicateContentsAt(int index) {}
    116   virtual void CloseFrameAfterDragSession() {}
    117   virtual void CreateHistoricalTab(TabContentsWrapper* contents) {}
    118   virtual bool RunUnloadListenerBeforeClosing(TabContentsWrapper* contents) {
    119     return run_unload_;
    120   }
    121   virtual bool CanRestoreTab() { return false; }
    122   virtual void RestoreTab() {}
    123   virtual bool CanCloseContentsAt(int index) { return can_close_ ; }
    124   virtual bool CanBookmarkAllTabs() const { return false; }
    125   virtual void BookmarkAllTabs() {}
    126   virtual bool CanCloseTab() const { return true; }
    127   virtual bool UseVerticalTabs() const { return false; }
    128   virtual void ToggleUseVerticalTabs() {}
    129   virtual bool LargeIconsPermitted() const { return true; }
    130 
    131  private:
    132   // A dummy TabContents we give to callers that expect us to actually build a
    133   // Destinations tab for them.
    134   TabContentsWrapper* dummy_contents_;
    135 
    136   // Whether tabs can be closed.
    137   bool can_close_;
    138 
    139   // Whether to report that we need to run an unload listener before closing.
    140   bool run_unload_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate);
    143 };
    144 
    145 class TabStripModelTest : public RenderViewHostTestHarness {
    146  public:
    147   TabContentsWrapper* CreateTabContents() {
    148     return Browser::TabContentsFactory(profile(), NULL, 0, NULL, NULL);
    149   }
    150 
    151   TabContentsWrapper* CreateTabContentsWithSharedRPH(
    152       TabContents* tab_contents) {
    153     TabContentsWrapper* retval = Browser::TabContentsFactory(profile(),
    154         tab_contents->render_view_host()->site_instance(), MSG_ROUTING_NONE,
    155         NULL, NULL);
    156     EXPECT_EQ(retval->tab_contents()->GetRenderProcessHost(),
    157               tab_contents->GetRenderProcessHost());
    158     return retval;
    159   }
    160 
    161   // Forwards a URL "load" request through to our dummy TabContents
    162   // implementation.
    163   void LoadURL(TabContents* con, const std::wstring& url) {
    164     controller().LoadURL(GURL(WideToUTF16(url)), GURL(), PageTransition::LINK);
    165   }
    166 
    167   void GoBack(TabContents* contents) {
    168     controller().GoBack();
    169   }
    170 
    171   void GoForward(TabContents* contents) {
    172     controller().GoForward();
    173   }
    174 
    175   void SwitchTabTo(TabContents* contents) {
    176     // contents()->DidBecomeSelected();
    177   }
    178 
    179   // Sets the id of the specified contents.
    180   void SetID(TabContents* contents, int id) {
    181     GetIDAccessor()->SetProperty(contents->property_bag(), id);
    182   }
    183 
    184   // Returns the id of the specified contents.
    185   int GetID(TabContents* contents) {
    186     return *GetIDAccessor()->GetProperty(contents->property_bag());
    187   }
    188 
    189   // Returns the state of the given tab strip as a string. The state consists
    190   // of the ID of each tab contents followed by a 'p' if pinned. For example,
    191   // if the model consists of two tabs with ids 2 and 1, with the first
    192   // tab pinned, this returns "2p 1".
    193   std::string GetPinnedState(const TabStripModel& model) {
    194     std::string actual;
    195     for (int i = 0; i < model.count(); ++i) {
    196       if (i > 0)
    197         actual += " ";
    198 
    199       actual +=
    200           base::IntToString(GetID(model.GetTabContentsAt(i)->tab_contents()));
    201 
    202       if (model.IsAppTab(i))
    203         actual += "a";
    204 
    205       if (model.IsTabPinned(i))
    206         actual += "p";
    207     }
    208     return actual;
    209   }
    210 
    211   std::string GetIndicesClosedByCommandAsString(
    212       const TabStripModel& model,
    213       int index,
    214       TabStripModel::ContextMenuCommand id) const {
    215     std::vector<int> indices = model.GetIndicesClosedByCommand(index, id);
    216     std::string result;
    217     for (size_t i = 0; i < indices.size(); ++i) {
    218       if (i != 0)
    219         result += " ";
    220       result += base::IntToString(indices[i]);
    221     }
    222     return result;
    223   }
    224 
    225   void PrepareTabstripForSelectionTest(TabStripModel* model,
    226                                        int tab_count,
    227                                        int pinned_count,
    228                                        const std::string& selected_tabs) {
    229     for (int i = 0; i < tab_count; ++i) {
    230       TabContentsWrapper* contents = CreateTabContents();
    231       SetID(contents->tab_contents(), i);
    232       model->AppendTabContents(contents, true);
    233     }
    234     for (int i = 0; i < pinned_count; ++i)
    235       model->SetTabPinned(i, true);
    236 
    237     TabStripSelectionModel selection_model;
    238     std::vector<std::string> selection;
    239     base::SplitStringAlongWhitespace(selected_tabs, &selection);
    240     for (size_t i = 0; i < selection.size(); ++i) {
    241       int value;
    242       ASSERT_TRUE(base::StringToInt(selection[i], &value));
    243       selection_model.AddIndexToSelection(value);
    244     }
    245     selection_model.set_active(selection_model.selected_indices()[0]);
    246     model->SetSelectionFromModel(selection_model);
    247   }
    248 
    249  private:
    250   PropertyAccessor<int>* GetIDAccessor() {
    251     static PropertyAccessor<int> accessor;
    252     return &accessor;
    253   }
    254 
    255   std::wstring test_dir_;
    256   std::wstring profile_path_;
    257   std::map<TabContents*, int> foo_;
    258 
    259   // ProfileManager requires a ui::SystemMonitor.
    260   ui::SystemMonitor system_monitor;
    261 
    262   ProfileManager pm_;
    263 };
    264 
    265 class MockTabStripModelObserver : public TabStripModelObserver {
    266  public:
    267   MockTabStripModelObserver() : empty_(true) {}
    268   ~MockTabStripModelObserver() {
    269     STLDeleteContainerPointers(states_.begin(), states_.end());
    270   }
    271 
    272   enum TabStripModelObserverAction {
    273     INSERT,
    274     CLOSE,
    275     DETACH,
    276     SELECT,
    277     MOVE,
    278     CHANGE,
    279     PINNED,
    280     REPLACED
    281   };
    282 
    283   struct State {
    284     State(TabContentsWrapper* a_dst_contents,
    285           int a_dst_index,
    286           TabStripModelObserverAction a_action)
    287         : src_contents(NULL),
    288           dst_contents(a_dst_contents),
    289           src_index(-1),
    290           dst_index(a_dst_index),
    291           user_gesture(false),
    292           foreground(false),
    293           action(a_action) {
    294     }
    295 
    296     TabContentsWrapper* src_contents;
    297     TabContentsWrapper* dst_contents;
    298     int src_index;
    299     int dst_index;
    300     bool user_gesture;
    301     bool foreground;
    302     TabStripModelObserverAction action;
    303   };
    304 
    305   int GetStateCount() const {
    306     return static_cast<int>(states_.size());
    307   }
    308 
    309   State* GetStateAt(int index) const {
    310     DCHECK(index >= 0 && index < GetStateCount());
    311     return states_.at(index);
    312   }
    313 
    314   bool StateEquals(int index, const State& state) {
    315     State* s = GetStateAt(index);
    316     EXPECT_EQ(state.src_contents, s->src_contents);
    317     EXPECT_EQ(state.dst_contents, s->dst_contents);
    318     EXPECT_EQ(state.src_index, s->src_index);
    319     EXPECT_EQ(state.dst_index, s->dst_index);
    320     EXPECT_EQ(state.user_gesture, s->user_gesture);
    321     EXPECT_EQ(state.foreground, s->foreground);
    322     EXPECT_EQ(state.action, s->action);
    323     return (s->src_contents == state.src_contents &&
    324             s->dst_contents == state.dst_contents &&
    325             s->src_index == state.src_index &&
    326             s->dst_index == state.dst_index &&
    327             s->user_gesture == state.user_gesture &&
    328             s->foreground == state.foreground &&
    329             s->action == state.action);
    330   }
    331 
    332   // TabStripModelObserver implementation:
    333   virtual void TabInsertedAt(TabContentsWrapper* contents,
    334                              int index,
    335                              bool foreground) {
    336     empty_ = false;
    337     State* s = new State(contents, index, INSERT);
    338     s->foreground = foreground;
    339     states_.push_back(s);
    340   }
    341   virtual void TabSelectedAt(TabContentsWrapper* old_contents,
    342                              TabContentsWrapper* new_contents,
    343                              int index,
    344                              bool user_gesture) {
    345     State* s = new State(new_contents, index, SELECT);
    346     s->src_contents = old_contents;
    347     s->user_gesture = user_gesture;
    348     states_.push_back(s);
    349   }
    350   virtual void TabMoved(
    351       TabContentsWrapper* contents, int from_index, int to_index) {
    352     State* s = new State(contents, to_index, MOVE);
    353     s->src_index = from_index;
    354     states_.push_back(s);
    355   }
    356 
    357   virtual void TabClosingAt(TabStripModel* tab_strip_model,
    358                             TabContentsWrapper* contents,
    359                             int index) {
    360     states_.push_back(new State(contents, index, CLOSE));
    361   }
    362   virtual void TabDetachedAt(TabContentsWrapper* contents, int index) {
    363     states_.push_back(new State(contents, index, DETACH));
    364   }
    365   virtual void TabChangedAt(TabContentsWrapper* contents, int index,
    366                             TabChangeType change_type) {
    367     states_.push_back(new State(contents, index, CHANGE));
    368   }
    369   virtual void TabReplacedAt(TabStripModel* tab_strip_model,
    370                              TabContentsWrapper* old_contents,
    371                              TabContentsWrapper* new_contents,
    372                              int index) {
    373     State* s = new State(new_contents, index, REPLACED);
    374     s ->src_contents = old_contents;
    375     states_.push_back(s);
    376   }
    377   virtual void TabPinnedStateChanged(TabContentsWrapper* contents, int index) {
    378     states_.push_back(new State(contents, index, PINNED));
    379   }
    380   virtual void TabStripEmpty() {
    381     empty_ = true;
    382   }
    383 
    384   void ClearStates() {
    385     STLDeleteContainerPointers(states_.begin(), states_.end());
    386     states_.clear();
    387   }
    388 
    389   bool empty() const { return empty_; }
    390 
    391  private:
    392   std::vector<State*> states_;
    393 
    394   bool empty_;
    395 
    396   DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver);
    397 };
    398 
    399 TEST_F(TabStripModelTest, TestBasicAPI) {
    400   TabStripDummyDelegate delegate(NULL);
    401   TabStripModel tabstrip(&delegate, profile());
    402   MockTabStripModelObserver observer;
    403   tabstrip.AddObserver(&observer);
    404 
    405   EXPECT_TRUE(tabstrip.empty());
    406 
    407   typedef MockTabStripModelObserver::State State;
    408 
    409   TabContentsWrapper* contents1 = CreateTabContents();
    410 
    411   // Note! The ordering of these tests is important, each subsequent test
    412   // builds on the state established in the previous. This is important if you
    413   // ever insert tests rather than append.
    414 
    415   // Test AppendTabContents, ContainsIndex
    416   {
    417     EXPECT_FALSE(tabstrip.ContainsIndex(0));
    418     tabstrip.AppendTabContents(contents1, true);
    419     EXPECT_TRUE(tabstrip.ContainsIndex(0));
    420     EXPECT_EQ(1, tabstrip.count());
    421     EXPECT_EQ(2, observer.GetStateCount());
    422     State s1(contents1, 0, MockTabStripModelObserver::INSERT);
    423     s1.foreground = true;
    424     EXPECT_TRUE(observer.StateEquals(0, s1));
    425     State s2(contents1, 0, MockTabStripModelObserver::SELECT);
    426     s2.src_contents = NULL;
    427     EXPECT_TRUE(observer.StateEquals(1, s2));
    428     observer.ClearStates();
    429   }
    430 
    431   // Test InsertTabContentsAt, foreground tab.
    432   TabContentsWrapper* contents2 = CreateTabContents();
    433   {
    434     tabstrip.InsertTabContentsAt(1, contents2, TabStripModel::ADD_ACTIVE);
    435 
    436     EXPECT_EQ(2, tabstrip.count());
    437     EXPECT_EQ(2, observer.GetStateCount());
    438     State s1(contents2, 1, MockTabStripModelObserver::INSERT);
    439     s1.foreground = true;
    440     EXPECT_TRUE(observer.StateEquals(0, s1));
    441     State s2(contents2, 1, MockTabStripModelObserver::SELECT);
    442     s2.src_contents = contents1;
    443     EXPECT_TRUE(observer.StateEquals(1, s2));
    444     observer.ClearStates();
    445   }
    446 
    447   // Test InsertTabContentsAt, background tab.
    448   TabContentsWrapper* contents3 = CreateTabContents();
    449   {
    450     tabstrip.InsertTabContentsAt(2, contents3, TabStripModel::ADD_NONE);
    451 
    452     EXPECT_EQ(3, tabstrip.count());
    453     EXPECT_EQ(1, observer.GetStateCount());
    454     State s1(contents3, 2, MockTabStripModelObserver::INSERT);
    455     s1.foreground = false;
    456     EXPECT_TRUE(observer.StateEquals(0, s1));
    457     observer.ClearStates();
    458   }
    459 
    460   // Test ActivateTabAt
    461   {
    462     tabstrip.ActivateTabAt(2, true);
    463     EXPECT_EQ(1, observer.GetStateCount());
    464     State s1(contents3, 2, MockTabStripModelObserver::SELECT);
    465     s1.src_contents = contents2;
    466     s1.user_gesture = true;
    467     EXPECT_TRUE(observer.StateEquals(0, s1));
    468     observer.ClearStates();
    469   }
    470 
    471   // Test DetachTabContentsAt
    472   {
    473     // Detach
    474     TabContentsWrapper* detached = tabstrip.DetachTabContentsAt(2);
    475     // ... and append again because we want this for later.
    476     tabstrip.AppendTabContents(detached, true);
    477     EXPECT_EQ(4, observer.GetStateCount());
    478     State s1(detached, 2, MockTabStripModelObserver::DETACH);
    479     EXPECT_TRUE(observer.StateEquals(0, s1));
    480     State s2(contents2, 1, MockTabStripModelObserver::SELECT);
    481     s2.src_contents = contents3;
    482     s2.user_gesture = false;
    483     EXPECT_TRUE(observer.StateEquals(1, s2));
    484     State s3(detached, 2, MockTabStripModelObserver::INSERT);
    485     s3.foreground = true;
    486     EXPECT_TRUE(observer.StateEquals(2, s3));
    487     State s4(detached, 2, MockTabStripModelObserver::SELECT);
    488     s4.src_contents = contents2;
    489     s4.user_gesture = false;
    490     EXPECT_TRUE(observer.StateEquals(3, s4));
    491     observer.ClearStates();
    492   }
    493 
    494   // Test CloseTabContentsAt
    495   {
    496     // Let's test nothing happens when the delegate veto the close.
    497     delegate.set_can_close(false);
    498     EXPECT_FALSE(tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE));
    499     EXPECT_EQ(3, tabstrip.count());
    500     EXPECT_EQ(0, observer.GetStateCount());
    501 
    502     // Now let's close for real.
    503     delegate.set_can_close(true);
    504     EXPECT_TRUE(tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE));
    505     EXPECT_EQ(2, tabstrip.count());
    506 
    507     EXPECT_EQ(3, observer.GetStateCount());
    508     State s1(contents3, 2, MockTabStripModelObserver::CLOSE);
    509     EXPECT_TRUE(observer.StateEquals(0, s1));
    510     State s2(contents3, 2, MockTabStripModelObserver::DETACH);
    511     EXPECT_TRUE(observer.StateEquals(1, s2));
    512     State s3(contents2, 1, MockTabStripModelObserver::SELECT);
    513     s3.src_contents = contents3;
    514     s3.user_gesture = false;
    515     EXPECT_TRUE(observer.StateEquals(2, s3));
    516     observer.ClearStates();
    517   }
    518 
    519   // Test MoveTabContentsAt, select_after_move == true
    520   {
    521     tabstrip.MoveTabContentsAt(1, 0, true);
    522 
    523     EXPECT_EQ(1, observer.GetStateCount());
    524     State s1(contents2, 0, MockTabStripModelObserver::MOVE);
    525     s1.src_index = 1;
    526     EXPECT_TRUE(observer.StateEquals(0, s1));
    527     EXPECT_EQ(0, tabstrip.active_index());
    528     observer.ClearStates();
    529   }
    530 
    531   // Test MoveTabContentsAt, select_after_move == false
    532   {
    533     tabstrip.MoveTabContentsAt(1, 0, false);
    534     EXPECT_EQ(1, observer.GetStateCount());
    535     State s1(contents1, 0, MockTabStripModelObserver::MOVE);
    536     s1.src_index = 1;
    537     EXPECT_TRUE(observer.StateEquals(0, s1));
    538     EXPECT_EQ(1, tabstrip.active_index());
    539 
    540     tabstrip.MoveTabContentsAt(0, 1, false);
    541     observer.ClearStates();
    542   }
    543 
    544   // Test Getters
    545   {
    546     EXPECT_EQ(contents2, tabstrip.GetSelectedTabContents());
    547     EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(0));
    548     EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(1));
    549     EXPECT_EQ(0, tabstrip.GetIndexOfTabContents(contents2));
    550     EXPECT_EQ(1, tabstrip.GetIndexOfTabContents(contents1));
    551     EXPECT_EQ(0, tabstrip.GetIndexOfController(&contents2->controller()));
    552     EXPECT_EQ(1, tabstrip.GetIndexOfController(&contents1->controller()));
    553   }
    554 
    555   // Test UpdateTabContentsStateAt
    556   {
    557     tabstrip.UpdateTabContentsStateAt(0, TabStripModelObserver::ALL);
    558     EXPECT_EQ(1, observer.GetStateCount());
    559     State s1(contents2, 0, MockTabStripModelObserver::CHANGE);
    560     EXPECT_TRUE(observer.StateEquals(0, s1));
    561     observer.ClearStates();
    562   }
    563 
    564   // Test SelectNextTab, SelectPreviousTab, SelectLastTab
    565   {
    566     // Make sure the second of the two tabs is selected first...
    567     tabstrip.ActivateTabAt(1, true);
    568     tabstrip.SelectPreviousTab();
    569     EXPECT_EQ(0, tabstrip.active_index());
    570     tabstrip.SelectLastTab();
    571     EXPECT_EQ(1, tabstrip.active_index());
    572     tabstrip.SelectNextTab();
    573     EXPECT_EQ(0, tabstrip.active_index());
    574   }
    575 
    576   // Test CloseSelectedTabs
    577   {
    578     tabstrip.CloseSelectedTabs();
    579     // |CloseSelectedTabs| calls CloseTabContentsAt, we already tested that, now
    580     // just verify that the count and selected index have changed
    581     // appropriately...
    582     EXPECT_EQ(1, tabstrip.count());
    583     EXPECT_EQ(0, tabstrip.active_index());
    584   }
    585 
    586   tabstrip.CloseAllTabs();
    587   // TabStripModel should now be empty.
    588   EXPECT_TRUE(tabstrip.empty());
    589 
    590   // Opener methods are tested below...
    591 
    592   tabstrip.RemoveObserver(&observer);
    593 }
    594 
    595 TEST_F(TabStripModelTest, TestBasicOpenerAPI) {
    596   TabStripDummyDelegate delegate(NULL);
    597   TabStripModel tabstrip(&delegate, profile());
    598   EXPECT_TRUE(tabstrip.empty());
    599 
    600   // This is a basic test of opener functionality. opener_contents is created
    601   // as the first tab in the strip and then we create 5 other tabs in the
    602   // background with opener_contents set as their opener.
    603 
    604   TabContentsWrapper* opener_contents = CreateTabContents();
    605   NavigationController* opener = &opener_contents->controller();
    606   tabstrip.AppendTabContents(opener_contents, true);
    607   TabContentsWrapper* contents1 = CreateTabContents();
    608   TabContentsWrapper* contents2 = CreateTabContents();
    609   TabContentsWrapper* contents3 = CreateTabContents();
    610   TabContentsWrapper* contents4 = CreateTabContents();
    611   TabContentsWrapper* contents5 = CreateTabContents();
    612 
    613   // We use |InsertTabContentsAt| here instead of AppendTabContents so that
    614   // openership relationships are preserved.
    615   tabstrip.InsertTabContentsAt(tabstrip.count(), contents1,
    616                                TabStripModel::ADD_INHERIT_GROUP);
    617   tabstrip.InsertTabContentsAt(tabstrip.count(), contents2,
    618                                TabStripModel::ADD_INHERIT_GROUP);
    619   tabstrip.InsertTabContentsAt(tabstrip.count(), contents3,
    620                                TabStripModel::ADD_INHERIT_GROUP);
    621   tabstrip.InsertTabContentsAt(tabstrip.count(), contents4,
    622                                TabStripModel::ADD_INHERIT_GROUP);
    623   tabstrip.InsertTabContentsAt(tabstrip.count(), contents5,
    624                                TabStripModel::ADD_INHERIT_GROUP);
    625 
    626   // All the tabs should have the same opener.
    627   for (int i = 1; i < tabstrip.count(); ++i)
    628     EXPECT_EQ(opener, tabstrip.GetOpenerOfTabContentsAt(i));
    629 
    630   // If there is a next adjacent item, then the index should be of that item.
    631   EXPECT_EQ(2, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 1, false));
    632   // If the last tab in the group is closed, the preceding tab in the same
    633   // group should be selected.
    634   EXPECT_EQ(4, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 5, false));
    635 
    636   // Tests the method that finds the last tab opened by the same opener in the
    637   // strip (this is the insertion index for the next background tab for the
    638   // specified opener).
    639   EXPECT_EQ(5, tabstrip.GetIndexOfLastTabContentsOpenedBy(opener, 1));
    640 
    641   // For a tab that has opened no other tabs, the return value should always be
    642   // -1...
    643   NavigationController* o1 = &contents1->controller();
    644   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(o1, 3, false));
    645   EXPECT_EQ(-1, tabstrip.GetIndexOfLastTabContentsOpenedBy(o1, 3));
    646 
    647   // ForgetAllOpeners should destroy all opener relationships.
    648   tabstrip.ForgetAllOpeners();
    649   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 1, false));
    650   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 5, false));
    651   EXPECT_EQ(-1, tabstrip.GetIndexOfLastTabContentsOpenedBy(opener, 1));
    652 
    653   tabstrip.CloseAllTabs();
    654   EXPECT_TRUE(tabstrip.empty());
    655 }
    656 
    657 static int GetInsertionIndex(TabStripModel* tabstrip,
    658                              TabContentsWrapper* contents) {
    659   return tabstrip->order_controller()->DetermineInsertionIndex(
    660       contents, PageTransition::LINK, false);
    661 }
    662 
    663 static void InsertTabContentses(TabStripModel* tabstrip,
    664                                 TabContentsWrapper* contents1,
    665                                 TabContentsWrapper* contents2,
    666                                 TabContentsWrapper* contents3) {
    667   tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents1),
    668                                 contents1, TabStripModel::ADD_INHERIT_GROUP);
    669   tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents2),
    670                                 contents2, TabStripModel::ADD_INHERIT_GROUP);
    671   tabstrip->InsertTabContentsAt(GetInsertionIndex(tabstrip, contents3),
    672                                 contents3, TabStripModel::ADD_INHERIT_GROUP);
    673 }
    674 
    675 // Tests opening background tabs.
    676 TEST_F(TabStripModelTest, TestLTRInsertionOptions) {
    677   TabStripDummyDelegate delegate(NULL);
    678   TabStripModel tabstrip(&delegate, profile());
    679   EXPECT_TRUE(tabstrip.empty());
    680 
    681   TabContentsWrapper* opener_contents = CreateTabContents();
    682   tabstrip.AppendTabContents(opener_contents, true);
    683 
    684   TabContentsWrapper* contents1 = CreateTabContents();
    685   TabContentsWrapper* contents2 = CreateTabContents();
    686   TabContentsWrapper* contents3 = CreateTabContents();
    687 
    688   // Test LTR
    689   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    690   EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(1));
    691   EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(2));
    692   EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(3));
    693 
    694   tabstrip.CloseAllTabs();
    695   EXPECT_TRUE(tabstrip.empty());
    696 }
    697 
    698 // Tests inserting tabs with InsertAfter set to false.
    699 TEST_F(TabStripModelTest, InsertBefore) {
    700   TabStripDummyDelegate delegate(NULL);
    701   TabStripModel tabstrip(&delegate, profile());
    702   tabstrip.SetInsertionPolicy(TabStripModel::INSERT_BEFORE);
    703   EXPECT_TRUE(tabstrip.empty());
    704 
    705   TabContentsWrapper* contents1 = CreateTabContents();
    706   TabContentsWrapper* contents2 = CreateTabContents();
    707   TabContentsWrapper* contents3 = CreateTabContents();
    708 
    709   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    710 
    711   // The order should be reversed.
    712   EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(0));
    713   EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(1));
    714   EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(2));
    715 
    716   tabstrip.CloseAllTabs();
    717   EXPECT_TRUE(tabstrip.empty());
    718 }
    719 
    720 // Tests opening background tabs with InsertAfter set to false.
    721 TEST_F(TabStripModelTest, InsertBeforeOpeners) {
    722   TabStripDummyDelegate delegate(NULL);
    723   TabStripModel tabstrip(&delegate, profile());
    724   tabstrip.SetInsertionPolicy(TabStripModel::INSERT_BEFORE);
    725   EXPECT_TRUE(tabstrip.empty());
    726   TabContentsWrapper* opener_contents = CreateTabContents();
    727   tabstrip.AppendTabContents(opener_contents, true);
    728 
    729   TabContentsWrapper* contents1 = CreateTabContents();
    730   TabContentsWrapper* contents2 = CreateTabContents();
    731   TabContentsWrapper* contents3 = CreateTabContents();
    732 
    733   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    734 
    735   // The order should be reversed.
    736   EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(0));
    737   EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(1));
    738   EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(2));
    739 
    740   tabstrip.CloseAllTabs();
    741   EXPECT_TRUE(tabstrip.empty());
    742 }
    743 
    744 // This test constructs a tabstrip, and then simulates loading several tabs in
    745 // the background from link clicks on the first tab. Then it simulates opening
    746 // a new tab from the first tab in the foreground via a link click, verifies
    747 // that this tab is opened adjacent to the opener, then closes it.
    748 // Finally it tests that a tab opened for some non-link purpose openes at the
    749 // end of the strip, not bundled to any existing context.
    750 TEST_F(TabStripModelTest, TestInsertionIndexDetermination) {
    751   TabStripDummyDelegate delegate(NULL);
    752   TabStripModel tabstrip(&delegate, profile());
    753   EXPECT_TRUE(tabstrip.empty());
    754 
    755   TabContentsWrapper* opener_contents = CreateTabContents();
    756   NavigationController* opener = &opener_contents->controller();
    757   tabstrip.AppendTabContents(opener_contents, true);
    758 
    759   // Open some other random unrelated tab in the background to monkey with our
    760   // insertion index.
    761   TabContentsWrapper* other_contents = CreateTabContents();
    762   tabstrip.AppendTabContents(other_contents, false);
    763 
    764   TabContentsWrapper* contents1 = CreateTabContents();
    765   TabContentsWrapper* contents2 = CreateTabContents();
    766   TabContentsWrapper* contents3 = CreateTabContents();
    767 
    768   // Start by testing LTR
    769   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    770   EXPECT_EQ(opener_contents, tabstrip.GetTabContentsAt(0));
    771   EXPECT_EQ(contents1, tabstrip.GetTabContentsAt(1));
    772   EXPECT_EQ(contents2, tabstrip.GetTabContentsAt(2));
    773   EXPECT_EQ(contents3, tabstrip.GetTabContentsAt(3));
    774   EXPECT_EQ(other_contents, tabstrip.GetTabContentsAt(4));
    775 
    776   // The opener API should work...
    777   EXPECT_EQ(3, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 2, false));
    778   EXPECT_EQ(2, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 3, false));
    779   EXPECT_EQ(3, tabstrip.GetIndexOfLastTabContentsOpenedBy(opener, 1));
    780 
    781   // Now open a foreground tab from a link. It should be opened adjacent to the
    782   // opener tab.
    783   TabContentsWrapper* fg_link_contents = CreateTabContents();
    784   int insert_index = tabstrip.order_controller()->DetermineInsertionIndex(
    785       fg_link_contents, PageTransition::LINK, true);
    786   EXPECT_EQ(1, insert_index);
    787   tabstrip.InsertTabContentsAt(insert_index, fg_link_contents,
    788                                TabStripModel::ADD_ACTIVE |
    789                                TabStripModel::ADD_INHERIT_GROUP);
    790   EXPECT_EQ(1, tabstrip.active_index());
    791   EXPECT_EQ(fg_link_contents, tabstrip.GetSelectedTabContents());
    792 
    793   // Now close this contents. The selection should move to the opener contents.
    794   tabstrip.CloseSelectedTabs();
    795   EXPECT_EQ(0, tabstrip.active_index());
    796 
    797   // Now open a new empty tab. It should open at the end of the strip.
    798   TabContentsWrapper* fg_nonlink_contents = CreateTabContents();
    799   insert_index = tabstrip.order_controller()->DetermineInsertionIndex(
    800       fg_nonlink_contents, PageTransition::AUTO_BOOKMARK, true);
    801   EXPECT_EQ(tabstrip.count(), insert_index);
    802   // We break the opener relationship...
    803   tabstrip.InsertTabContentsAt(insert_index, fg_nonlink_contents,
    804                                TabStripModel::ADD_NONE);
    805   // Now select it, so that user_gesture == true causes the opener relationship
    806   // to be forgotten...
    807   tabstrip.ActivateTabAt(tabstrip.count() - 1, true);
    808   EXPECT_EQ(tabstrip.count() - 1, tabstrip.active_index());
    809   EXPECT_EQ(fg_nonlink_contents, tabstrip.GetSelectedTabContents());
    810 
    811   // Verify that all opener relationships are forgotten.
    812   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 2, false));
    813   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 3, false));
    814   EXPECT_EQ(-1, tabstrip.GetIndexOfNextTabContentsOpenedBy(opener, 3, false));
    815   EXPECT_EQ(-1, tabstrip.GetIndexOfLastTabContentsOpenedBy(opener, 1));
    816 
    817   tabstrip.CloseAllTabs();
    818   EXPECT_TRUE(tabstrip.empty());
    819 }
    820 
    821 // Tests that selection is shifted to the correct tab when a tab is closed.
    822 // If a tab is in the background when it is closed, the selection does not
    823 // change.
    824 // If a tab is in the foreground (selected),
    825 //   If that tab does not have an opener, selection shifts to the right.
    826 //   If the tab has an opener,
    827 //     The next tab (scanning LTR) in the entire strip that has the same opener
    828 //     is selected
    829 //     If there are no other tabs that have the same opener,
    830 //       The opener is selected
    831 //
    832 TEST_F(TabStripModelTest, TestSelectOnClose) {
    833   TabStripDummyDelegate delegate(NULL);
    834   TabStripModel tabstrip(&delegate, profile());
    835   EXPECT_TRUE(tabstrip.empty());
    836 
    837   TabContentsWrapper* opener_contents = CreateTabContents();
    838   tabstrip.AppendTabContents(opener_contents, true);
    839 
    840   TabContentsWrapper* contents1 = CreateTabContents();
    841   TabContentsWrapper* contents2 = CreateTabContents();
    842   TabContentsWrapper* contents3 = CreateTabContents();
    843 
    844   // Note that we use Detach instead of Close throughout this test to avoid
    845   // having to keep reconstructing these TabContentses.
    846 
    847   // First test that closing tabs that are in the background doesn't adjust the
    848   // current selection.
    849   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    850   EXPECT_EQ(0, tabstrip.active_index());
    851 
    852   tabstrip.DetachTabContentsAt(1);
    853   EXPECT_EQ(0, tabstrip.active_index());
    854 
    855   for (int i = tabstrip.count() - 1; i >= 1; --i)
    856     tabstrip.DetachTabContentsAt(i);
    857 
    858   // Now test that when a tab doesn't have an opener, selection shifts to the
    859   // right when the tab is closed.
    860   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    861   EXPECT_EQ(0, tabstrip.active_index());
    862 
    863   tabstrip.ForgetAllOpeners();
    864   tabstrip.ActivateTabAt(1, true);
    865   EXPECT_EQ(1, tabstrip.active_index());
    866   tabstrip.DetachTabContentsAt(1);
    867   EXPECT_EQ(1, tabstrip.active_index());
    868   tabstrip.DetachTabContentsAt(1);
    869   EXPECT_EQ(1, tabstrip.active_index());
    870   tabstrip.DetachTabContentsAt(1);
    871   EXPECT_EQ(0, tabstrip.active_index());
    872 
    873   for (int i = tabstrip.count() - 1; i >= 1; --i)
    874     tabstrip.DetachTabContentsAt(i);
    875 
    876   // Now test that when a tab does have an opener, it selects the next tab
    877   // opened by the same opener scanning LTR when it is closed.
    878   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
    879   EXPECT_EQ(0, tabstrip.active_index());
    880   tabstrip.ActivateTabAt(2, false);
    881   EXPECT_EQ(2, tabstrip.active_index());
    882   tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE);
    883   EXPECT_EQ(2, tabstrip.active_index());
    884   tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE);
    885   EXPECT_EQ(1, tabstrip.active_index());
    886   tabstrip.CloseTabContentsAt(1, TabStripModel::CLOSE_NONE);
    887   EXPECT_EQ(0, tabstrip.active_index());
    888   // Finally test that when a tab has no "siblings" that the opener is
    889   // selected.
    890   TabContentsWrapper* other_contents = CreateTabContents();
    891   tabstrip.InsertTabContentsAt(1, other_contents, TabStripModel::ADD_NONE);
    892   EXPECT_EQ(2, tabstrip.count());
    893   TabContentsWrapper* opened_contents = CreateTabContents();
    894   tabstrip.InsertTabContentsAt(2, opened_contents,
    895                                TabStripModel::ADD_ACTIVE |
    896                                TabStripModel::ADD_INHERIT_GROUP);
    897   EXPECT_EQ(2, tabstrip.active_index());
    898   tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE);
    899   EXPECT_EQ(0, tabstrip.active_index());
    900 
    901   tabstrip.CloseAllTabs();
    902   EXPECT_TRUE(tabstrip.empty());
    903 }
    904 
    905 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
    906 // CommandCloseTab.
    907 TEST_F(TabStripModelTest, CommandCloseTab) {
    908   TabStripDummyDelegate delegate(NULL);
    909   TabStripModel tabstrip(&delegate, profile());
    910   EXPECT_TRUE(tabstrip.empty());
    911 
    912   // Make sure can_close is honored.
    913   ASSERT_NO_FATAL_FAILURE(
    914       PrepareTabstripForSelectionTest(&tabstrip, 1, 0, "0"));
    915   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    916                   0, TabStripModel::CommandCloseTab));
    917   delegate.set_can_close(false);
    918   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    919                    0, TabStripModel::CommandCloseTab));
    920   delegate.set_can_close(true);
    921   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
    922   ASSERT_TRUE(tabstrip.empty());
    923 
    924   // Make sure close on a tab that is selected effects all the selected tabs.
    925   ASSERT_NO_FATAL_FAILURE(
    926       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    927   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    928                   0, TabStripModel::CommandCloseTab));
    929   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
    930   // Should have closed tabs 0 and 1.
    931   EXPECT_EQ("2", GetPinnedState(tabstrip));
    932 
    933   tabstrip.CloseAllTabs();
    934   EXPECT_TRUE(tabstrip.empty());
    935 
    936   // Select two tabs and make close on a tab that isn't selected doesn't effect
    937   // selected tabs.
    938   ASSERT_NO_FATAL_FAILURE(
    939       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    940   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    941                   2, TabStripModel::CommandCloseTab));
    942   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab);
    943   // Should have closed tab 2.
    944   EXPECT_EQ("0 1", GetPinnedState(tabstrip));
    945   tabstrip.CloseAllTabs();
    946   EXPECT_TRUE(tabstrip.empty());
    947 
    948   // Tests with 3 tabs, one pinned, two tab selected, one of which is pinned.
    949   ASSERT_NO_FATAL_FAILURE(
    950       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "0 1"));
    951   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    952                   0, TabStripModel::CommandCloseTab));
    953   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
    954   // Should have closed tab 2.
    955   EXPECT_EQ("2", GetPinnedState(tabstrip));
    956   tabstrip.CloseAllTabs();
    957   EXPECT_TRUE(tabstrip.empty());
    958 }
    959 
    960 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
    961 // CommandCloseTabs.
    962 TEST_F(TabStripModelTest, CommandCloseOtherTabs) {
    963   TabStripDummyDelegate delegate(NULL);
    964   TabStripModel tabstrip(&delegate, profile());
    965   EXPECT_TRUE(tabstrip.empty());
    966 
    967   // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
    968   // and close two tabs.
    969   ASSERT_NO_FATAL_FAILURE(
    970       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    971   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    972                   0, TabStripModel::CommandCloseOtherTabs));
    973   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs);
    974   EXPECT_EQ("0 1", GetPinnedState(tabstrip));
    975   tabstrip.CloseAllTabs();
    976   EXPECT_TRUE(tabstrip.empty());
    977 
    978   // Select two tabs, CommandCloseOtherTabs should be enabled and invoking it
    979   // with a non-selected index should close the two other tabs.
    980   ASSERT_NO_FATAL_FAILURE(
    981       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    982   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    983                   2, TabStripModel::CommandCloseOtherTabs));
    984   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs);
    985   EXPECT_EQ("0 1", GetPinnedState(tabstrip));
    986   tabstrip.CloseAllTabs();
    987   EXPECT_TRUE(tabstrip.empty());
    988 
    989   // Select all, CommandCloseOtherTabs should not be enabled.
    990   ASSERT_NO_FATAL_FAILURE(
    991       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1 2"));
    992   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
    993                   2, TabStripModel::CommandCloseOtherTabs));
    994   tabstrip.CloseAllTabs();
    995   EXPECT_TRUE(tabstrip.empty());
    996 
    997   // Three tabs, pin one, select the two non-pinned.
    998   ASSERT_NO_FATAL_FAILURE(
    999       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "1 2"));
   1000   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1001                   1, TabStripModel::CommandCloseOtherTabs));
   1002   // If we don't pass in the pinned index, the command should be enabled.
   1003   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1004                   0, TabStripModel::CommandCloseOtherTabs));
   1005   tabstrip.CloseAllTabs();
   1006   EXPECT_TRUE(tabstrip.empty());
   1007 
   1008   // 3 tabs, one pinned.
   1009   ASSERT_NO_FATAL_FAILURE(
   1010       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "1"));
   1011   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1012                   1, TabStripModel::CommandCloseOtherTabs));
   1013   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1014                   0, TabStripModel::CommandCloseOtherTabs));
   1015   tabstrip.ExecuteContextMenuCommand(1, TabStripModel::CommandCloseOtherTabs);
   1016   // The pinned tab shouldn't be closed.
   1017   EXPECT_EQ("0p 1", GetPinnedState(tabstrip));
   1018   tabstrip.CloseAllTabs();
   1019   EXPECT_TRUE(tabstrip.empty());
   1020 }
   1021 
   1022 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
   1023 // CommandCloseTabsToRight.
   1024 TEST_F(TabStripModelTest, CommandCloseTabsToRight) {
   1025   TabStripDummyDelegate delegate(NULL);
   1026   TabStripModel tabstrip(&delegate, profile());
   1027   EXPECT_TRUE(tabstrip.empty());
   1028 
   1029   // Create three tabs, select last two tabs, CommandCloseTabsToRight should
   1030   // only be enabled for the first tab.
   1031   ASSERT_NO_FATAL_FAILURE(
   1032       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "1 2"));
   1033   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1034                   0, TabStripModel::CommandCloseTabsToRight));
   1035   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1036                    1, TabStripModel::CommandCloseTabsToRight));
   1037   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1038                    2, TabStripModel::CommandCloseTabsToRight));
   1039   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight);
   1040   EXPECT_EQ("0", GetPinnedState(tabstrip));
   1041   tabstrip.CloseAllTabs();
   1042   EXPECT_TRUE(tabstrip.empty());
   1043 }
   1044 
   1045 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
   1046 // CommandTogglePinned.
   1047 TEST_F(TabStripModelTest, CommandTogglePinned) {
   1048   TabStripDummyDelegate delegate(NULL);
   1049   TabStripModel tabstrip(&delegate, profile());
   1050   EXPECT_TRUE(tabstrip.empty());
   1051 
   1052   // Create three tabs with one pinned, pin the first two.
   1053   ASSERT_NO_FATAL_FAILURE(
   1054       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "0 1"));
   1055   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1056                   0, TabStripModel::CommandTogglePinned));
   1057   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1058                   1, TabStripModel::CommandTogglePinned));
   1059   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1060                   2, TabStripModel::CommandTogglePinned));
   1061   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned);
   1062   EXPECT_EQ("0p 1p 2", GetPinnedState(tabstrip));
   1063 
   1064   // Execute CommandTogglePinned again, this should unpin.
   1065   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned);
   1066   EXPECT_EQ("0 1 2", GetPinnedState(tabstrip));
   1067 
   1068   // Pin the last.
   1069   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandTogglePinned);
   1070   EXPECT_EQ("2p 0 1", GetPinnedState(tabstrip));
   1071 
   1072   tabstrip.CloseAllTabs();
   1073   EXPECT_TRUE(tabstrip.empty());
   1074 }
   1075 
   1076 // Tests the following context menu commands:
   1077 //  - Close Tab
   1078 //  - Close Other Tabs
   1079 //  - Close Tabs To Right
   1080 TEST_F(TabStripModelTest, TestContextMenuCloseCommands) {
   1081   TabStripDummyDelegate delegate(NULL);
   1082   TabStripModel tabstrip(&delegate, profile());
   1083   EXPECT_TRUE(tabstrip.empty());
   1084 
   1085   TabContentsWrapper* opener_contents = CreateTabContents();
   1086   tabstrip.AppendTabContents(opener_contents, true);
   1087 
   1088   TabContentsWrapper* contents1 = CreateTabContents();
   1089   TabContentsWrapper* contents2 = CreateTabContents();
   1090   TabContentsWrapper* contents3 = CreateTabContents();
   1091 
   1092   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
   1093   EXPECT_EQ(0, tabstrip.active_index());
   1094 
   1095   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab);
   1096   EXPECT_EQ(3, tabstrip.count());
   1097 
   1098   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight);
   1099   EXPECT_EQ(1, tabstrip.count());
   1100   EXPECT_EQ(opener_contents, tabstrip.GetSelectedTabContents());
   1101 
   1102   TabContentsWrapper* dummy_contents = CreateTabContents();
   1103   tabstrip.AppendTabContents(dummy_contents, false);
   1104 
   1105   contents1 = CreateTabContents();
   1106   contents2 = CreateTabContents();
   1107   contents3 = CreateTabContents();
   1108   InsertTabContentses(&tabstrip, contents1, contents2, contents3);
   1109   EXPECT_EQ(5, tabstrip.count());
   1110 
   1111   int dummy_index = tabstrip.count() - 1;
   1112   tabstrip.ActivateTabAt(dummy_index, true);
   1113   EXPECT_EQ(dummy_contents, tabstrip.GetSelectedTabContents());
   1114 
   1115   tabstrip.ExecuteContextMenuCommand(dummy_index,
   1116                                      TabStripModel::CommandCloseOtherTabs);
   1117   EXPECT_EQ(1, tabstrip.count());
   1118   EXPECT_EQ(dummy_contents, tabstrip.GetSelectedTabContents());
   1119 
   1120   tabstrip.CloseAllTabs();
   1121   EXPECT_TRUE(tabstrip.empty());
   1122 }
   1123 
   1124 // Tests GetIndicesClosedByCommand.
   1125 TEST_F(TabStripModelTest, GetIndicesClosedByCommand) {
   1126   TabStripDummyDelegate delegate(NULL);
   1127   TabStripModel tabstrip(&delegate, profile());
   1128   EXPECT_TRUE(tabstrip.empty());
   1129 
   1130   TabContentsWrapper* contents1 = CreateTabContents();
   1131   TabContentsWrapper* contents2 = CreateTabContents();
   1132   TabContentsWrapper* contents3 = CreateTabContents();
   1133   TabContentsWrapper* contents4 = CreateTabContents();
   1134   TabContentsWrapper* contents5 = CreateTabContents();
   1135 
   1136   tabstrip.AppendTabContents(contents1, true);
   1137   tabstrip.AppendTabContents(contents2, true);
   1138   tabstrip.AppendTabContents(contents3, true);
   1139   tabstrip.AppendTabContents(contents4, true);
   1140   tabstrip.AppendTabContents(contents5, true);
   1141 
   1142   EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
   1143                 tabstrip, 0, TabStripModel::CommandCloseTabsToRight));
   1144   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1145                 tabstrip, 1, TabStripModel::CommandCloseTabsToRight));
   1146 
   1147   EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
   1148                 tabstrip, 0, TabStripModel::CommandCloseOtherTabs));
   1149   EXPECT_EQ("4 3 2 0", GetIndicesClosedByCommandAsString(
   1150                 tabstrip, 1, TabStripModel::CommandCloseOtherTabs));
   1151 
   1152   // Pin the first two tabs. Pinned tabs shouldn't be closed by the close other
   1153   // commands.
   1154   tabstrip.SetTabPinned(0, true);
   1155   tabstrip.SetTabPinned(1, true);
   1156 
   1157   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1158                 tabstrip, 0, TabStripModel::CommandCloseTabsToRight));
   1159   EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
   1160                 tabstrip, 2, TabStripModel::CommandCloseTabsToRight));
   1161 
   1162   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1163                 tabstrip, 0, TabStripModel::CommandCloseOtherTabs));
   1164   EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
   1165                 tabstrip, 2, TabStripModel::CommandCloseOtherTabs));
   1166 
   1167   tabstrip.CloseAllTabs();
   1168   EXPECT_TRUE(tabstrip.empty());
   1169 }
   1170 
   1171 // Tests whether or not TabContentses are inserted in the correct position
   1172 // using this "smart" function with a simulated middle click action on a series
   1173 // of links on the home page.
   1174 TEST_F(TabStripModelTest, AddTabContents_MiddleClickLinksAndClose) {
   1175   TabStripDummyDelegate delegate(NULL);
   1176   TabStripModel tabstrip(&delegate, profile());
   1177   EXPECT_TRUE(tabstrip.empty());
   1178 
   1179   // Open the Home Page
   1180   TabContentsWrapper* homepage_contents = CreateTabContents();
   1181   tabstrip.AddTabContents(
   1182       homepage_contents, -1, PageTransition::AUTO_BOOKMARK,
   1183       TabStripModel::ADD_ACTIVE);
   1184 
   1185   // Open some other tab, by user typing.
   1186   TabContentsWrapper* typed_page_contents = CreateTabContents();
   1187   tabstrip.AddTabContents(
   1188       typed_page_contents, -1, PageTransition::TYPED,
   1189       TabStripModel::ADD_ACTIVE);
   1190 
   1191   EXPECT_EQ(2, tabstrip.count());
   1192 
   1193   // Re-select the home page.
   1194   tabstrip.ActivateTabAt(0, true);
   1195 
   1196   // Open a bunch of tabs by simulating middle clicking on links on the home
   1197   // page.
   1198   TabContentsWrapper* middle_click_contents1 = CreateTabContents();
   1199   tabstrip.AddTabContents(
   1200       middle_click_contents1, -1, PageTransition::LINK,
   1201       TabStripModel::ADD_NONE);
   1202   TabContentsWrapper* middle_click_contents2 = CreateTabContents();
   1203   tabstrip.AddTabContents(
   1204       middle_click_contents2, -1, PageTransition::LINK,
   1205       TabStripModel::ADD_NONE);
   1206   TabContentsWrapper* middle_click_contents3 = CreateTabContents();
   1207   tabstrip.AddTabContents(
   1208       middle_click_contents3, -1, PageTransition::LINK,
   1209       TabStripModel::ADD_NONE);
   1210 
   1211   EXPECT_EQ(5, tabstrip.count());
   1212 
   1213   EXPECT_EQ(homepage_contents, tabstrip.GetTabContentsAt(0));
   1214   EXPECT_EQ(middle_click_contents1, tabstrip.GetTabContentsAt(1));
   1215   EXPECT_EQ(middle_click_contents2, tabstrip.GetTabContentsAt(2));
   1216   EXPECT_EQ(middle_click_contents3, tabstrip.GetTabContentsAt(3));
   1217   EXPECT_EQ(typed_page_contents, tabstrip.GetTabContentsAt(4));
   1218 
   1219   // Now simulate seleting a tab in the middle of the group of tabs opened from
   1220   // the home page and start closing them. Each TabContents in the group should
   1221   // be closed, right to left. This test is constructed to start at the middle
   1222   // TabContents in the group to make sure the cursor wraps around to the first
   1223   // TabContents in the group before closing the opener or any other
   1224   // TabContents.
   1225   tabstrip.ActivateTabAt(2, true);
   1226   tabstrip.CloseSelectedTabs();
   1227   EXPECT_EQ(middle_click_contents3, tabstrip.GetSelectedTabContents());
   1228   tabstrip.CloseSelectedTabs();
   1229   EXPECT_EQ(middle_click_contents1, tabstrip.GetSelectedTabContents());
   1230   tabstrip.CloseSelectedTabs();
   1231   EXPECT_EQ(homepage_contents, tabstrip.GetSelectedTabContents());
   1232   tabstrip.CloseSelectedTabs();
   1233   EXPECT_EQ(typed_page_contents, tabstrip.GetSelectedTabContents());
   1234 
   1235   EXPECT_EQ(1, tabstrip.count());
   1236 
   1237   tabstrip.CloseAllTabs();
   1238   EXPECT_TRUE(tabstrip.empty());
   1239 }
   1240 
   1241 // Tests whether or not a TabContents created by a left click on a link that
   1242 // opens a new tab is inserted correctly adjacent to the tab that spawned it.
   1243 TEST_F(TabStripModelTest, AddTabContents_LeftClickPopup) {
   1244   TabStripDummyDelegate delegate(NULL);
   1245   TabStripModel tabstrip(&delegate, profile());
   1246   EXPECT_TRUE(tabstrip.empty());
   1247 
   1248   // Open the Home Page
   1249   TabContentsWrapper* homepage_contents = CreateTabContents();
   1250   tabstrip.AddTabContents(
   1251       homepage_contents, -1, PageTransition::AUTO_BOOKMARK,
   1252       TabStripModel::ADD_ACTIVE);
   1253 
   1254   // Open some other tab, by user typing.
   1255   TabContentsWrapper* typed_page_contents = CreateTabContents();
   1256   tabstrip.AddTabContents(
   1257       typed_page_contents, -1, PageTransition::TYPED,
   1258       TabStripModel::ADD_ACTIVE);
   1259 
   1260   EXPECT_EQ(2, tabstrip.count());
   1261 
   1262   // Re-select the home page.
   1263   tabstrip.ActivateTabAt(0, true);
   1264 
   1265   // Open a tab by simulating a left click on a link that opens in a new tab.
   1266   TabContentsWrapper* left_click_contents = CreateTabContents();
   1267   tabstrip.AddTabContents(left_click_contents, -1, PageTransition::LINK,
   1268                           TabStripModel::ADD_ACTIVE);
   1269 
   1270   // Verify the state meets our expectations.
   1271   EXPECT_EQ(3, tabstrip.count());
   1272   EXPECT_EQ(homepage_contents, tabstrip.GetTabContentsAt(0));
   1273   EXPECT_EQ(left_click_contents, tabstrip.GetTabContentsAt(1));
   1274   EXPECT_EQ(typed_page_contents, tabstrip.GetTabContentsAt(2));
   1275 
   1276   // The newly created tab should be selected.
   1277   EXPECT_EQ(left_click_contents, tabstrip.GetSelectedTabContents());
   1278 
   1279   // After closing the selected tab, the selection should move to the left, to
   1280   // the opener.
   1281   tabstrip.CloseSelectedTabs();
   1282   EXPECT_EQ(homepage_contents, tabstrip.GetSelectedTabContents());
   1283 
   1284   EXPECT_EQ(2, tabstrip.count());
   1285 
   1286   tabstrip.CloseAllTabs();
   1287   EXPECT_TRUE(tabstrip.empty());
   1288 }
   1289 
   1290 // Tests whether or not new tabs that should split context (typed pages,
   1291 // generated urls, also blank tabs) open at the end of the tabstrip instead of
   1292 // in the middle.
   1293 TEST_F(TabStripModelTest, AddTabContents_CreateNewBlankTab) {
   1294   TabStripDummyDelegate delegate(NULL);
   1295   TabStripModel tabstrip(&delegate, profile());
   1296   EXPECT_TRUE(tabstrip.empty());
   1297 
   1298   // Open the Home Page
   1299   TabContentsWrapper* homepage_contents = CreateTabContents();
   1300   tabstrip.AddTabContents(
   1301       homepage_contents, -1, PageTransition::AUTO_BOOKMARK,
   1302       TabStripModel::ADD_ACTIVE);
   1303 
   1304   // Open some other tab, by user typing.
   1305   TabContentsWrapper* typed_page_contents = CreateTabContents();
   1306   tabstrip.AddTabContents(
   1307       typed_page_contents, -1, PageTransition::TYPED,
   1308       TabStripModel::ADD_ACTIVE);
   1309 
   1310   EXPECT_EQ(2, tabstrip.count());
   1311 
   1312   // Re-select the home page.
   1313   tabstrip.ActivateTabAt(0, true);
   1314 
   1315   // Open a new blank tab in the foreground.
   1316   TabContentsWrapper* new_blank_contents = CreateTabContents();
   1317   tabstrip.AddTabContents(new_blank_contents, -1, PageTransition::TYPED,
   1318                           TabStripModel::ADD_ACTIVE);
   1319 
   1320   // Verify the state of the tabstrip.
   1321   EXPECT_EQ(3, tabstrip.count());
   1322   EXPECT_EQ(homepage_contents, tabstrip.GetTabContentsAt(0));
   1323   EXPECT_EQ(typed_page_contents, tabstrip.GetTabContentsAt(1));
   1324   EXPECT_EQ(new_blank_contents, tabstrip.GetTabContentsAt(2));
   1325 
   1326   // Now open a couple more blank tabs in the background.
   1327   TabContentsWrapper* background_blank_contents1 = CreateTabContents();
   1328   tabstrip.AddTabContents(
   1329       background_blank_contents1, -1, PageTransition::TYPED,
   1330       TabStripModel::ADD_NONE);
   1331   TabContentsWrapper* background_blank_contents2 = CreateTabContents();
   1332   tabstrip.AddTabContents(
   1333       background_blank_contents2, -1, PageTransition::GENERATED,
   1334       TabStripModel::ADD_NONE);
   1335   EXPECT_EQ(5, tabstrip.count());
   1336   EXPECT_EQ(homepage_contents, tabstrip.GetTabContentsAt(0));
   1337   EXPECT_EQ(typed_page_contents, tabstrip.GetTabContentsAt(1));
   1338   EXPECT_EQ(new_blank_contents, tabstrip.GetTabContentsAt(2));
   1339   EXPECT_EQ(background_blank_contents1, tabstrip.GetTabContentsAt(3));
   1340   EXPECT_EQ(background_blank_contents2, tabstrip.GetTabContentsAt(4));
   1341 
   1342   tabstrip.CloseAllTabs();
   1343   EXPECT_TRUE(tabstrip.empty());
   1344 }
   1345 
   1346 // Tests whether opener state is correctly forgotten when the user switches
   1347 // context.
   1348 TEST_F(TabStripModelTest, AddTabContents_ForgetOpeners) {
   1349   TabStripDummyDelegate delegate(NULL);
   1350   TabStripModel tabstrip(&delegate, profile());
   1351   EXPECT_TRUE(tabstrip.empty());
   1352 
   1353   // Open the Home Page
   1354   TabContentsWrapper* homepage_contents = CreateTabContents();
   1355   tabstrip.AddTabContents(
   1356       homepage_contents, -1, PageTransition::AUTO_BOOKMARK,
   1357       TabStripModel::ADD_ACTIVE);
   1358 
   1359   // Open some other tab, by user typing.
   1360   TabContentsWrapper* typed_page_contents = CreateTabContents();
   1361   tabstrip.AddTabContents(
   1362       typed_page_contents, -1, PageTransition::TYPED,
   1363       TabStripModel::ADD_ACTIVE);
   1364 
   1365   EXPECT_EQ(2, tabstrip.count());
   1366 
   1367   // Re-select the home page.
   1368   tabstrip.ActivateTabAt(0, true);
   1369 
   1370   // Open a bunch of tabs by simulating middle clicking on links on the home
   1371   // page.
   1372   TabContentsWrapper* middle_click_contents1 = CreateTabContents();
   1373   tabstrip.AddTabContents(
   1374       middle_click_contents1, -1, PageTransition::LINK,
   1375       TabStripModel::ADD_NONE);
   1376   TabContentsWrapper* middle_click_contents2 = CreateTabContents();
   1377   tabstrip.AddTabContents(
   1378       middle_click_contents2, -1, PageTransition::LINK,
   1379       TabStripModel::ADD_NONE);
   1380   TabContentsWrapper* middle_click_contents3 = CreateTabContents();
   1381   tabstrip.AddTabContents(
   1382       middle_click_contents3, -1, PageTransition::LINK,
   1383       TabStripModel::ADD_NONE);
   1384 
   1385   // Break out of the context by selecting a tab in a different context.
   1386   EXPECT_EQ(typed_page_contents, tabstrip.GetTabContentsAt(4));
   1387   tabstrip.SelectLastTab();
   1388   EXPECT_EQ(typed_page_contents, tabstrip.GetSelectedTabContents());
   1389 
   1390   // Step back into the context by selecting a tab inside it.
   1391   tabstrip.ActivateTabAt(2, true);
   1392   EXPECT_EQ(middle_click_contents2, tabstrip.GetSelectedTabContents());
   1393 
   1394   // Now test that closing tabs selects to the right until there are no more,
   1395   // then to the left, as if there were no context (context has been
   1396   // successfully forgotten).
   1397   tabstrip.CloseSelectedTabs();
   1398   EXPECT_EQ(middle_click_contents3, tabstrip.GetSelectedTabContents());
   1399   tabstrip.CloseSelectedTabs();
   1400   EXPECT_EQ(typed_page_contents, tabstrip.GetSelectedTabContents());
   1401   tabstrip.CloseSelectedTabs();
   1402   EXPECT_EQ(middle_click_contents1, tabstrip.GetSelectedTabContents());
   1403   tabstrip.CloseSelectedTabs();
   1404   EXPECT_EQ(homepage_contents, tabstrip.GetSelectedTabContents());
   1405 
   1406   EXPECT_EQ(1, tabstrip.count());
   1407 
   1408   tabstrip.CloseAllTabs();
   1409   EXPECT_TRUE(tabstrip.empty());
   1410 }
   1411 
   1412 // Added for http://b/issue?id=958960
   1413 TEST_F(TabStripModelTest, AppendContentsReselectionTest) {
   1414   TabContents* fake_destinations_tab =
   1415       new TabContents(profile(), NULL, 0, NULL, NULL);
   1416   TabContentsWrapper wrapper(fake_destinations_tab);
   1417   TabStripDummyDelegate delegate(&wrapper);
   1418   TabStripModel tabstrip(&delegate, profile());
   1419   EXPECT_TRUE(tabstrip.empty());
   1420 
   1421   // Open the Home Page
   1422   TabContentsWrapper* homepage_contents = CreateTabContents();
   1423   tabstrip.AddTabContents(
   1424       homepage_contents, -1, PageTransition::AUTO_BOOKMARK,
   1425       TabStripModel::ADD_ACTIVE);
   1426 
   1427   // Open some other tab, by user typing.
   1428   TabContentsWrapper* typed_page_contents = CreateTabContents();
   1429   tabstrip.AddTabContents(
   1430       typed_page_contents, -1, PageTransition::TYPED,
   1431       TabStripModel::ADD_NONE);
   1432 
   1433   // The selected tab should still be the first.
   1434   EXPECT_EQ(0, tabstrip.active_index());
   1435 
   1436   // Now simulate a link click that opens a new tab (by virtue of target=_blank)
   1437   // and make sure the right tab gets selected when the new tab is closed.
   1438   TabContentsWrapper* target_blank_contents = CreateTabContents();
   1439   tabstrip.AppendTabContents(target_blank_contents, true);
   1440   EXPECT_EQ(2, tabstrip.active_index());
   1441   tabstrip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE);
   1442   EXPECT_EQ(0, tabstrip.active_index());
   1443 
   1444   // clean up after ourselves
   1445   tabstrip.CloseAllTabs();
   1446 }
   1447 
   1448 // Added for http://b/issue?id=1027661
   1449 TEST_F(TabStripModelTest, ReselectionConsidersChildrenTest) {
   1450   TabStripDummyDelegate delegate(NULL);
   1451   TabStripModel strip(&delegate, profile());
   1452 
   1453   // Open page A
   1454   TabContentsWrapper* page_a_contents = CreateTabContents();
   1455   strip.AddTabContents(
   1456       page_a_contents, -1, PageTransition::AUTO_BOOKMARK,
   1457       TabStripModel::ADD_ACTIVE);
   1458 
   1459   // Simulate middle click to open page A.A and A.B
   1460   TabContentsWrapper* page_a_a_contents = CreateTabContents();
   1461   strip.AddTabContents(page_a_a_contents, -1, PageTransition::LINK,
   1462                        TabStripModel::ADD_NONE);
   1463   TabContentsWrapper* page_a_b_contents = CreateTabContents();
   1464   strip.AddTabContents(page_a_b_contents, -1, PageTransition::LINK,
   1465                        TabStripModel::ADD_NONE);
   1466 
   1467   // Select page A.A
   1468   strip.ActivateTabAt(1, true);
   1469   EXPECT_EQ(page_a_a_contents, strip.GetSelectedTabContents());
   1470 
   1471   // Simulate a middle click to open page A.A.A
   1472   TabContentsWrapper* page_a_a_a_contents = CreateTabContents();
   1473   strip.AddTabContents(page_a_a_a_contents, -1, PageTransition::LINK,
   1474                        TabStripModel::ADD_NONE);
   1475 
   1476   EXPECT_EQ(page_a_a_a_contents, strip.GetTabContentsAt(2));
   1477 
   1478   // Close page A.A
   1479   strip.CloseTabContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1480 
   1481   // Page A.A.A should be selected, NOT A.B
   1482   EXPECT_EQ(page_a_a_a_contents, strip.GetSelectedTabContents());
   1483 
   1484   // Close page A.A.A
   1485   strip.CloseTabContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1486 
   1487   // Page A.B should be selected
   1488   EXPECT_EQ(page_a_b_contents, strip.GetSelectedTabContents());
   1489 
   1490   // Close page A.B
   1491   strip.CloseTabContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1492 
   1493   // Page A should be selected
   1494   EXPECT_EQ(page_a_contents, strip.GetSelectedTabContents());
   1495 
   1496   // Clean up.
   1497   strip.CloseAllTabs();
   1498 }
   1499 
   1500 TEST_F(TabStripModelTest, AddTabContents_NewTabAtEndOfStripInheritsGroup) {
   1501   TabStripDummyDelegate delegate(NULL);
   1502   TabStripModel strip(&delegate, profile());
   1503 
   1504   // Open page A
   1505   TabContentsWrapper* page_a_contents = CreateTabContents();
   1506   strip.AddTabContents(page_a_contents, -1, PageTransition::START_PAGE,
   1507                        TabStripModel::ADD_ACTIVE);
   1508 
   1509   // Open pages B, C and D in the background from links on page A...
   1510   TabContentsWrapper* page_b_contents = CreateTabContents();
   1511   TabContentsWrapper* page_c_contents = CreateTabContents();
   1512   TabContentsWrapper* page_d_contents = CreateTabContents();
   1513   strip.AddTabContents(page_b_contents, -1, PageTransition::LINK,
   1514                        TabStripModel::ADD_NONE);
   1515   strip.AddTabContents(page_c_contents, -1, PageTransition::LINK,
   1516                        TabStripModel::ADD_NONE);
   1517   strip.AddTabContents(page_d_contents, -1, PageTransition::LINK,
   1518                        TabStripModel::ADD_NONE);
   1519 
   1520   // Switch to page B's tab.
   1521   strip.ActivateTabAt(1, true);
   1522 
   1523   // Open a New Tab at the end of the strip (simulate Ctrl+T)
   1524   TabContentsWrapper* new_tab_contents = CreateTabContents();
   1525   strip.AddTabContents(new_tab_contents, -1, PageTransition::TYPED,
   1526                        TabStripModel::ADD_ACTIVE);
   1527 
   1528   EXPECT_EQ(4, strip.GetIndexOfTabContents(new_tab_contents));
   1529   EXPECT_EQ(4, strip.active_index());
   1530 
   1531   // Close the New Tab that was just opened. We should be returned to page B's
   1532   // Tab...
   1533   strip.CloseTabContentsAt(4, TabStripModel::CLOSE_NONE);
   1534 
   1535   EXPECT_EQ(1, strip.active_index());
   1536 
   1537   // Open a non-New Tab tab at the end of the strip, with a TYPED transition.
   1538   // This is like typing a URL in the address bar and pressing Alt+Enter. The
   1539   // behavior should be the same as above.
   1540   TabContentsWrapper* page_e_contents = CreateTabContents();
   1541   strip.AddTabContents(page_e_contents, -1, PageTransition::TYPED,
   1542                        TabStripModel::ADD_ACTIVE);
   1543 
   1544   EXPECT_EQ(4, strip.GetIndexOfTabContents(page_e_contents));
   1545   EXPECT_EQ(4, strip.active_index());
   1546 
   1547   // Close the Tab. Selection should shift back to page B's Tab.
   1548   strip.CloseTabContentsAt(4, TabStripModel::CLOSE_NONE);
   1549 
   1550   EXPECT_EQ(1, strip.active_index());
   1551 
   1552   // Open a non-New Tab tab at the end of the strip, with some other
   1553   // transition. This is like right clicking on a bookmark and choosing "Open
   1554   // in New Tab". No opener relationship should be preserved between this Tab
   1555   // and the one that was active when the gesture was performed.
   1556   TabContentsWrapper* page_f_contents = CreateTabContents();
   1557   strip.AddTabContents(page_f_contents, -1, PageTransition::AUTO_BOOKMARK,
   1558                        TabStripModel::ADD_ACTIVE);
   1559 
   1560   EXPECT_EQ(4, strip.GetIndexOfTabContents(page_f_contents));
   1561   EXPECT_EQ(4, strip.active_index());
   1562 
   1563   // Close the Tab. The next-adjacent should be selected.
   1564   strip.CloseTabContentsAt(4, TabStripModel::CLOSE_NONE);
   1565 
   1566   EXPECT_EQ(3, strip.active_index());
   1567 
   1568   // Clean up.
   1569   strip.CloseAllTabs();
   1570 }
   1571 
   1572 // A test of navigations in a tab that is part of a group of opened from some
   1573 // parent tab. If the navigations are link clicks, the group relationship of
   1574 // the tab to its parent are preserved. If they are of any other type, they are
   1575 // not preserved.
   1576 TEST_F(TabStripModelTest, NavigationForgetsOpeners) {
   1577   TabStripDummyDelegate delegate(NULL);
   1578   TabStripModel strip(&delegate, profile());
   1579 
   1580   // Open page A
   1581   TabContentsWrapper* page_a_contents = CreateTabContents();
   1582   strip.AddTabContents(page_a_contents, -1, PageTransition::START_PAGE,
   1583                        TabStripModel::ADD_ACTIVE);
   1584 
   1585   // Open pages B, C and D in the background from links on page A...
   1586   TabContentsWrapper* page_b_contents = CreateTabContents();
   1587   TabContentsWrapper* page_c_contents = CreateTabContents();
   1588   TabContentsWrapper* page_d_contents = CreateTabContents();
   1589   strip.AddTabContents(page_b_contents, -1, PageTransition::LINK,
   1590                        TabStripModel::ADD_NONE);
   1591   strip.AddTabContents(page_c_contents, -1, PageTransition::LINK,
   1592                        TabStripModel::ADD_NONE);
   1593   strip.AddTabContents(page_d_contents, -1, PageTransition::LINK,
   1594                        TabStripModel::ADD_NONE);
   1595 
   1596   // Open page E in a different opener group from page A.
   1597   TabContentsWrapper* page_e_contents = CreateTabContents();
   1598   strip.AddTabContents(page_e_contents, -1, PageTransition::START_PAGE,
   1599                        TabStripModel::ADD_NONE);
   1600 
   1601   // Tell the TabStripModel that we are navigating page D via a link click.
   1602   strip.ActivateTabAt(3, true);
   1603   strip.TabNavigating(page_d_contents, PageTransition::LINK);
   1604 
   1605   // Close page D, page C should be selected. (part of same group).
   1606   strip.CloseTabContentsAt(3, TabStripModel::CLOSE_NONE);
   1607   EXPECT_EQ(2, strip.active_index());
   1608 
   1609   // Tell the TabStripModel that we are navigating in page C via a bookmark.
   1610   strip.TabNavigating(page_c_contents, PageTransition::AUTO_BOOKMARK);
   1611 
   1612   // Close page C, page E should be selected. (C is no longer part of the
   1613   // A-B-C-D group, selection moves to the right).
   1614   strip.CloseTabContentsAt(2, TabStripModel::CLOSE_NONE);
   1615   EXPECT_EQ(page_e_contents, strip.GetTabContentsAt(strip.active_index()));
   1616 
   1617   strip.CloseAllTabs();
   1618 }
   1619 
   1620 // A test that the forgetting behavior tested in NavigationForgetsOpeners above
   1621 // doesn't cause the opener relationship for a New Tab opened at the end of the
   1622 // TabStrip to be reset (Test 1 below), unless another any other tab is
   1623 // seelcted (Test 2 below).
   1624 TEST_F(TabStripModelTest, NavigationForgettingDoesntAffectNewTab) {
   1625   TabStripDummyDelegate delegate(NULL);
   1626   TabStripModel strip(&delegate, profile());
   1627 
   1628   // Open a tab and several tabs from it, then select one of the tabs that was
   1629   // opened.
   1630   TabContentsWrapper* page_a_contents = CreateTabContents();
   1631   strip.AddTabContents(page_a_contents, -1, PageTransition::START_PAGE,
   1632                        TabStripModel::ADD_ACTIVE);
   1633 
   1634   TabContentsWrapper* page_b_contents = CreateTabContents();
   1635   TabContentsWrapper* page_c_contents = CreateTabContents();
   1636   TabContentsWrapper* page_d_contents = CreateTabContents();
   1637   strip.AddTabContents(page_b_contents, -1, PageTransition::LINK,
   1638                        TabStripModel::ADD_NONE);
   1639   strip.AddTabContents(page_c_contents, -1, PageTransition::LINK,
   1640                        TabStripModel::ADD_NONE);
   1641   strip.AddTabContents(page_d_contents, -1, PageTransition::LINK,
   1642                        TabStripModel::ADD_NONE);
   1643 
   1644   strip.ActivateTabAt(2, true);
   1645 
   1646   // TEST 1: If the user is in a group of tabs and opens a new tab at the end
   1647   // of the strip, closing that new tab will select the tab that they were
   1648   // last on.
   1649 
   1650   // Now simulate opening a new tab at the end of the TabStrip.
   1651   TabContentsWrapper* new_tab_contents1 = CreateTabContents();
   1652   strip.AddTabContents(new_tab_contents1, -1, PageTransition::TYPED,
   1653                        TabStripModel::ADD_ACTIVE);
   1654 
   1655   // At this point, if we close this tab the last selected one should be
   1656   // re-selected.
   1657   strip.CloseTabContentsAt(strip.count() - 1, TabStripModel::CLOSE_NONE);
   1658   EXPECT_EQ(page_c_contents, strip.GetTabContentsAt(strip.active_index()));
   1659 
   1660   // TEST 2: If the user is in a group of tabs and opens a new tab at the end
   1661   // of the strip, selecting any other tab in the strip will cause that new
   1662   // tab's opener relationship to be forgotten.
   1663 
   1664   // Open a new tab again.
   1665   TabContentsWrapper* new_tab_contents2 = CreateTabContents();
   1666   strip.AddTabContents(new_tab_contents2, -1, PageTransition::TYPED,
   1667                        TabStripModel::ADD_ACTIVE);
   1668 
   1669   // Now select the first tab.
   1670   strip.ActivateTabAt(0, true);
   1671 
   1672   // Now select the last tab.
   1673   strip.ActivateTabAt(strip.count() - 1, true);
   1674 
   1675   // Now close the last tab. The next adjacent should be selected.
   1676   strip.CloseTabContentsAt(strip.count() - 1, TabStripModel::CLOSE_NONE);
   1677   EXPECT_EQ(page_d_contents, strip.GetTabContentsAt(strip.active_index()));
   1678 
   1679   strip.CloseAllTabs();
   1680 }
   1681 
   1682 // Tests that fast shutdown is attempted appropriately.
   1683 TEST_F(TabStripModelTest, FastShutdown) {
   1684   TabStripDummyDelegate delegate(NULL);
   1685   TabStripModel tabstrip(&delegate, profile());
   1686   MockTabStripModelObserver observer;
   1687   tabstrip.AddObserver(&observer);
   1688 
   1689   EXPECT_TRUE(tabstrip.empty());
   1690 
   1691   // Make sure fast shutdown is attempted when tabs that share a RPH are shut
   1692   // down.
   1693   {
   1694     TabContentsWrapper* contents1 = CreateTabContents();
   1695     TabContentsWrapper* contents2 =
   1696         CreateTabContentsWithSharedRPH(contents1->tab_contents());
   1697 
   1698     SetID(contents1->tab_contents(), 1);
   1699     SetID(contents2->tab_contents(), 2);
   1700 
   1701     tabstrip.AppendTabContents(contents1, true);
   1702     tabstrip.AppendTabContents(contents2, true);
   1703 
   1704     // Turn on the fake unload listener so the tabs don't actually get shut
   1705     // down when we call CloseAllTabs()---we need to be able to check that
   1706     // fast shutdown was attempted.
   1707     delegate.set_run_unload_listener(true);
   1708     tabstrip.CloseAllTabs();
   1709     // On a mock RPH this checks whether we *attempted* fast shutdown.
   1710     // A real RPH would reject our attempt since there is an unload handler.
   1711     EXPECT_TRUE(contents1->tab_contents()->
   1712         GetRenderProcessHost()->fast_shutdown_started());
   1713     EXPECT_EQ(2, tabstrip.count());
   1714 
   1715     delegate.set_run_unload_listener(false);
   1716     tabstrip.CloseAllTabs();
   1717     EXPECT_TRUE(tabstrip.empty());
   1718   }
   1719 
   1720   // Make sure fast shutdown is not attempted when only some tabs that share a
   1721   // RPH are shut down.
   1722   {
   1723     TabContentsWrapper* contents1 = CreateTabContents();
   1724     TabContentsWrapper* contents2 =
   1725         CreateTabContentsWithSharedRPH(contents1->tab_contents());
   1726 
   1727     SetID(contents1->tab_contents(), 1);
   1728     SetID(contents2->tab_contents(), 2);
   1729 
   1730     tabstrip.AppendTabContents(contents1, true);
   1731     tabstrip.AppendTabContents(contents2, true);
   1732 
   1733     tabstrip.CloseTabContentsAt(1, TabStripModel::CLOSE_NONE);
   1734     EXPECT_FALSE(contents1->tab_contents()->
   1735         GetRenderProcessHost()->fast_shutdown_started());
   1736     EXPECT_EQ(1, tabstrip.count());
   1737 
   1738     tabstrip.CloseAllTabs();
   1739     EXPECT_TRUE(tabstrip.empty());
   1740   }
   1741 }
   1742 
   1743 // Tests various permutations of apps.
   1744 TEST_F(TabStripModelTest, Apps) {
   1745   TabStripDummyDelegate delegate(NULL);
   1746   TabStripModel tabstrip(&delegate, profile());
   1747   MockTabStripModelObserver observer;
   1748   tabstrip.AddObserver(&observer);
   1749 
   1750   EXPECT_TRUE(tabstrip.empty());
   1751 
   1752   typedef MockTabStripModelObserver::State State;
   1753 
   1754 #if defined(OS_WIN)
   1755   FilePath path(FILE_PATH_LITERAL("c:\\foo"));
   1756 #elif defined(OS_POSIX)
   1757   FilePath path(FILE_PATH_LITERAL("/foo"));
   1758 #endif
   1759   scoped_refptr<Extension> extension_app(new Extension(path,
   1760                                                        Extension::INVALID));
   1761   extension_app->launch_web_url_ = "http://www.google.com";
   1762   TabContentsWrapper* contents1 = CreateTabContents();
   1763   contents1->extension_tab_helper()->SetExtensionApp(extension_app);
   1764   TabContentsWrapper* contents2 = CreateTabContents();
   1765   contents2->extension_tab_helper()->SetExtensionApp(extension_app);
   1766   TabContentsWrapper* contents3 = CreateTabContents();
   1767 
   1768   SetID(contents1->tab_contents(), 1);
   1769   SetID(contents2->tab_contents(), 2);
   1770   SetID(contents3->tab_contents(), 3);
   1771 
   1772   // Note! The ordering of these tests is important, each subsequent test
   1773   // builds on the state established in the previous. This is important if you
   1774   // ever insert tests rather than append.
   1775 
   1776   // Initial state, tab3 only and selected.
   1777   tabstrip.AppendTabContents(contents3, true);
   1778 
   1779   observer.ClearStates();
   1780 
   1781   // Attempt to insert tab1 (an app tab) at position 1. This isn't a legal
   1782   // position and tab1 should end up at position 0.
   1783   {
   1784     tabstrip.InsertTabContentsAt(1, contents1, TabStripModel::ADD_NONE);
   1785 
   1786     ASSERT_EQ(1, observer.GetStateCount());
   1787     State state(contents1, 0, MockTabStripModelObserver::INSERT);
   1788     EXPECT_TRUE(observer.StateEquals(0, state));
   1789 
   1790     // And verify the state.
   1791     EXPECT_EQ("1ap 3", GetPinnedState(tabstrip));
   1792 
   1793     observer.ClearStates();
   1794   }
   1795 
   1796   // Insert tab 2 at position 1.
   1797   {
   1798     tabstrip.InsertTabContentsAt(1, contents2, TabStripModel::ADD_NONE);
   1799 
   1800     ASSERT_EQ(1, observer.GetStateCount());
   1801     State state(contents2, 1, MockTabStripModelObserver::INSERT);
   1802     EXPECT_TRUE(observer.StateEquals(0, state));
   1803 
   1804     // And verify the state.
   1805     EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
   1806 
   1807     observer.ClearStates();
   1808   }
   1809 
   1810   // Try to move tab 3 to position 0. This isn't legal and should be ignored.
   1811   {
   1812     tabstrip.MoveTabContentsAt(2, 0, false);
   1813 
   1814     ASSERT_EQ(0, observer.GetStateCount());
   1815 
   1816     // And verify the state didn't change.
   1817     EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
   1818 
   1819     observer.ClearStates();
   1820   }
   1821 
   1822   // Try to move tab 0 to position 3. This isn't legal and should be ignored.
   1823   {
   1824     tabstrip.MoveTabContentsAt(0, 2, false);
   1825 
   1826     ASSERT_EQ(0, observer.GetStateCount());
   1827 
   1828     // And verify the state didn't change.
   1829     EXPECT_EQ("1ap 2ap 3", GetPinnedState(tabstrip));
   1830 
   1831     observer.ClearStates();
   1832   }
   1833 
   1834   // Try to move tab 0 to position 1. This is a legal move.
   1835   {
   1836     tabstrip.MoveTabContentsAt(0, 1, false);
   1837 
   1838     ASSERT_EQ(1, observer.GetStateCount());
   1839     State state(contents1, 1, MockTabStripModelObserver::MOVE);
   1840     state.src_index = 0;
   1841     EXPECT_TRUE(observer.StateEquals(0, state));
   1842 
   1843     // And verify the state didn't change.
   1844     EXPECT_EQ("2ap 1ap 3", GetPinnedState(tabstrip));
   1845 
   1846     observer.ClearStates();
   1847   }
   1848 
   1849   // Remove tab3 and insert at position 0. It should be forced to position 2.
   1850   {
   1851     tabstrip.DetachTabContentsAt(2);
   1852     observer.ClearStates();
   1853 
   1854     tabstrip.InsertTabContentsAt(0, contents3, TabStripModel::ADD_NONE);
   1855 
   1856     ASSERT_EQ(1, observer.GetStateCount());
   1857     State state(contents3, 2, MockTabStripModelObserver::INSERT);
   1858     EXPECT_TRUE(observer.StateEquals(0, state));
   1859 
   1860     // And verify the state didn't change.
   1861     EXPECT_EQ("2ap 1ap 3", GetPinnedState(tabstrip));
   1862 
   1863     observer.ClearStates();
   1864   }
   1865 
   1866   tabstrip.CloseAllTabs();
   1867 }
   1868 
   1869 // Tests various permutations of pinning tabs.
   1870 TEST_F(TabStripModelTest, Pinning) {
   1871   TabStripDummyDelegate delegate(NULL);
   1872   TabStripModel tabstrip(&delegate, profile());
   1873   MockTabStripModelObserver observer;
   1874   tabstrip.AddObserver(&observer);
   1875 
   1876   EXPECT_TRUE(tabstrip.empty());
   1877 
   1878   typedef MockTabStripModelObserver::State State;
   1879 
   1880   TabContentsWrapper* contents1 = CreateTabContents();
   1881   TabContentsWrapper* contents2 = CreateTabContents();
   1882   TabContentsWrapper* contents3 = CreateTabContents();
   1883 
   1884   SetID(contents1->tab_contents(), 1);
   1885   SetID(contents2->tab_contents(), 2);
   1886   SetID(contents3->tab_contents(), 3);
   1887 
   1888   // Note! The ordering of these tests is important, each subsequent test
   1889   // builds on the state established in the previous. This is important if you
   1890   // ever insert tests rather than append.
   1891 
   1892   // Initial state, three tabs, first selected.
   1893   tabstrip.AppendTabContents(contents1, true);
   1894   tabstrip.AppendTabContents(contents2, false);
   1895   tabstrip.AppendTabContents(contents3, false);
   1896 
   1897   observer.ClearStates();
   1898 
   1899   // Pin the first tab, this shouldn't visually reorder anything.
   1900   {
   1901     tabstrip.SetTabPinned(0, true);
   1902 
   1903     // As the order didn't change, we should get a pinned notification.
   1904     ASSERT_EQ(1, observer.GetStateCount());
   1905     State state(contents1, 0, MockTabStripModelObserver::PINNED);
   1906     EXPECT_TRUE(observer.StateEquals(0, state));
   1907 
   1908     // And verify the state.
   1909     EXPECT_EQ("1p 2 3", GetPinnedState(tabstrip));
   1910 
   1911     observer.ClearStates();
   1912   }
   1913 
   1914   // Unpin the first tab.
   1915   {
   1916     tabstrip.SetTabPinned(0, false);
   1917 
   1918     // As the order didn't change, we should get a pinned notification.
   1919     ASSERT_EQ(1, observer.GetStateCount());
   1920     State state(contents1, 0, MockTabStripModelObserver::PINNED);
   1921     EXPECT_TRUE(observer.StateEquals(0, state));
   1922 
   1923     // And verify the state.
   1924     EXPECT_EQ("1 2 3", GetPinnedState(tabstrip));
   1925 
   1926     observer.ClearStates();
   1927   }
   1928 
   1929   // Pin the 3rd tab, which should move it to the front.
   1930   {
   1931     tabstrip.SetTabPinned(2, true);
   1932 
   1933     // The pinning should have resulted in a move and a pinned notification.
   1934     ASSERT_EQ(2, observer.GetStateCount());
   1935     State state(contents3, 0, MockTabStripModelObserver::MOVE);
   1936     state.src_index = 2;
   1937     EXPECT_TRUE(observer.StateEquals(0, state));
   1938 
   1939     state = State(contents3, 0, MockTabStripModelObserver::PINNED);
   1940     EXPECT_TRUE(observer.StateEquals(1, state));
   1941 
   1942     // And verify the state.
   1943     EXPECT_EQ("3p 1 2", GetPinnedState(tabstrip));
   1944 
   1945     observer.ClearStates();
   1946   }
   1947 
   1948   // Pin the tab "1", which shouldn't move anything.
   1949   {
   1950     tabstrip.SetTabPinned(1, true);
   1951 
   1952     // As the order didn't change, we should get a pinned notification.
   1953     ASSERT_EQ(1, observer.GetStateCount());
   1954     State state(contents1, 1, MockTabStripModelObserver::PINNED);
   1955     EXPECT_TRUE(observer.StateEquals(0, state));
   1956 
   1957     // And verify the state.
   1958     EXPECT_EQ("3p 1p 2", GetPinnedState(tabstrip));
   1959 
   1960     observer.ClearStates();
   1961   }
   1962 
   1963   // Try to move tab "2" to the front, it should be ignored.
   1964   {
   1965     tabstrip.MoveTabContentsAt(2, 0, false);
   1966 
   1967     // As the order didn't change, we should get a pinned notification.
   1968     ASSERT_EQ(0, observer.GetStateCount());
   1969 
   1970     // And verify the state.
   1971     EXPECT_EQ("3p 1p 2", GetPinnedState(tabstrip));
   1972 
   1973     observer.ClearStates();
   1974   }
   1975 
   1976   // Unpin tab "3", which implicitly moves it to the end.
   1977   {
   1978     tabstrip.SetTabPinned(0, false);
   1979 
   1980     ASSERT_EQ(2, observer.GetStateCount());
   1981     State state(contents3, 1, MockTabStripModelObserver::MOVE);
   1982     state.src_index = 0;
   1983     EXPECT_TRUE(observer.StateEquals(0, state));
   1984 
   1985     state = State(contents3, 1, MockTabStripModelObserver::PINNED);
   1986     EXPECT_TRUE(observer.StateEquals(1, state));
   1987 
   1988     // And verify the state.
   1989     EXPECT_EQ("1p 3 2", GetPinnedState(tabstrip));
   1990 
   1991     observer.ClearStates();
   1992   }
   1993 
   1994   // Unpin tab "3", nothing should happen.
   1995   {
   1996     tabstrip.SetTabPinned(1, false);
   1997 
   1998     ASSERT_EQ(0, observer.GetStateCount());
   1999 
   2000     EXPECT_EQ("1p 3 2", GetPinnedState(tabstrip));
   2001 
   2002     observer.ClearStates();
   2003   }
   2004 
   2005   // Pin "3" and "1".
   2006   {
   2007     tabstrip.SetTabPinned(0, true);
   2008     tabstrip.SetTabPinned(1, true);
   2009 
   2010     EXPECT_EQ("1p 3p 2", GetPinnedState(tabstrip));
   2011 
   2012     observer.ClearStates();
   2013   }
   2014 
   2015   TabContentsWrapper* contents4 = CreateTabContents();
   2016   SetID(contents4->tab_contents(), 4);
   2017 
   2018   // Insert "4" between "1" and "3". As "1" and "4" are pinned, "4" should end
   2019   // up after them.
   2020   {
   2021     tabstrip.InsertTabContentsAt(1, contents4, TabStripModel::ADD_NONE);
   2022 
   2023     ASSERT_EQ(1, observer.GetStateCount());
   2024     State state(contents4, 2, MockTabStripModelObserver::INSERT);
   2025     EXPECT_TRUE(observer.StateEquals(0, state));
   2026 
   2027     EXPECT_EQ("1p 3p 4 2", GetPinnedState(tabstrip));
   2028   }
   2029 
   2030   tabstrip.CloseAllTabs();
   2031 }
   2032 
   2033 // Makes sure the TabStripModel calls the right observer methods during a
   2034 // replace.
   2035 TEST_F(TabStripModelTest, ReplaceSendsSelected) {
   2036   typedef MockTabStripModelObserver::State State;
   2037 
   2038   TabStripDummyDelegate delegate(NULL);
   2039   TabStripModel strip(&delegate, profile());
   2040 
   2041   TabContentsWrapper* first_contents = CreateTabContents();
   2042   strip.AddTabContents(first_contents, -1, PageTransition::TYPED,
   2043                        TabStripModel::ADD_ACTIVE);
   2044 
   2045   MockTabStripModelObserver tabstrip_observer;
   2046   strip.AddObserver(&tabstrip_observer);
   2047 
   2048   TabContentsWrapper* new_contents = CreateTabContents();
   2049   delete strip.ReplaceTabContentsAt(0, new_contents);
   2050 
   2051   ASSERT_EQ(2, tabstrip_observer.GetStateCount());
   2052 
   2053   // First event should be for replaced.
   2054   State state(new_contents, 0, MockTabStripModelObserver::REPLACED);
   2055   state.src_contents = first_contents;
   2056   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
   2057 
   2058   // And the second for selected.
   2059   state = State(new_contents, 0, MockTabStripModelObserver::SELECT);
   2060   state.src_contents = first_contents;
   2061   EXPECT_TRUE(tabstrip_observer.StateEquals(1, state));
   2062 
   2063   // Now add another tab and replace it, making sure we don't get a selected
   2064   // event this time.
   2065   TabContentsWrapper* third_contents = CreateTabContents();
   2066   strip.AddTabContents(third_contents, 1, PageTransition::TYPED,
   2067                        TabStripModel::ADD_NONE);
   2068 
   2069   tabstrip_observer.ClearStates();
   2070 
   2071   // And replace it.
   2072   new_contents = CreateTabContents();
   2073   delete strip.ReplaceTabContentsAt(1, new_contents);
   2074 
   2075   ASSERT_EQ(1, tabstrip_observer.GetStateCount());
   2076 
   2077   state = State(new_contents, 1, MockTabStripModelObserver::REPLACED);
   2078   state.src_contents = third_contents;
   2079   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
   2080 
   2081   strip.CloseAllTabs();
   2082 }
   2083 
   2084 // Makes sure TabStripModel handles the case of deleting a tab while removing
   2085 // another tab.
   2086 TEST_F(TabStripModelTest, DeleteFromDestroy) {
   2087   TabStripDummyDelegate delegate(NULL);
   2088   TabStripModel strip(&delegate, profile());
   2089   TabContentsWrapper* contents1 = CreateTabContents();
   2090   TabContentsWrapper* contents2 = CreateTabContents();
   2091   strip.AppendTabContents(contents1, true);
   2092   strip.AppendTabContents(contents2, true);
   2093   // DeleteTabContentsOnDestroyedObserver deletes contents1 when contents2 sends
   2094   // out notification that it is being destroyed.
   2095   DeleteTabContentsOnDestroyedObserver observer(contents2, contents1);
   2096   strip.CloseAllTabs();
   2097 }
   2098 
   2099 TEST_F(TabStripModelTest, MoveSelectedTabsTo) {
   2100   struct TestData {
   2101     // Number of tabs the tab strip should have.
   2102     const int tab_count;
   2103 
   2104     // Number of pinned tabs.
   2105     const int pinned_count;
   2106 
   2107     // Index of the tabs to select.
   2108     const std::string selected_tabs;
   2109 
   2110     // Index to move the tabs to.
   2111     const int target_index;
   2112 
   2113     // Expected state after the move (space separated list of indices).
   2114     const std::string state_after_move;
   2115   } test_data[] = {
   2116     // 1 selected tab.
   2117     { 2, 0, "0", 1, "1 0" },
   2118     { 3, 0, "0", 2, "1 2 0" },
   2119     { 3, 0, "2", 0, "2 0 1" },
   2120     { 3, 0, "2", 1, "0 2 1" },
   2121     { 3, 0, "0 1", 0, "0 1 2" },
   2122 
   2123     // 2 selected tabs.
   2124     { 6, 0, "4 5", 1, "0 4 5 1 2 3" },
   2125     { 3, 0, "0 1", 1, "2 0 1" },
   2126     { 4, 0, "0 2", 1, "1 0 2 3" },
   2127     { 6, 0, "0 1", 3, "2 3 4 0 1 5" },
   2128 
   2129     // 3 selected tabs.
   2130     { 6, 0, "0 2 3", 3, "1 4 5 0 2 3" },
   2131     { 7, 0, "4 5 6", 1, "0 4 5 6 1 2 3" },
   2132     { 7, 0, "1 5 6", 4, "0 2 3 4 1 5 6" },
   2133 
   2134     // 5 selected tabs.
   2135     { 8, 0, "0 2 3 6 7", 3, "1 4 5 0 2 3 6 7" },
   2136 
   2137     // 7 selected tabs
   2138     { 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" },
   2139 
   2140     // With pinned tabs.
   2141     { 6, 2, "2 3", 2, "0p 1p 2 3 4 5" },
   2142     { 6, 2, "0 4", 3, "1p 0p 2 3 4 5" },
   2143     { 6, 3, "1 2 4", 0, "1p 2p 0p 4 3 5" },
   2144     { 8, 3, "1 3 4", 4, "0p 2p 1p 5 6 3 4 7" },
   2145 
   2146     { 7, 4, "2 3 4", 3, "0p 1p 2p 3p 5 4 6" },
   2147   };
   2148 
   2149   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
   2150     TabStripDummyDelegate delegate(NULL);
   2151     TabStripModel strip(&delegate, profile());
   2152     ASSERT_NO_FATAL_FAILURE(
   2153         PrepareTabstripForSelectionTest(&strip, test_data[i].tab_count,
   2154                                         test_data[i].pinned_count,
   2155                                         test_data[i].selected_tabs));
   2156     strip.MoveSelectedTabsTo(test_data[i].target_index);
   2157     EXPECT_EQ(test_data[i].state_after_move, GetPinnedState(strip)) << i;
   2158     strip.CloseAllTabs();
   2159   }
   2160 }
   2161 
   2162 TEST_F(TabStripModelTest, CloseSelectedTabs) {
   2163   TabStripDummyDelegate delegate(NULL);
   2164   TabStripModel strip(&delegate, profile());
   2165   TabContentsWrapper* contents1 = CreateTabContents();
   2166   TabContentsWrapper* contents2 = CreateTabContents();
   2167   TabContentsWrapper* contents3 = CreateTabContents();
   2168   strip.AppendTabContents(contents1, true);
   2169   strip.AppendTabContents(contents2, true);
   2170   strip.AppendTabContents(contents3, true);
   2171   strip.ToggleSelectionAt(1);
   2172   strip.CloseSelectedTabs();
   2173   EXPECT_EQ(1, strip.count());
   2174   EXPECT_EQ(0, strip.active_index());
   2175   strip.CloseAllTabs();
   2176 }
   2177 
   2178 // Verifies that if we change the selection from a multi selection to a single
   2179 // selection, but not in a way that changes the selected_index that
   2180 // TabSelectedAt is still invoked.
   2181 TEST_F(TabStripModelTest, MultipleToSingle) {
   2182   TabStripDummyDelegate delegate(NULL);
   2183   TabStripModel strip(&delegate, profile());
   2184   TabContentsWrapper* contents1 = CreateTabContents();
   2185   TabContentsWrapper* contents2 = CreateTabContents();
   2186   strip.AppendTabContents(contents1, false);
   2187   strip.AppendTabContents(contents2, false);
   2188   strip.ToggleSelectionAt(0);
   2189   strip.ToggleSelectionAt(1);
   2190 
   2191   MockTabStripModelObserver observer;
   2192   strip.AddObserver(&observer);
   2193   // This changes the selection (0 is no longer selected) but the selected_index
   2194   // still remains at 1.
   2195   strip.ActivateTabAt(1, true);
   2196   ASSERT_EQ(1, observer.GetStateCount());
   2197   MockTabStripModelObserver::State s(
   2198       contents2, 1, MockTabStripModelObserver::SELECT);
   2199   s.src_contents = contents2;
   2200   s.user_gesture = true;
   2201   EXPECT_TRUE(observer.StateEquals(0, s));
   2202   strip.RemoveObserver(&observer);
   2203   strip.CloseAllTabs();
   2204 }
   2205