Home | History | Annotate | Download | only in tabs
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/tabs/tab_strip_model.h"
      6 
      7 #include <map>
      8 #include <string>
      9 
     10 #include "base/files/file_path.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/path_service.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/strings/string_split.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "chrome/browser/defaults.h"
     19 #include "chrome/browser/extensions/tab_helper.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/ui/browser.h"
     22 #include "chrome/browser/ui/browser_tabstrip.h"
     23 #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h"
     24 #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h"
     25 #include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
     26 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
     27 #include "chrome/common/url_constants.h"
     28 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     29 #include "chrome/test/base/testing_profile.h"
     30 #include "components/web_modal/popup_manager.h"
     31 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     32 #include "content/public/browser/navigation_controller.h"
     33 #include "content/public/browser/navigation_entry.h"
     34 #include "content/public/browser/render_process_host.h"
     35 #include "content/public/browser/web_contents.h"
     36 #include "content/public/browser/web_contents_observer.h"
     37 #include "extensions/common/extension.h"
     38 #include "testing/gtest/include/gtest/gtest.h"
     39 
     40 using content::SiteInstance;
     41 using content::WebContents;
     42 using extensions::Extension;
     43 using web_modal::NativeWebContentsModalDialog;
     44 
     45 namespace {
     46 
     47 // Class used to delete a WebContents and TabStripModel when another WebContents
     48 // is destroyed.
     49 class DeleteWebContentsOnDestroyedObserver
     50     : public content::WebContentsObserver {
     51  public:
     52   // When |source| is deleted both |tab_to_delete| and |tab_strip| are deleted.
     53   // |tab_to_delete| and |tab_strip| may be NULL.
     54   DeleteWebContentsOnDestroyedObserver(WebContents* source,
     55                                        WebContents* tab_to_delete,
     56                                        TabStripModel* tab_strip)
     57       : WebContentsObserver(source),
     58         tab_to_delete_(tab_to_delete),
     59         tab_strip_(tab_strip) {
     60   }
     61 
     62   virtual void WebContentsDestroyed() OVERRIDE {
     63     WebContents* tab_to_delete = tab_to_delete_;
     64     tab_to_delete_ = NULL;
     65     TabStripModel* tab_strip_to_delete = tab_strip_;
     66     tab_strip_ = NULL;
     67     delete tab_to_delete;
     68     delete tab_strip_to_delete;
     69   }
     70 
     71  private:
     72   WebContents* tab_to_delete_;
     73   TabStripModel* tab_strip_;
     74 
     75   DISALLOW_COPY_AND_ASSIGN(DeleteWebContentsOnDestroyedObserver);
     76 };
     77 
     78 class TabStripDummyDelegate : public TestTabStripModelDelegate {
     79  public:
     80   TabStripDummyDelegate() : run_unload_(false) {}
     81   virtual ~TabStripDummyDelegate() {}
     82 
     83   void set_run_unload_listener(bool value) { run_unload_ = value; }
     84 
     85   virtual bool RunUnloadListenerBeforeClosing(WebContents* contents) OVERRIDE {
     86     return run_unload_;
     87   }
     88 
     89  private:
     90   // Whether to report that we need to run an unload listener before closing.
     91   bool run_unload_;
     92 
     93   DISALLOW_COPY_AND_ASSIGN(TabStripDummyDelegate);
     94 };
     95 
     96 const char kTabStripModelTestIDUserDataKey[] = "TabStripModelTestIDUserData";
     97 
     98 class TabStripModelTestIDUserData : public base::SupportsUserData::Data {
     99  public:
    100   explicit TabStripModelTestIDUserData(int id) : id_(id) {}
    101   virtual ~TabStripModelTestIDUserData() {}
    102   int id() { return id_; }
    103 
    104  private:
    105   int id_;
    106 };
    107 
    108 class DummySingleWebContentsDialogManager
    109     : public web_modal::SingleWebContentsDialogManager {
    110  public:
    111   explicit DummySingleWebContentsDialogManager(
    112       NativeWebContentsModalDialog dialog,
    113       web_modal::SingleWebContentsDialogManagerDelegate* delegate)
    114       : delegate_(delegate),
    115         dialog_(dialog) {}
    116   virtual ~DummySingleWebContentsDialogManager() {}
    117 
    118   virtual void Show() OVERRIDE {}
    119   virtual void Hide() OVERRIDE {}
    120   virtual void Close() OVERRIDE {
    121     delegate_->WillClose(dialog_);
    122   }
    123   virtual void Focus() OVERRIDE {}
    124   virtual void Pulse() OVERRIDE {}
    125   virtual void HostChanged(
    126       web_modal::WebContentsModalDialogHost* new_host) OVERRIDE {}
    127   virtual NativeWebContentsModalDialog dialog() OVERRIDE { return dialog_; }
    128 
    129  private:
    130   web_modal::SingleWebContentsDialogManagerDelegate* delegate_;
    131   NativeWebContentsModalDialog dialog_;
    132 
    133   DISALLOW_COPY_AND_ASSIGN(DummySingleWebContentsDialogManager);
    134 };
    135 
    136 // Test Browser-like class for TabStripModelTest.TabBlockedState.
    137 class TabBlockedStateTestBrowser
    138     : public TabStripModelObserver,
    139       public web_modal::WebContentsModalDialogManagerDelegate {
    140  public:
    141   explicit TabBlockedStateTestBrowser(TabStripModel* tab_strip_model)
    142       : tab_strip_model_(tab_strip_model) {
    143     tab_strip_model_->AddObserver(this);
    144   }
    145 
    146   virtual ~TabBlockedStateTestBrowser() {
    147     tab_strip_model_->RemoveObserver(this);
    148   }
    149 
    150  private:
    151   // TabStripModelObserver
    152   virtual void TabInsertedAt(WebContents* contents,
    153                              int index,
    154                              bool foreground) OVERRIDE {
    155     web_modal::WebContentsModalDialogManager* manager =
    156         web_modal::WebContentsModalDialogManager::FromWebContents(contents);
    157     if (manager)
    158       manager->SetDelegate(this);
    159   }
    160 
    161   // WebContentsModalDialogManagerDelegate
    162   virtual void SetWebContentsBlocked(content::WebContents* contents,
    163                                      bool blocked) OVERRIDE {
    164     int index = tab_strip_model_->GetIndexOfWebContents(contents);
    165     ASSERT_GE(index, 0);
    166     tab_strip_model_->SetTabBlocked(index, blocked);
    167   }
    168 
    169   TabStripModel* tab_strip_model_;
    170 
    171   DISALLOW_COPY_AND_ASSIGN(TabBlockedStateTestBrowser);
    172 };
    173 
    174 }  // namespace
    175 
    176 class TabStripModelTest : public ChromeRenderViewHostTestHarness {
    177  public:
    178   WebContents* CreateWebContents() {
    179     return WebContents::Create(WebContents::CreateParams(profile()));
    180   }
    181 
    182   WebContents* CreateWebContentsWithSharedRPH(WebContents* web_contents) {
    183     WebContents::CreateParams create_params(
    184         profile(), web_contents->GetRenderViewHost()->GetSiteInstance());
    185     WebContents* retval = WebContents::Create(create_params);
    186     EXPECT_EQ(retval->GetRenderProcessHost(),
    187               web_contents->GetRenderProcessHost());
    188     return retval;
    189   }
    190 
    191   // Sets the id of the specified contents.
    192   void SetID(WebContents* contents, int id) {
    193     contents->SetUserData(&kTabStripModelTestIDUserDataKey,
    194                           new TabStripModelTestIDUserData(id));
    195   }
    196 
    197   // Returns the id of the specified contents.
    198   int GetID(WebContents* contents) {
    199     TabStripModelTestIDUserData* user_data =
    200         static_cast<TabStripModelTestIDUserData*>(
    201             contents->GetUserData(&kTabStripModelTestIDUserDataKey));
    202 
    203     return user_data ? user_data->id() : -1;
    204   }
    205 
    206   // Returns the state of the given tab strip as a string. The state consists
    207   // of the ID of each web contents followed by a 'p' if pinned. For example,
    208   // if the model consists of two tabs with ids 2 and 1, with the first
    209   // tab pinned, this returns "2p 1".
    210   std::string GetTabStripStateString(const TabStripModel& model) {
    211     std::string actual;
    212     for (int i = 0; i < model.count(); ++i) {
    213       if (i > 0)
    214         actual += " ";
    215 
    216       actual += base::IntToString(GetID(model.GetWebContentsAt(i)));
    217 
    218       if (model.IsAppTab(i))
    219         actual += "a";
    220 
    221       if (model.IsTabPinned(i))
    222         actual += "p";
    223     }
    224     return actual;
    225   }
    226 
    227   std::string GetIndicesClosedByCommandAsString(
    228       const TabStripModel& model,
    229       int index,
    230       TabStripModel::ContextMenuCommand id) const {
    231     std::vector<int> indices = model.GetIndicesClosedByCommand(index, id);
    232     std::string result;
    233     for (size_t i = 0; i < indices.size(); ++i) {
    234       if (i != 0)
    235         result += " ";
    236       result += base::IntToString(indices[i]);
    237     }
    238     return result;
    239   }
    240 
    241   void PrepareTabstripForSelectionTest(TabStripModel* model,
    242                                        int tab_count,
    243                                        int pinned_count,
    244                                        const std::string& selected_tabs) {
    245     for (int i = 0; i < tab_count; ++i) {
    246       WebContents* contents = CreateWebContents();
    247       SetID(contents, i);
    248       model->AppendWebContents(contents, true);
    249     }
    250     for (int i = 0; i < pinned_count; ++i)
    251       model->SetTabPinned(i, true);
    252 
    253     ui::ListSelectionModel selection_model;
    254     std::vector<std::string> selection;
    255     base::SplitStringAlongWhitespace(selected_tabs, &selection);
    256     for (size_t i = 0; i < selection.size(); ++i) {
    257       int value;
    258       ASSERT_TRUE(base::StringToInt(selection[i], &value));
    259       selection_model.AddIndexToSelection(value);
    260     }
    261     selection_model.set_active(selection_model.selected_indices()[0]);
    262     model->SetSelectionFromModel(selection_model);
    263   }
    264 };
    265 
    266 class MockTabStripModelObserver : public TabStripModelObserver {
    267  public:
    268   explicit MockTabStripModelObserver(TabStripModel* model)
    269       : empty_(true),
    270         deleted_(false),
    271         model_(model) {}
    272   virtual ~MockTabStripModelObserver() {}
    273 
    274   enum TabStripModelObserverAction {
    275     INSERT,
    276     CLOSE,
    277     DETACH,
    278     ACTIVATE,
    279     DEACTIVATE,
    280     SELECT,
    281     MOVE,
    282     CHANGE,
    283     PINNED,
    284     REPLACED,
    285     CLOSE_ALL,
    286     CLOSE_ALL_CANCELED,
    287   };
    288 
    289   struct State {
    290     State(WebContents* a_dst_contents,
    291           int a_dst_index,
    292           TabStripModelObserverAction a_action)
    293         : src_contents(NULL),
    294           dst_contents(a_dst_contents),
    295           src_index(-1),
    296           dst_index(a_dst_index),
    297           change_reason(CHANGE_REASON_NONE),
    298           foreground(false),
    299           action(a_action) {
    300     }
    301 
    302     WebContents* src_contents;
    303     WebContents* dst_contents;
    304     int src_index;
    305     int dst_index;
    306     int change_reason;
    307     bool foreground;
    308     TabStripModelObserverAction action;
    309   };
    310 
    311   int GetStateCount() const {
    312     return static_cast<int>(states_.size());
    313   }
    314 
    315   // Returns (by way of parameters) the number of state's with CLOSE_ALL and
    316   // CLOSE_ALL_CANCELED.
    317   void GetCloseCounts(int* close_all_count,
    318                       int* close_all_canceled_count) {
    319     *close_all_count = *close_all_canceled_count = 0;
    320     for (int i = 0; i < GetStateCount(); ++i) {
    321       switch (GetStateAt(i).action) {
    322         case CLOSE_ALL:
    323           (*close_all_count)++;
    324           break;
    325         case CLOSE_ALL_CANCELED:
    326           (*close_all_canceled_count)++;
    327           break;
    328         default:
    329           break;
    330       }
    331     }
    332   }
    333 
    334   const State& GetStateAt(int index) const {
    335     DCHECK(index >= 0 && index < GetStateCount());
    336     return states_[index];
    337   }
    338 
    339   bool StateEquals(int index, const State& state) {
    340     const State& s = GetStateAt(index);
    341     return (s.src_contents == state.src_contents &&
    342             s.dst_contents == state.dst_contents &&
    343             s.src_index == state.src_index &&
    344             s.dst_index == state.dst_index &&
    345             s.change_reason == state.change_reason &&
    346             s.foreground == state.foreground &&
    347             s.action == state.action);
    348   }
    349 
    350   // TabStripModelObserver implementation:
    351   virtual void TabInsertedAt(WebContents* contents,
    352                              int index,
    353                              bool foreground) OVERRIDE {
    354     empty_ = false;
    355     State s(contents, index, INSERT);
    356     s.foreground = foreground;
    357     states_.push_back(s);
    358   }
    359   virtual void ActiveTabChanged(WebContents* old_contents,
    360                                 WebContents* new_contents,
    361                                 int index,
    362                                 int reason) OVERRIDE {
    363     State s(new_contents, index, ACTIVATE);
    364     s.src_contents = old_contents;
    365     s.change_reason = reason;
    366     states_.push_back(s);
    367   }
    368   virtual void TabSelectionChanged(
    369       TabStripModel* tab_strip_model,
    370       const ui::ListSelectionModel& old_model) OVERRIDE {
    371     State s(model()->GetActiveWebContents(), model()->active_index(), SELECT);
    372     s.src_contents = model()->GetWebContentsAt(old_model.active());
    373     s.src_index = old_model.active();
    374     states_.push_back(s);
    375   }
    376   virtual void TabMoved(WebContents* contents,
    377                         int from_index,
    378                         int to_index) OVERRIDE {
    379     State s(contents, to_index, MOVE);
    380     s.src_index = from_index;
    381     states_.push_back(s);
    382   }
    383 
    384   virtual void TabClosingAt(TabStripModel* tab_strip_model,
    385                             WebContents* contents,
    386                             int index) OVERRIDE {
    387     states_.push_back(State(contents, index, CLOSE));
    388   }
    389   virtual void TabDetachedAt(WebContents* contents, int index) OVERRIDE {
    390     states_.push_back(State(contents, index, DETACH));
    391   }
    392   virtual void TabDeactivated(WebContents* contents) OVERRIDE {
    393     states_.push_back(State(contents, model()->active_index(), DEACTIVATE));
    394   }
    395   virtual void TabChangedAt(WebContents* contents,
    396                             int index,
    397                             TabChangeType change_type) OVERRIDE {
    398     states_.push_back(State(contents, index, CHANGE));
    399   }
    400   virtual void TabReplacedAt(TabStripModel* tab_strip_model,
    401                              WebContents* old_contents,
    402                              WebContents* new_contents,
    403                              int index) OVERRIDE {
    404     State s(new_contents, index, REPLACED);
    405     s.src_contents = old_contents;
    406     states_.push_back(s);
    407   }
    408   virtual void TabPinnedStateChanged(WebContents* contents,
    409                                      int index) OVERRIDE {
    410     states_.push_back(State(contents, index, PINNED));
    411   }
    412   virtual void TabStripEmpty() OVERRIDE {
    413     empty_ = true;
    414   }
    415   virtual void WillCloseAllTabs() OVERRIDE {
    416     states_.push_back(State(NULL, -1, CLOSE_ALL));
    417   }
    418   virtual void CloseAllTabsCanceled() OVERRIDE {
    419     states_.push_back(State(NULL, -1, CLOSE_ALL_CANCELED));
    420   }
    421   virtual void TabStripModelDeleted() OVERRIDE {
    422     deleted_ = true;
    423   }
    424 
    425   void ClearStates() {
    426     states_.clear();
    427   }
    428 
    429   bool empty() const { return empty_; }
    430   bool deleted() const { return deleted_; }
    431   TabStripModel* model() { return model_; }
    432 
    433  private:
    434   std::vector<State> states_;
    435 
    436   bool empty_;
    437   bool deleted_;
    438   TabStripModel* model_;
    439 
    440   DISALLOW_COPY_AND_ASSIGN(MockTabStripModelObserver);
    441 };
    442 
    443 TEST_F(TabStripModelTest, TestBasicAPI) {
    444   TabStripDummyDelegate delegate;
    445   TabStripModel tabstrip(&delegate, profile());
    446   MockTabStripModelObserver observer(&tabstrip);
    447   tabstrip.AddObserver(&observer);
    448 
    449   EXPECT_TRUE(tabstrip.empty());
    450 
    451   typedef MockTabStripModelObserver::State State;
    452 
    453   WebContents* contents1 = CreateWebContents();
    454   SetID(contents1, 1);
    455 
    456   // Note! The ordering of these tests is important, each subsequent test
    457   // builds on the state established in the previous. This is important if you
    458   // ever insert tests rather than append.
    459 
    460   // Test AppendWebContents, ContainsIndex
    461   {
    462     EXPECT_FALSE(tabstrip.ContainsIndex(0));
    463     tabstrip.AppendWebContents(contents1, true);
    464     EXPECT_TRUE(tabstrip.ContainsIndex(0));
    465     EXPECT_EQ(1, tabstrip.count());
    466     EXPECT_EQ(3, observer.GetStateCount());
    467     State s1(contents1, 0, MockTabStripModelObserver::INSERT);
    468     s1.foreground = true;
    469     EXPECT_TRUE(observer.StateEquals(0, s1));
    470     State s2(contents1, 0, MockTabStripModelObserver::ACTIVATE);
    471     EXPECT_TRUE(observer.StateEquals(1, s2));
    472     State s3(contents1, 0, MockTabStripModelObserver::SELECT);
    473     s3.src_contents = NULL;
    474     s3.src_index = ui::ListSelectionModel::kUnselectedIndex;
    475     EXPECT_TRUE(observer.StateEquals(2, s3));
    476     observer.ClearStates();
    477   }
    478   EXPECT_EQ("1", GetTabStripStateString(tabstrip));
    479 
    480   // Test InsertWebContentsAt, foreground tab.
    481   WebContents* contents2 = CreateWebContents();
    482   SetID(contents2, 2);
    483   {
    484     tabstrip.InsertWebContentsAt(1, contents2, TabStripModel::ADD_ACTIVE);
    485 
    486     EXPECT_EQ(2, tabstrip.count());
    487     EXPECT_EQ(4, observer.GetStateCount());
    488     State s1(contents2, 1, MockTabStripModelObserver::INSERT);
    489     s1.foreground = true;
    490     EXPECT_TRUE(observer.StateEquals(0, s1));
    491     State s2(contents1, 0, MockTabStripModelObserver::DEACTIVATE);
    492     EXPECT_TRUE(observer.StateEquals(1, s2));
    493     State s3(contents2, 1, MockTabStripModelObserver::ACTIVATE);
    494     s3.src_contents = contents1;
    495     EXPECT_TRUE(observer.StateEquals(2, s3));
    496     State s4(contents2, 1, MockTabStripModelObserver::SELECT);
    497     s4.src_contents = contents1;
    498     s4.src_index = 0;
    499     EXPECT_TRUE(observer.StateEquals(3, s4));
    500     observer.ClearStates();
    501   }
    502   EXPECT_EQ("1 2", GetTabStripStateString(tabstrip));
    503 
    504   // Test InsertWebContentsAt, background tab.
    505   WebContents* contents3 = CreateWebContents();
    506   SetID(contents3, 3);
    507   {
    508     tabstrip.InsertWebContentsAt(2, contents3, TabStripModel::ADD_NONE);
    509 
    510     EXPECT_EQ(3, tabstrip.count());
    511     EXPECT_EQ(1, observer.GetStateCount());
    512     State s1(contents3, 2, MockTabStripModelObserver::INSERT);
    513     s1.foreground = false;
    514     EXPECT_TRUE(observer.StateEquals(0, s1));
    515     observer.ClearStates();
    516   }
    517   EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip));
    518 
    519   // Test ActivateTabAt
    520   {
    521     tabstrip.ActivateTabAt(2, true);
    522     EXPECT_EQ(3, observer.GetStateCount());
    523     State s1(contents2, 1, MockTabStripModelObserver::DEACTIVATE);
    524     EXPECT_TRUE(observer.StateEquals(0, s1));
    525     State s2(contents3, 2, MockTabStripModelObserver::ACTIVATE);
    526     s2.src_contents = contents2;
    527     s2.change_reason = TabStripModelObserver::CHANGE_REASON_USER_GESTURE;
    528     EXPECT_TRUE(observer.StateEquals(1, s2));
    529     State s3(contents3, 2, MockTabStripModelObserver::SELECT);
    530     s3.src_contents = contents2;
    531     s3.src_index = 1;
    532     EXPECT_TRUE(observer.StateEquals(2, s3));
    533     observer.ClearStates();
    534   }
    535   EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip));
    536 
    537   // Test DetachWebContentsAt
    538   {
    539     // Detach ...
    540     WebContents* detached = tabstrip.DetachWebContentsAt(2);
    541     // ... and append again because we want this for later.
    542     tabstrip.AppendWebContents(detached, true);
    543     EXPECT_EQ(8, observer.GetStateCount());
    544     State s1(detached, 2, MockTabStripModelObserver::DETACH);
    545     EXPECT_TRUE(observer.StateEquals(0, s1));
    546     State s2(detached, ui::ListSelectionModel::kUnselectedIndex,
    547         MockTabStripModelObserver::DEACTIVATE);
    548     EXPECT_TRUE(observer.StateEquals(1, s2));
    549     State s3(contents2, 1, MockTabStripModelObserver::ACTIVATE);
    550     s3.src_contents = contents3;
    551     s3.change_reason = TabStripModelObserver::CHANGE_REASON_NONE;
    552     EXPECT_TRUE(observer.StateEquals(2, s3));
    553     State s4(contents2, 1, MockTabStripModelObserver::SELECT);
    554     s4.src_contents = NULL;
    555     s4.src_index = ui::ListSelectionModel::kUnselectedIndex;
    556     EXPECT_TRUE(observer.StateEquals(3, s4));
    557     State s5(detached, 2, MockTabStripModelObserver::INSERT);
    558     s5.foreground = true;
    559     EXPECT_TRUE(observer.StateEquals(4, s5));
    560     State s6(contents2, 1, MockTabStripModelObserver::DEACTIVATE);
    561     EXPECT_TRUE(observer.StateEquals(5, s6));
    562     State s7(detached, 2, MockTabStripModelObserver::ACTIVATE);
    563     s7.src_contents = contents2;
    564     s7.change_reason = TabStripModelObserver::CHANGE_REASON_NONE;
    565     EXPECT_TRUE(observer.StateEquals(6, s7));
    566     State s8(detached, 2, MockTabStripModelObserver::SELECT);
    567     s8.src_contents = contents2;
    568     s8.src_index = 1;
    569     EXPECT_TRUE(observer.StateEquals(7, s8));
    570     observer.ClearStates();
    571   }
    572   EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip));
    573 
    574   // Test CloseWebContentsAt
    575   {
    576     EXPECT_TRUE(tabstrip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE));
    577     EXPECT_EQ(2, tabstrip.count());
    578 
    579     EXPECT_EQ(5, observer.GetStateCount());
    580     State s1(contents3, 2, MockTabStripModelObserver::CLOSE);
    581     EXPECT_TRUE(observer.StateEquals(0, s1));
    582     State s2(contents3, 2, MockTabStripModelObserver::DETACH);
    583     EXPECT_TRUE(observer.StateEquals(1, s2));
    584     State s3(contents3, ui::ListSelectionModel::kUnselectedIndex,
    585         MockTabStripModelObserver::DEACTIVATE);
    586     EXPECT_TRUE(observer.StateEquals(2, s3));
    587     State s4(contents2, 1, MockTabStripModelObserver::ACTIVATE);
    588     s4.src_contents = contents3;
    589     s4.change_reason = TabStripModelObserver::CHANGE_REASON_NONE;
    590     EXPECT_TRUE(observer.StateEquals(3, s4));
    591     State s5(contents2, 1, MockTabStripModelObserver::SELECT);
    592     s5.src_contents = NULL;
    593     s5.src_index = ui::ListSelectionModel::kUnselectedIndex;
    594     EXPECT_TRUE(observer.StateEquals(4, s5));
    595     observer.ClearStates();
    596   }
    597   EXPECT_EQ("1 2", GetTabStripStateString(tabstrip));
    598 
    599   // Test MoveWebContentsAt, select_after_move == true
    600   {
    601     tabstrip.MoveWebContentsAt(1, 0, true);
    602 
    603     EXPECT_EQ(1, observer.GetStateCount());
    604     State s1(contents2, 0, MockTabStripModelObserver::MOVE);
    605     s1.src_index = 1;
    606     EXPECT_TRUE(observer.StateEquals(0, s1));
    607     EXPECT_EQ(0, tabstrip.active_index());
    608     observer.ClearStates();
    609   }
    610   EXPECT_EQ("2 1", GetTabStripStateString(tabstrip));
    611 
    612   // Test MoveWebContentsAt, select_after_move == false
    613   {
    614     tabstrip.MoveWebContentsAt(1, 0, false);
    615     EXPECT_EQ(1, observer.GetStateCount());
    616     State s1(contents1, 0, MockTabStripModelObserver::MOVE);
    617     s1.src_index = 1;
    618     EXPECT_TRUE(observer.StateEquals(0, s1));
    619     EXPECT_EQ(1, tabstrip.active_index());
    620 
    621     tabstrip.MoveWebContentsAt(0, 1, false);
    622     observer.ClearStates();
    623   }
    624   EXPECT_EQ("2 1", GetTabStripStateString(tabstrip));
    625 
    626   // Test Getters
    627   {
    628     EXPECT_EQ(contents2, tabstrip.GetActiveWebContents());
    629     EXPECT_EQ(contents2, tabstrip.GetWebContentsAt(0));
    630     EXPECT_EQ(contents1, tabstrip.GetWebContentsAt(1));
    631     EXPECT_EQ(0, tabstrip.GetIndexOfWebContents(contents2));
    632     EXPECT_EQ(1, tabstrip.GetIndexOfWebContents(contents1));
    633   }
    634 
    635   // Test UpdateWebContentsStateAt
    636   {
    637     tabstrip.UpdateWebContentsStateAt(0, TabStripModelObserver::ALL);
    638     EXPECT_EQ(1, observer.GetStateCount());
    639     State s1(contents2, 0, MockTabStripModelObserver::CHANGE);
    640     EXPECT_TRUE(observer.StateEquals(0, s1));
    641     observer.ClearStates();
    642   }
    643 
    644   // Test SelectNextTab, SelectPreviousTab, SelectLastTab
    645   {
    646     // Make sure the second of the two tabs is selected first...
    647     tabstrip.ActivateTabAt(1, true);
    648     tabstrip.SelectPreviousTab();
    649     EXPECT_EQ(0, tabstrip.active_index());
    650     tabstrip.SelectLastTab();
    651     EXPECT_EQ(1, tabstrip.active_index());
    652     tabstrip.SelectNextTab();
    653     EXPECT_EQ(0, tabstrip.active_index());
    654   }
    655 
    656   // Test CloseSelectedTabs
    657   {
    658     tabstrip.CloseSelectedTabs();
    659     // |CloseSelectedTabs| calls CloseWebContentsAt, we already tested that, now
    660     // just verify that the count and selected index have changed
    661     // appropriately...
    662     EXPECT_EQ(1, tabstrip.count());
    663     EXPECT_EQ(0, tabstrip.active_index());
    664   }
    665 
    666   observer.ClearStates();
    667   tabstrip.CloseAllTabs();
    668 
    669   int close_all_count = 0, close_all_canceled_count = 0;
    670   observer.GetCloseCounts(&close_all_count, &close_all_canceled_count);
    671   EXPECT_EQ(1, close_all_count);
    672   EXPECT_EQ(0, close_all_canceled_count);
    673 
    674   // TabStripModel should now be empty.
    675   EXPECT_TRUE(tabstrip.empty());
    676 
    677   // Opener methods are tested below...
    678 
    679   tabstrip.RemoveObserver(&observer);
    680 }
    681 
    682 TEST_F(TabStripModelTest, TestBasicOpenerAPI) {
    683   TabStripDummyDelegate delegate;
    684   TabStripModel tabstrip(&delegate, profile());
    685   EXPECT_TRUE(tabstrip.empty());
    686 
    687   // This is a basic test of opener functionality. opener is created
    688   // as the first tab in the strip and then we create 5 other tabs in the
    689   // background with opener set as their opener.
    690 
    691   WebContents* opener = CreateWebContents();
    692   tabstrip.AppendWebContents(opener, true);
    693   WebContents* contents1 = CreateWebContents();
    694   WebContents* contents2 = CreateWebContents();
    695   WebContents* contents3 = CreateWebContents();
    696   WebContents* contents4 = CreateWebContents();
    697   WebContents* contents5 = CreateWebContents();
    698 
    699   // We use |InsertWebContentsAt| here instead of |AppendWebContents| so that
    700   // openership relationships are preserved.
    701   tabstrip.InsertWebContentsAt(tabstrip.count(), contents1,
    702                                TabStripModel::ADD_INHERIT_GROUP);
    703   tabstrip.InsertWebContentsAt(tabstrip.count(), contents2,
    704                                TabStripModel::ADD_INHERIT_GROUP);
    705   tabstrip.InsertWebContentsAt(tabstrip.count(), contents3,
    706                                TabStripModel::ADD_INHERIT_GROUP);
    707   tabstrip.InsertWebContentsAt(tabstrip.count(), contents4,
    708                                TabStripModel::ADD_INHERIT_GROUP);
    709   tabstrip.InsertWebContentsAt(tabstrip.count(), contents5,
    710                                TabStripModel::ADD_INHERIT_GROUP);
    711 
    712   // All the tabs should have the same opener.
    713   for (int i = 1; i < tabstrip.count(); ++i)
    714     EXPECT_EQ(opener, tabstrip.GetOpenerOfWebContentsAt(i));
    715 
    716   // If there is a next adjacent item, then the index should be of that item.
    717   EXPECT_EQ(2, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 1, false));
    718   // If the last tab in the group is closed, the preceding tab in the same
    719   // group should be selected.
    720   EXPECT_EQ(4, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 5, false));
    721 
    722   // Tests the method that finds the last tab opened by the same opener in the
    723   // strip (this is the insertion index for the next background tab for the
    724   // specified opener).
    725   EXPECT_EQ(5, tabstrip.GetIndexOfLastWebContentsOpenedBy(opener, 1));
    726 
    727   // For a tab that has opened no other tabs, the return value should always be
    728   // -1...
    729   EXPECT_EQ(-1,
    730             tabstrip.GetIndexOfNextWebContentsOpenedBy(contents1, 3, false));
    731   EXPECT_EQ(-1,
    732             tabstrip.GetIndexOfLastWebContentsOpenedBy(contents1, 3));
    733 
    734   // ForgetAllOpeners should destroy all opener relationships.
    735   tabstrip.ForgetAllOpeners();
    736   EXPECT_EQ(-1, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 1, false));
    737   EXPECT_EQ(-1, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 5, false));
    738   EXPECT_EQ(-1, tabstrip.GetIndexOfLastWebContentsOpenedBy(opener, 1));
    739 
    740   // Specify the last tab as the opener of the others.
    741   for (int i = 0; i < tabstrip.count() - 1; ++i)
    742     tabstrip.SetOpenerOfWebContentsAt(i, contents5);
    743 
    744   for (int i = 0; i < tabstrip.count() - 1; ++i)
    745     EXPECT_EQ(contents5, tabstrip.GetOpenerOfWebContentsAt(i));
    746 
    747   // If there is a next adjacent item, then the index should be of that item.
    748   EXPECT_EQ(2, tabstrip.GetIndexOfNextWebContentsOpenedBy(contents5, 1, false));
    749 
    750   // If the last tab in the group is closed, the preceding tab in the same
    751   // group should be selected.
    752   EXPECT_EQ(3, tabstrip.GetIndexOfNextWebContentsOpenedBy(contents5, 4, false));
    753 
    754   tabstrip.CloseAllTabs();
    755   EXPECT_TRUE(tabstrip.empty());
    756 }
    757 
    758 static int GetInsertionIndex(TabStripModel* tabstrip) {
    759   return tabstrip->order_controller()->DetermineInsertionIndex(
    760       ui::PAGE_TRANSITION_LINK, false);
    761 }
    762 
    763 static void InsertWebContentses(TabStripModel* tabstrip,
    764                                 WebContents* contents1,
    765                                 WebContents* contents2,
    766                                 WebContents* contents3) {
    767   tabstrip->InsertWebContentsAt(GetInsertionIndex(tabstrip),
    768                                 contents1,
    769                                 TabStripModel::ADD_INHERIT_GROUP);
    770   tabstrip->InsertWebContentsAt(GetInsertionIndex(tabstrip),
    771                                 contents2,
    772                                 TabStripModel::ADD_INHERIT_GROUP);
    773   tabstrip->InsertWebContentsAt(GetInsertionIndex(tabstrip),
    774                                 contents3,
    775                                 TabStripModel::ADD_INHERIT_GROUP);
    776 }
    777 
    778 // Tests opening background tabs.
    779 TEST_F(TabStripModelTest, TestLTRInsertionOptions) {
    780   TabStripDummyDelegate delegate;
    781   TabStripModel tabstrip(&delegate, profile());
    782   EXPECT_TRUE(tabstrip.empty());
    783 
    784   WebContents* opener = CreateWebContents();
    785   tabstrip.AppendWebContents(opener, true);
    786 
    787   WebContents* contents1 = CreateWebContents();
    788   WebContents* contents2 = CreateWebContents();
    789   WebContents* contents3 = CreateWebContents();
    790 
    791   // Test LTR
    792   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
    793   EXPECT_EQ(contents1, tabstrip.GetWebContentsAt(1));
    794   EXPECT_EQ(contents2, tabstrip.GetWebContentsAt(2));
    795   EXPECT_EQ(contents3, tabstrip.GetWebContentsAt(3));
    796 
    797   tabstrip.CloseAllTabs();
    798   EXPECT_TRUE(tabstrip.empty());
    799 }
    800 
    801 // This test constructs a tabstrip, and then simulates loading several tabs in
    802 // the background from link clicks on the first tab. Then it simulates opening
    803 // a new tab from the first tab in the foreground via a link click, verifies
    804 // that this tab is opened adjacent to the opener, then closes it.
    805 // Finally it tests that a tab opened for some non-link purpose opens at the
    806 // end of the strip, not bundled to any existing context.
    807 TEST_F(TabStripModelTest, TestInsertionIndexDetermination) {
    808   TabStripDummyDelegate delegate;
    809   TabStripModel tabstrip(&delegate, profile());
    810   EXPECT_TRUE(tabstrip.empty());
    811 
    812   WebContents* opener = CreateWebContents();
    813   tabstrip.AppendWebContents(opener, true);
    814 
    815   // Open some other random unrelated tab in the background to monkey with our
    816   // insertion index.
    817   WebContents* other = CreateWebContents();
    818   tabstrip.AppendWebContents(other, false);
    819 
    820   WebContents* contents1 = CreateWebContents();
    821   WebContents* contents2 = CreateWebContents();
    822   WebContents* contents3 = CreateWebContents();
    823 
    824   // Start by testing LTR.
    825   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
    826   EXPECT_EQ(opener, tabstrip.GetWebContentsAt(0));
    827   EXPECT_EQ(contents1, tabstrip.GetWebContentsAt(1));
    828   EXPECT_EQ(contents2, tabstrip.GetWebContentsAt(2));
    829   EXPECT_EQ(contents3, tabstrip.GetWebContentsAt(3));
    830   EXPECT_EQ(other, tabstrip.GetWebContentsAt(4));
    831 
    832   // The opener API should work...
    833   EXPECT_EQ(3, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 2, false));
    834   EXPECT_EQ(2, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 3, false));
    835   EXPECT_EQ(3, tabstrip.GetIndexOfLastWebContentsOpenedBy(opener, 1));
    836 
    837   // Now open a foreground tab from a link. It should be opened adjacent to the
    838   // opener tab.
    839   WebContents* fg_link_contents = CreateWebContents();
    840   int insert_index = tabstrip.order_controller()->DetermineInsertionIndex(
    841       ui::PAGE_TRANSITION_LINK, true);
    842   EXPECT_EQ(1, insert_index);
    843   tabstrip.InsertWebContentsAt(insert_index, fg_link_contents,
    844                                TabStripModel::ADD_ACTIVE |
    845                                TabStripModel::ADD_INHERIT_GROUP);
    846   EXPECT_EQ(1, tabstrip.active_index());
    847   EXPECT_EQ(fg_link_contents, tabstrip.GetActiveWebContents());
    848 
    849   // Now close this contents. The selection should move to the opener contents.
    850   tabstrip.CloseSelectedTabs();
    851   EXPECT_EQ(0, tabstrip.active_index());
    852 
    853   // Now open a new empty tab. It should open at the end of the strip.
    854   WebContents* fg_nonlink_contents = CreateWebContents();
    855   insert_index = tabstrip.order_controller()->DetermineInsertionIndex(
    856       ui::PAGE_TRANSITION_AUTO_BOOKMARK, true);
    857   EXPECT_EQ(tabstrip.count(), insert_index);
    858   // We break the opener relationship...
    859   tabstrip.InsertWebContentsAt(insert_index,
    860                                fg_nonlink_contents,
    861                                TabStripModel::ADD_NONE);
    862   // Now select it, so that user_gesture == true causes the opener relationship
    863   // to be forgotten...
    864   tabstrip.ActivateTabAt(tabstrip.count() - 1, true);
    865   EXPECT_EQ(tabstrip.count() - 1, tabstrip.active_index());
    866   EXPECT_EQ(fg_nonlink_contents, tabstrip.GetActiveWebContents());
    867 
    868   // Verify that all opener relationships are forgotten.
    869   EXPECT_EQ(-1, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 2, false));
    870   EXPECT_EQ(-1, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 3, false));
    871   EXPECT_EQ(-1, tabstrip.GetIndexOfNextWebContentsOpenedBy(opener, 3, false));
    872   EXPECT_EQ(-1, tabstrip.GetIndexOfLastWebContentsOpenedBy(opener, 1));
    873 
    874   tabstrip.CloseAllTabs();
    875   EXPECT_TRUE(tabstrip.empty());
    876 }
    877 
    878 // Tests that selection is shifted to the correct tab when a tab is closed.
    879 // If a tab is in the background when it is closed, the selection does not
    880 // change.
    881 // If a tab is in the foreground (selected),
    882 //   If that tab does not have an opener, selection shifts to the right.
    883 //   If the tab has an opener,
    884 //     The next tab (scanning LTR) in the entire strip that has the same opener
    885 //     is selected
    886 //     If there are no other tabs that have the same opener,
    887 //       The opener is selected
    888 //
    889 TEST_F(TabStripModelTest, TestSelectOnClose) {
    890   TabStripDummyDelegate delegate;
    891   TabStripModel tabstrip(&delegate, profile());
    892   EXPECT_TRUE(tabstrip.empty());
    893 
    894   WebContents* opener = CreateWebContents();
    895   tabstrip.AppendWebContents(opener, true);
    896 
    897   WebContents* contents1 = CreateWebContents();
    898   WebContents* contents2 = CreateWebContents();
    899   WebContents* contents3 = CreateWebContents();
    900 
    901   // Note that we use Detach instead of Close throughout this test to avoid
    902   // having to keep reconstructing these WebContentses.
    903 
    904   // First test that closing tabs that are in the background doesn't adjust the
    905   // current selection.
    906   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
    907   EXPECT_EQ(0, tabstrip.active_index());
    908 
    909   tabstrip.DetachWebContentsAt(1);
    910   EXPECT_EQ(0, tabstrip.active_index());
    911 
    912   for (int i = tabstrip.count() - 1; i >= 1; --i)
    913     tabstrip.DetachWebContentsAt(i);
    914 
    915   // Now test that when a tab doesn't have an opener, selection shifts to the
    916   // right when the tab is closed.
    917   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
    918   EXPECT_EQ(0, tabstrip.active_index());
    919 
    920   tabstrip.ForgetAllOpeners();
    921   tabstrip.ActivateTabAt(1, true);
    922   EXPECT_EQ(1, tabstrip.active_index());
    923   tabstrip.DetachWebContentsAt(1);
    924   EXPECT_EQ(1, tabstrip.active_index());
    925   tabstrip.DetachWebContentsAt(1);
    926   EXPECT_EQ(1, tabstrip.active_index());
    927   tabstrip.DetachWebContentsAt(1);
    928   EXPECT_EQ(0, tabstrip.active_index());
    929 
    930   for (int i = tabstrip.count() - 1; i >= 1; --i)
    931     tabstrip.DetachWebContentsAt(i);
    932 
    933   // Now test that when a tab does have an opener, it selects the next tab
    934   // opened by the same opener scanning LTR when it is closed.
    935   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
    936   EXPECT_EQ(0, tabstrip.active_index());
    937   tabstrip.ActivateTabAt(2, false);
    938   EXPECT_EQ(2, tabstrip.active_index());
    939   tabstrip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE);
    940   EXPECT_EQ(2, tabstrip.active_index());
    941   tabstrip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE);
    942   EXPECT_EQ(1, tabstrip.active_index());
    943   tabstrip.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
    944   EXPECT_EQ(0, tabstrip.active_index());
    945   // Finally test that when a tab has no "siblings" that the opener is
    946   // selected.
    947   WebContents* other_contents = CreateWebContents();
    948   tabstrip.InsertWebContentsAt(1, other_contents,
    949                                TabStripModel::ADD_NONE);
    950   EXPECT_EQ(2, tabstrip.count());
    951   WebContents* opened_contents = CreateWebContents();
    952   tabstrip.InsertWebContentsAt(2, opened_contents,
    953                                TabStripModel::ADD_ACTIVE |
    954                                TabStripModel::ADD_INHERIT_GROUP);
    955   EXPECT_EQ(2, tabstrip.active_index());
    956   tabstrip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE);
    957   EXPECT_EQ(0, tabstrip.active_index());
    958 
    959   tabstrip.CloseAllTabs();
    960   EXPECT_TRUE(tabstrip.empty());
    961 }
    962 
    963 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
    964 // CommandCloseTab.
    965 TEST_F(TabStripModelTest, CommandCloseTab) {
    966   TabStripDummyDelegate delegate;
    967   TabStripModel tabstrip(&delegate, profile());
    968   EXPECT_TRUE(tabstrip.empty());
    969 
    970   // Make sure can_close is honored.
    971   ASSERT_NO_FATAL_FAILURE(
    972       PrepareTabstripForSelectionTest(&tabstrip, 1, 0, "0"));
    973   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    974                   0, TabStripModel::CommandCloseTab));
    975   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
    976   ASSERT_TRUE(tabstrip.empty());
    977 
    978   // Make sure close on a tab that is selected affects all the selected tabs.
    979   ASSERT_NO_FATAL_FAILURE(
    980       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    981   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    982                   0, TabStripModel::CommandCloseTab));
    983   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
    984   // Should have closed tabs 0 and 1.
    985   EXPECT_EQ("2", GetTabStripStateString(tabstrip));
    986 
    987   tabstrip.CloseAllTabs();
    988   EXPECT_TRUE(tabstrip.empty());
    989 
    990   // Select two tabs and make close on a tab that isn't selected doesn't affect
    991   // selected tabs.
    992   ASSERT_NO_FATAL_FAILURE(
    993       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
    994   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
    995                   2, TabStripModel::CommandCloseTab));
    996   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab);
    997   // Should have closed tab 2.
    998   EXPECT_EQ("0 1", GetTabStripStateString(tabstrip));
    999   tabstrip.CloseAllTabs();
   1000   EXPECT_TRUE(tabstrip.empty());
   1001 
   1002   // Tests with 3 tabs, one pinned, two tab selected, one of which is pinned.
   1003   ASSERT_NO_FATAL_FAILURE(
   1004       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "0 1"));
   1005   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1006                   0, TabStripModel::CommandCloseTab));
   1007   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTab);
   1008   // Should have closed tab 2.
   1009   EXPECT_EQ("2", GetTabStripStateString(tabstrip));
   1010   tabstrip.CloseAllTabs();
   1011   EXPECT_TRUE(tabstrip.empty());
   1012 }
   1013 
   1014 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
   1015 // CommandCloseTabs.
   1016 TEST_F(TabStripModelTest, CommandCloseOtherTabs) {
   1017   TabStripDummyDelegate delegate;
   1018   TabStripModel tabstrip(&delegate, profile());
   1019   EXPECT_TRUE(tabstrip.empty());
   1020 
   1021   // Create three tabs, select two tabs, CommandCloseOtherTabs should be enabled
   1022   // and close two tabs.
   1023   ASSERT_NO_FATAL_FAILURE(
   1024       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
   1025   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1026                   0, TabStripModel::CommandCloseOtherTabs));
   1027   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs);
   1028   EXPECT_EQ("0 1", GetTabStripStateString(tabstrip));
   1029   tabstrip.CloseAllTabs();
   1030   EXPECT_TRUE(tabstrip.empty());
   1031 
   1032   // Select two tabs, CommandCloseOtherTabs should be enabled and invoking it
   1033   // with a non-selected index should close the two other tabs.
   1034   ASSERT_NO_FATAL_FAILURE(
   1035       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1"));
   1036   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1037                   2, TabStripModel::CommandCloseOtherTabs));
   1038   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseOtherTabs);
   1039   EXPECT_EQ("0 1", GetTabStripStateString(tabstrip));
   1040   tabstrip.CloseAllTabs();
   1041   EXPECT_TRUE(tabstrip.empty());
   1042 
   1043   // Select all, CommandCloseOtherTabs should not be enabled.
   1044   ASSERT_NO_FATAL_FAILURE(
   1045       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "0 1 2"));
   1046   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1047                   2, TabStripModel::CommandCloseOtherTabs));
   1048   tabstrip.CloseAllTabs();
   1049   EXPECT_TRUE(tabstrip.empty());
   1050 
   1051   // Three tabs, pin one, select the two non-pinned.
   1052   ASSERT_NO_FATAL_FAILURE(
   1053       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "1 2"));
   1054   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1055                   1, TabStripModel::CommandCloseOtherTabs));
   1056   // If we don't pass in the pinned index, the command should be enabled.
   1057   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1058                   0, TabStripModel::CommandCloseOtherTabs));
   1059   tabstrip.CloseAllTabs();
   1060   EXPECT_TRUE(tabstrip.empty());
   1061 
   1062   // 3 tabs, one pinned.
   1063   ASSERT_NO_FATAL_FAILURE(
   1064       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "1"));
   1065   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1066                   1, TabStripModel::CommandCloseOtherTabs));
   1067   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1068                   0, TabStripModel::CommandCloseOtherTabs));
   1069   tabstrip.ExecuteContextMenuCommand(1, TabStripModel::CommandCloseOtherTabs);
   1070   // The pinned tab shouldn't be closed.
   1071   EXPECT_EQ("0p 1", GetTabStripStateString(tabstrip));
   1072   tabstrip.CloseAllTabs();
   1073   EXPECT_TRUE(tabstrip.empty());
   1074 }
   1075 
   1076 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
   1077 // CommandCloseTabsToRight.
   1078 TEST_F(TabStripModelTest, CommandCloseTabsToRight) {
   1079   TabStripDummyDelegate delegate;
   1080   TabStripModel tabstrip(&delegate, profile());
   1081   EXPECT_TRUE(tabstrip.empty());
   1082 
   1083   // Create three tabs, select last two tabs, CommandCloseTabsToRight should
   1084   // only be enabled for the first tab.
   1085   ASSERT_NO_FATAL_FAILURE(
   1086       PrepareTabstripForSelectionTest(&tabstrip, 3, 0, "1 2"));
   1087   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1088                   0, TabStripModel::CommandCloseTabsToRight));
   1089   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1090                    1, TabStripModel::CommandCloseTabsToRight));
   1091   EXPECT_FALSE(tabstrip.IsContextMenuCommandEnabled(
   1092                    2, TabStripModel::CommandCloseTabsToRight));
   1093   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight);
   1094   EXPECT_EQ("0", GetTabStripStateString(tabstrip));
   1095   tabstrip.CloseAllTabs();
   1096   EXPECT_TRUE(tabstrip.empty());
   1097 }
   1098 
   1099 // Tests IsContextMenuCommandEnabled and ExecuteContextMenuCommand with
   1100 // CommandTogglePinned.
   1101 TEST_F(TabStripModelTest, CommandTogglePinned) {
   1102   TabStripDummyDelegate delegate;
   1103   TabStripModel tabstrip(&delegate, profile());
   1104   EXPECT_TRUE(tabstrip.empty());
   1105 
   1106   // Create three tabs with one pinned, pin the first two.
   1107   ASSERT_NO_FATAL_FAILURE(
   1108       PrepareTabstripForSelectionTest(&tabstrip, 3, 1, "0 1"));
   1109   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1110                   0, TabStripModel::CommandTogglePinned));
   1111   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1112                   1, TabStripModel::CommandTogglePinned));
   1113   EXPECT_TRUE(tabstrip.IsContextMenuCommandEnabled(
   1114                   2, TabStripModel::CommandTogglePinned));
   1115   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned);
   1116   EXPECT_EQ("0p 1p 2", GetTabStripStateString(tabstrip));
   1117 
   1118   // Execute CommandTogglePinned again, this should unpin.
   1119   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandTogglePinned);
   1120   EXPECT_EQ("0 1 2", GetTabStripStateString(tabstrip));
   1121 
   1122   // Pin the last.
   1123   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandTogglePinned);
   1124   EXPECT_EQ("2p 0 1", GetTabStripStateString(tabstrip));
   1125 
   1126   tabstrip.CloseAllTabs();
   1127   EXPECT_TRUE(tabstrip.empty());
   1128 }
   1129 
   1130 // Tests the following context menu commands:
   1131 //  - Close Tab
   1132 //  - Close Other Tabs
   1133 //  - Close Tabs To Right
   1134 TEST_F(TabStripModelTest, TestContextMenuCloseCommands) {
   1135   TabStripDummyDelegate delegate;
   1136   TabStripModel tabstrip(&delegate, profile());
   1137   EXPECT_TRUE(tabstrip.empty());
   1138 
   1139   WebContents* opener = CreateWebContents();
   1140   tabstrip.AppendWebContents(opener, true);
   1141 
   1142   WebContents* contents1 = CreateWebContents();
   1143   WebContents* contents2 = CreateWebContents();
   1144   WebContents* contents3 = CreateWebContents();
   1145 
   1146   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
   1147   EXPECT_EQ(0, tabstrip.active_index());
   1148 
   1149   tabstrip.ExecuteContextMenuCommand(2, TabStripModel::CommandCloseTab);
   1150   EXPECT_EQ(3, tabstrip.count());
   1151 
   1152   tabstrip.ExecuteContextMenuCommand(0, TabStripModel::CommandCloseTabsToRight);
   1153   EXPECT_EQ(1, tabstrip.count());
   1154   EXPECT_EQ(opener, tabstrip.GetActiveWebContents());
   1155 
   1156   WebContents* dummy = CreateWebContents();
   1157   tabstrip.AppendWebContents(dummy, false);
   1158 
   1159   contents1 = CreateWebContents();
   1160   contents2 = CreateWebContents();
   1161   contents3 = CreateWebContents();
   1162   InsertWebContentses(&tabstrip, contents1, contents2, contents3);
   1163   EXPECT_EQ(5, tabstrip.count());
   1164 
   1165   int dummy_index = tabstrip.count() - 1;
   1166   tabstrip.ActivateTabAt(dummy_index, true);
   1167   EXPECT_EQ(dummy, tabstrip.GetActiveWebContents());
   1168 
   1169   tabstrip.ExecuteContextMenuCommand(dummy_index,
   1170                                      TabStripModel::CommandCloseOtherTabs);
   1171   EXPECT_EQ(1, tabstrip.count());
   1172   EXPECT_EQ(dummy, tabstrip.GetActiveWebContents());
   1173 
   1174   tabstrip.CloseAllTabs();
   1175   EXPECT_TRUE(tabstrip.empty());
   1176 }
   1177 
   1178 // Tests GetIndicesClosedByCommand.
   1179 TEST_F(TabStripModelTest, GetIndicesClosedByCommand) {
   1180   TabStripDummyDelegate delegate;
   1181   TabStripModel tabstrip(&delegate, profile());
   1182   EXPECT_TRUE(tabstrip.empty());
   1183 
   1184   WebContents* contents1 = CreateWebContents();
   1185   WebContents* contents2 = CreateWebContents();
   1186   WebContents* contents3 = CreateWebContents();
   1187   WebContents* contents4 = CreateWebContents();
   1188   WebContents* contents5 = CreateWebContents();
   1189 
   1190   tabstrip.AppendWebContents(contents1, true);
   1191   tabstrip.AppendWebContents(contents2, true);
   1192   tabstrip.AppendWebContents(contents3, true);
   1193   tabstrip.AppendWebContents(contents4, true);
   1194   tabstrip.AppendWebContents(contents5, true);
   1195 
   1196   EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
   1197                 tabstrip, 0, TabStripModel::CommandCloseTabsToRight));
   1198   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1199                 tabstrip, 1, TabStripModel::CommandCloseTabsToRight));
   1200 
   1201   EXPECT_EQ("4 3 2 1", GetIndicesClosedByCommandAsString(
   1202                 tabstrip, 0, TabStripModel::CommandCloseOtherTabs));
   1203   EXPECT_EQ("4 3 2 0", GetIndicesClosedByCommandAsString(
   1204                 tabstrip, 1, TabStripModel::CommandCloseOtherTabs));
   1205 
   1206   // Pin the first two tabs. Pinned tabs shouldn't be closed by the close other
   1207   // commands.
   1208   tabstrip.SetTabPinned(0, true);
   1209   tabstrip.SetTabPinned(1, true);
   1210 
   1211   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1212                 tabstrip, 0, TabStripModel::CommandCloseTabsToRight));
   1213   EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
   1214                 tabstrip, 2, TabStripModel::CommandCloseTabsToRight));
   1215 
   1216   EXPECT_EQ("4 3 2", GetIndicesClosedByCommandAsString(
   1217                 tabstrip, 0, TabStripModel::CommandCloseOtherTabs));
   1218   EXPECT_EQ("4 3", GetIndicesClosedByCommandAsString(
   1219                 tabstrip, 2, TabStripModel::CommandCloseOtherTabs));
   1220 
   1221   tabstrip.CloseAllTabs();
   1222   EXPECT_TRUE(tabstrip.empty());
   1223 }
   1224 
   1225 // Tests whether or not WebContentses are inserted in the correct position
   1226 // using this "smart" function with a simulated middle click action on a series
   1227 // of links on the home page.
   1228 TEST_F(TabStripModelTest, AddWebContents_MiddleClickLinksAndClose) {
   1229   TabStripDummyDelegate delegate;
   1230   TabStripModel tabstrip(&delegate, profile());
   1231   EXPECT_TRUE(tabstrip.empty());
   1232 
   1233   // Open the Home Page.
   1234   WebContents* homepage_contents = CreateWebContents();
   1235   tabstrip.AddWebContents(
   1236       homepage_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1237       TabStripModel::ADD_ACTIVE);
   1238 
   1239   // Open some other tab, by user typing.
   1240   WebContents* typed_page_contents = CreateWebContents();
   1241   tabstrip.AddWebContents(
   1242       typed_page_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1243       TabStripModel::ADD_ACTIVE);
   1244 
   1245   EXPECT_EQ(2, tabstrip.count());
   1246 
   1247   // Re-select the home page.
   1248   tabstrip.ActivateTabAt(0, true);
   1249 
   1250   // Open a bunch of tabs by simulating middle clicking on links on the home
   1251   // page.
   1252   WebContents* middle_click_contents1 = CreateWebContents();
   1253   tabstrip.AddWebContents(
   1254       middle_click_contents1, -1, ui::PAGE_TRANSITION_LINK,
   1255       TabStripModel::ADD_NONE);
   1256   WebContents* middle_click_contents2 = CreateWebContents();
   1257   tabstrip.AddWebContents(
   1258       middle_click_contents2, -1, ui::PAGE_TRANSITION_LINK,
   1259       TabStripModel::ADD_NONE);
   1260   WebContents* middle_click_contents3 = CreateWebContents();
   1261   tabstrip.AddWebContents(
   1262       middle_click_contents3, -1, ui::PAGE_TRANSITION_LINK,
   1263       TabStripModel::ADD_NONE);
   1264 
   1265   EXPECT_EQ(5, tabstrip.count());
   1266 
   1267   EXPECT_EQ(homepage_contents, tabstrip.GetWebContentsAt(0));
   1268   EXPECT_EQ(middle_click_contents1, tabstrip.GetWebContentsAt(1));
   1269   EXPECT_EQ(middle_click_contents2, tabstrip.GetWebContentsAt(2));
   1270   EXPECT_EQ(middle_click_contents3, tabstrip.GetWebContentsAt(3));
   1271   EXPECT_EQ(typed_page_contents, tabstrip.GetWebContentsAt(4));
   1272 
   1273   // Now simulate selecting a tab in the middle of the group of tabs opened from
   1274   // the home page and start closing them. Each WebContents in the group
   1275   // should be closed, right to left. This test is constructed to start at the
   1276   // middle WebContents in the group to make sure the cursor wraps around
   1277   // to the first WebContents in the group before closing the opener or
   1278   // any other WebContents.
   1279   tabstrip.ActivateTabAt(2, true);
   1280   tabstrip.CloseSelectedTabs();
   1281   EXPECT_EQ(middle_click_contents3, tabstrip.GetActiveWebContents());
   1282   tabstrip.CloseSelectedTabs();
   1283   EXPECT_EQ(middle_click_contents1, tabstrip.GetActiveWebContents());
   1284   tabstrip.CloseSelectedTabs();
   1285   EXPECT_EQ(homepage_contents, tabstrip.GetActiveWebContents());
   1286   tabstrip.CloseSelectedTabs();
   1287   EXPECT_EQ(typed_page_contents, tabstrip.GetActiveWebContents());
   1288 
   1289   EXPECT_EQ(1, tabstrip.count());
   1290 
   1291   tabstrip.CloseAllTabs();
   1292   EXPECT_TRUE(tabstrip.empty());
   1293 }
   1294 
   1295 // Tests whether or not a WebContents created by a left click on a link
   1296 // that opens a new tab is inserted correctly adjacent to the tab that spawned
   1297 // it.
   1298 TEST_F(TabStripModelTest, AddWebContents_LeftClickPopup) {
   1299   TabStripDummyDelegate delegate;
   1300   TabStripModel tabstrip(&delegate, profile());
   1301   EXPECT_TRUE(tabstrip.empty());
   1302 
   1303   // Open the Home Page.
   1304   WebContents* homepage_contents = CreateWebContents();
   1305   tabstrip.AddWebContents(
   1306       homepage_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1307       TabStripModel::ADD_ACTIVE);
   1308 
   1309   // Open some other tab, by user typing.
   1310   WebContents* typed_page_contents = CreateWebContents();
   1311   tabstrip.AddWebContents(
   1312       typed_page_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1313       TabStripModel::ADD_ACTIVE);
   1314 
   1315   EXPECT_EQ(2, tabstrip.count());
   1316 
   1317   // Re-select the home page.
   1318   tabstrip.ActivateTabAt(0, true);
   1319 
   1320   // Open a tab by simulating a left click on a link that opens in a new tab.
   1321   WebContents* left_click_contents = CreateWebContents();
   1322   tabstrip.AddWebContents(left_click_contents, -1,
   1323                           ui::PAGE_TRANSITION_LINK,
   1324                           TabStripModel::ADD_ACTIVE);
   1325 
   1326   // Verify the state meets our expectations.
   1327   EXPECT_EQ(3, tabstrip.count());
   1328   EXPECT_EQ(homepage_contents, tabstrip.GetWebContentsAt(0));
   1329   EXPECT_EQ(left_click_contents, tabstrip.GetWebContentsAt(1));
   1330   EXPECT_EQ(typed_page_contents, tabstrip.GetWebContentsAt(2));
   1331 
   1332   // The newly created tab should be selected.
   1333   EXPECT_EQ(left_click_contents, tabstrip.GetActiveWebContents());
   1334 
   1335   // After closing the selected tab, the selection should move to the left, to
   1336   // the opener.
   1337   tabstrip.CloseSelectedTabs();
   1338   EXPECT_EQ(homepage_contents, tabstrip.GetActiveWebContents());
   1339 
   1340   EXPECT_EQ(2, tabstrip.count());
   1341 
   1342   tabstrip.CloseAllTabs();
   1343   EXPECT_TRUE(tabstrip.empty());
   1344 }
   1345 
   1346 // Tests whether or not new tabs that should split context (typed pages,
   1347 // generated urls, also blank tabs) open at the end of the tabstrip instead of
   1348 // in the middle.
   1349 TEST_F(TabStripModelTest, AddWebContents_CreateNewBlankTab) {
   1350   TabStripDummyDelegate delegate;
   1351   TabStripModel tabstrip(&delegate, profile());
   1352   EXPECT_TRUE(tabstrip.empty());
   1353 
   1354   // Open the Home Page.
   1355   WebContents* homepage_contents = CreateWebContents();
   1356   tabstrip.AddWebContents(
   1357       homepage_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1358       TabStripModel::ADD_ACTIVE);
   1359 
   1360   // Open some other tab, by user typing.
   1361   WebContents* typed_page_contents = CreateWebContents();
   1362   tabstrip.AddWebContents(
   1363       typed_page_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1364       TabStripModel::ADD_ACTIVE);
   1365 
   1366   EXPECT_EQ(2, tabstrip.count());
   1367 
   1368   // Re-select the home page.
   1369   tabstrip.ActivateTabAt(0, true);
   1370 
   1371   // Open a new blank tab in the foreground.
   1372   WebContents* new_blank_contents = CreateWebContents();
   1373   tabstrip.AddWebContents(new_blank_contents, -1,
   1374                           ui::PAGE_TRANSITION_TYPED,
   1375                           TabStripModel::ADD_ACTIVE);
   1376 
   1377   // Verify the state of the tabstrip.
   1378   EXPECT_EQ(3, tabstrip.count());
   1379   EXPECT_EQ(homepage_contents, tabstrip.GetWebContentsAt(0));
   1380   EXPECT_EQ(typed_page_contents, tabstrip.GetWebContentsAt(1));
   1381   EXPECT_EQ(new_blank_contents, tabstrip.GetWebContentsAt(2));
   1382 
   1383   // Now open a couple more blank tabs in the background.
   1384   WebContents* background_blank_contents1 = CreateWebContents();
   1385   tabstrip.AddWebContents(
   1386       background_blank_contents1, -1, ui::PAGE_TRANSITION_TYPED,
   1387       TabStripModel::ADD_NONE);
   1388   WebContents* background_blank_contents2 = CreateWebContents();
   1389   tabstrip.AddWebContents(
   1390       background_blank_contents2, -1, ui::PAGE_TRANSITION_GENERATED,
   1391       TabStripModel::ADD_NONE);
   1392   EXPECT_EQ(5, tabstrip.count());
   1393   EXPECT_EQ(homepage_contents, tabstrip.GetWebContentsAt(0));
   1394   EXPECT_EQ(typed_page_contents, tabstrip.GetWebContentsAt(1));
   1395   EXPECT_EQ(new_blank_contents, tabstrip.GetWebContentsAt(2));
   1396   EXPECT_EQ(background_blank_contents1, tabstrip.GetWebContentsAt(3));
   1397   EXPECT_EQ(background_blank_contents2, tabstrip.GetWebContentsAt(4));
   1398 
   1399   tabstrip.CloseAllTabs();
   1400   EXPECT_TRUE(tabstrip.empty());
   1401 }
   1402 
   1403 // Tests whether opener state is correctly forgotten when the user switches
   1404 // context.
   1405 TEST_F(TabStripModelTest, AddWebContents_ForgetOpeners) {
   1406   TabStripDummyDelegate delegate;
   1407   TabStripModel tabstrip(&delegate, profile());
   1408   EXPECT_TRUE(tabstrip.empty());
   1409 
   1410   // Open the Home Page
   1411   WebContents* homepage_contents = CreateWebContents();
   1412   tabstrip.AddWebContents(
   1413       homepage_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1414       TabStripModel::ADD_ACTIVE);
   1415 
   1416   // Open some other tab, by user typing.
   1417   WebContents* typed_page_contents = CreateWebContents();
   1418   tabstrip.AddWebContents(
   1419       typed_page_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1420       TabStripModel::ADD_ACTIVE);
   1421 
   1422   EXPECT_EQ(2, tabstrip.count());
   1423 
   1424   // Re-select the home page.
   1425   tabstrip.ActivateTabAt(0, true);
   1426 
   1427   // Open a bunch of tabs by simulating middle clicking on links on the home
   1428   // page.
   1429   WebContents* middle_click_contents1 = CreateWebContents();
   1430   tabstrip.AddWebContents(
   1431       middle_click_contents1, -1, ui::PAGE_TRANSITION_LINK,
   1432       TabStripModel::ADD_NONE);
   1433   WebContents* middle_click_contents2 = CreateWebContents();
   1434   tabstrip.AddWebContents(
   1435       middle_click_contents2, -1, ui::PAGE_TRANSITION_LINK,
   1436       TabStripModel::ADD_NONE);
   1437   WebContents* middle_click_contents3 = CreateWebContents();
   1438   tabstrip.AddWebContents(
   1439       middle_click_contents3, -1, ui::PAGE_TRANSITION_LINK,
   1440       TabStripModel::ADD_NONE);
   1441 
   1442   // Break out of the context by selecting a tab in a different context.
   1443   EXPECT_EQ(typed_page_contents, tabstrip.GetWebContentsAt(4));
   1444   tabstrip.SelectLastTab();
   1445   EXPECT_EQ(typed_page_contents, tabstrip.GetActiveWebContents());
   1446 
   1447   // Step back into the context by selecting a tab inside it.
   1448   tabstrip.ActivateTabAt(2, true);
   1449   EXPECT_EQ(middle_click_contents2, tabstrip.GetActiveWebContents());
   1450 
   1451   // Now test that closing tabs selects to the right until there are no more,
   1452   // then to the left, as if there were no context (context has been
   1453   // successfully forgotten).
   1454   tabstrip.CloseSelectedTabs();
   1455   EXPECT_EQ(middle_click_contents3, tabstrip.GetActiveWebContents());
   1456   tabstrip.CloseSelectedTabs();
   1457   EXPECT_EQ(typed_page_contents, tabstrip.GetActiveWebContents());
   1458   tabstrip.CloseSelectedTabs();
   1459   EXPECT_EQ(middle_click_contents1, tabstrip.GetActiveWebContents());
   1460   tabstrip.CloseSelectedTabs();
   1461   EXPECT_EQ(homepage_contents, tabstrip.GetActiveWebContents());
   1462 
   1463   EXPECT_EQ(1, tabstrip.count());
   1464 
   1465   tabstrip.CloseAllTabs();
   1466   EXPECT_TRUE(tabstrip.empty());
   1467 }
   1468 
   1469 // Added for http://b/issue?id=958960
   1470 TEST_F(TabStripModelTest, AppendContentsReselectionTest) {
   1471   TabStripDummyDelegate delegate;
   1472   TabStripModel tabstrip(&delegate, profile());
   1473   EXPECT_TRUE(tabstrip.empty());
   1474 
   1475   // Open the Home Page.
   1476   WebContents* homepage_contents = CreateWebContents();
   1477   tabstrip.AddWebContents(
   1478       homepage_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1479       TabStripModel::ADD_ACTIVE);
   1480 
   1481   // Open some other tab, by user typing.
   1482   WebContents* typed_page_contents = CreateWebContents();
   1483   tabstrip.AddWebContents(
   1484       typed_page_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1485       TabStripModel::ADD_NONE);
   1486 
   1487   // The selected tab should still be the first.
   1488   EXPECT_EQ(0, tabstrip.active_index());
   1489 
   1490   // Now simulate a link click that opens a new tab (by virtue of target=_blank)
   1491   // and make sure the correct tab gets selected when the new tab is closed.
   1492   WebContents* target_blank = CreateWebContents();
   1493   tabstrip.AppendWebContents(target_blank, true);
   1494   EXPECT_EQ(2, tabstrip.active_index());
   1495   tabstrip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE);
   1496   EXPECT_EQ(0, tabstrip.active_index());
   1497 
   1498   // Clean up after ourselves.
   1499   tabstrip.CloseAllTabs();
   1500 }
   1501 
   1502 // Added for http://b/issue?id=1027661
   1503 TEST_F(TabStripModelTest, ReselectionConsidersChildrenTest) {
   1504   TabStripDummyDelegate delegate;
   1505   TabStripModel strip(&delegate, profile());
   1506 
   1507   // Open page A
   1508   WebContents* page_a_contents = CreateWebContents();
   1509   strip.AddWebContents(
   1510       page_a_contents, -1, ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1511       TabStripModel::ADD_ACTIVE);
   1512 
   1513   // Simulate middle click to open page A.A and A.B
   1514   WebContents* page_a_a_contents = CreateWebContents();
   1515   strip.AddWebContents(page_a_a_contents, -1, ui::PAGE_TRANSITION_LINK,
   1516                        TabStripModel::ADD_NONE);
   1517   WebContents* page_a_b_contents = CreateWebContents();
   1518   strip.AddWebContents(page_a_b_contents, -1, ui::PAGE_TRANSITION_LINK,
   1519                        TabStripModel::ADD_NONE);
   1520 
   1521   // Select page A.A
   1522   strip.ActivateTabAt(1, true);
   1523   EXPECT_EQ(page_a_a_contents, strip.GetActiveWebContents());
   1524 
   1525   // Simulate a middle click to open page A.A.A
   1526   WebContents* page_a_a_a_contents = CreateWebContents();
   1527   strip.AddWebContents(page_a_a_a_contents, -1, ui::PAGE_TRANSITION_LINK,
   1528                        TabStripModel::ADD_NONE);
   1529 
   1530   EXPECT_EQ(page_a_a_a_contents, strip.GetWebContentsAt(2));
   1531 
   1532   // Close page A.A
   1533   strip.CloseWebContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1534 
   1535   // Page A.A.A should be selected, NOT A.B
   1536   EXPECT_EQ(page_a_a_a_contents, strip.GetActiveWebContents());
   1537 
   1538   // Close page A.A.A
   1539   strip.CloseWebContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1540 
   1541   // Page A.B should be selected
   1542   EXPECT_EQ(page_a_b_contents, strip.GetActiveWebContents());
   1543 
   1544   // Close page A.B
   1545   strip.CloseWebContentsAt(strip.active_index(), TabStripModel::CLOSE_NONE);
   1546 
   1547   // Page A should be selected
   1548   EXPECT_EQ(page_a_contents, strip.GetActiveWebContents());
   1549 
   1550   // Clean up.
   1551   strip.CloseAllTabs();
   1552 }
   1553 
   1554 TEST_F(TabStripModelTest, AddWebContents_NewTabAtEndOfStripInheritsGroup) {
   1555   TabStripDummyDelegate delegate;
   1556   TabStripModel strip(&delegate, profile());
   1557 
   1558   // Open page A
   1559   WebContents* page_a_contents = CreateWebContents();
   1560   strip.AddWebContents(page_a_contents, -1,
   1561                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   1562                        TabStripModel::ADD_ACTIVE);
   1563 
   1564   // Open pages B, C and D in the background from links on page A...
   1565   WebContents* page_b_contents = CreateWebContents();
   1566   WebContents* page_c_contents = CreateWebContents();
   1567   WebContents* page_d_contents = CreateWebContents();
   1568   strip.AddWebContents(page_b_contents, -1, ui::PAGE_TRANSITION_LINK,
   1569                        TabStripModel::ADD_NONE);
   1570   strip.AddWebContents(page_c_contents, -1, ui::PAGE_TRANSITION_LINK,
   1571                        TabStripModel::ADD_NONE);
   1572   strip.AddWebContents(page_d_contents, -1, ui::PAGE_TRANSITION_LINK,
   1573                        TabStripModel::ADD_NONE);
   1574 
   1575   // Switch to page B's tab.
   1576   strip.ActivateTabAt(1, true);
   1577 
   1578   // Open a New Tab at the end of the strip (simulate Ctrl+T)
   1579   WebContents* new_contents = CreateWebContents();
   1580   strip.AddWebContents(new_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1581                        TabStripModel::ADD_ACTIVE);
   1582 
   1583   EXPECT_EQ(4, strip.GetIndexOfWebContents(new_contents));
   1584   EXPECT_EQ(4, strip.active_index());
   1585 
   1586   // Close the New Tab that was just opened. We should be returned to page B's
   1587   // Tab...
   1588   strip.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE);
   1589 
   1590   EXPECT_EQ(1, strip.active_index());
   1591 
   1592   // Open a non-New Tab tab at the end of the strip, with a TYPED transition.
   1593   // This is like typing a URL in the address bar and pressing Alt+Enter. The
   1594   // behavior should be the same as above.
   1595   WebContents* page_e_contents = CreateWebContents();
   1596   strip.AddWebContents(page_e_contents, -1, ui::PAGE_TRANSITION_TYPED,
   1597                        TabStripModel::ADD_ACTIVE);
   1598 
   1599   EXPECT_EQ(4, strip.GetIndexOfWebContents(page_e_contents));
   1600   EXPECT_EQ(4, strip.active_index());
   1601 
   1602   // Close the Tab. Selection should shift back to page B's Tab.
   1603   strip.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE);
   1604 
   1605   EXPECT_EQ(1, strip.active_index());
   1606 
   1607   // Open a non-New Tab tab at the end of the strip, with some other
   1608   // transition. This is like right clicking on a bookmark and choosing "Open
   1609   // in New Tab". No opener relationship should be preserved between this Tab
   1610   // and the one that was active when the gesture was performed.
   1611   WebContents* page_f_contents = CreateWebContents();
   1612   strip.AddWebContents(page_f_contents, -1,
   1613                        ui::PAGE_TRANSITION_AUTO_BOOKMARK,
   1614                        TabStripModel::ADD_ACTIVE);
   1615 
   1616   EXPECT_EQ(4, strip.GetIndexOfWebContents(page_f_contents));
   1617   EXPECT_EQ(4, strip.active_index());
   1618 
   1619   // Close the Tab. The next-adjacent should be selected.
   1620   strip.CloseWebContentsAt(4, TabStripModel::CLOSE_NONE);
   1621 
   1622   EXPECT_EQ(3, strip.active_index());
   1623 
   1624   // Clean up.
   1625   strip.CloseAllTabs();
   1626 }
   1627 
   1628 // A test of navigations in a tab that is part of a group of opened from some
   1629 // parent tab. If the navigations are link clicks, the group relationship of
   1630 // the tab to its parent are preserved. If they are of any other type, they are
   1631 // not preserved.
   1632 TEST_F(TabStripModelTest, NavigationForgetsOpeners) {
   1633   TabStripDummyDelegate delegate;
   1634   TabStripModel strip(&delegate, profile());
   1635 
   1636   // Open page A
   1637   WebContents* page_a_contents = CreateWebContents();
   1638   strip.AddWebContents(page_a_contents, -1,
   1639                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   1640                        TabStripModel::ADD_ACTIVE);
   1641 
   1642   // Open pages B, C and D in the background from links on page A...
   1643   WebContents* page_b_contents = CreateWebContents();
   1644   WebContents* page_c_contents = CreateWebContents();
   1645   WebContents* page_d_contents = CreateWebContents();
   1646   strip.AddWebContents(page_b_contents, -1, ui::PAGE_TRANSITION_LINK,
   1647                        TabStripModel::ADD_NONE);
   1648   strip.AddWebContents(page_c_contents, -1, ui::PAGE_TRANSITION_LINK,
   1649                        TabStripModel::ADD_NONE);
   1650   strip.AddWebContents(page_d_contents, -1, ui::PAGE_TRANSITION_LINK,
   1651                        TabStripModel::ADD_NONE);
   1652 
   1653   // Open page E in a different opener group from page A.
   1654   WebContents* page_e_contents = CreateWebContents();
   1655   strip.AddWebContents(page_e_contents, -1,
   1656                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   1657                        TabStripModel::ADD_NONE);
   1658 
   1659   // Tell the TabStripModel that we are navigating page D via a link click.
   1660   strip.ActivateTabAt(3, true);
   1661   strip.TabNavigating(page_d_contents, ui::PAGE_TRANSITION_LINK);
   1662 
   1663   // Close page D, page C should be selected. (part of same group).
   1664   strip.CloseWebContentsAt(3, TabStripModel::CLOSE_NONE);
   1665   EXPECT_EQ(2, strip.active_index());
   1666 
   1667   // Tell the TabStripModel that we are navigating in page C via a bookmark.
   1668   strip.TabNavigating(page_c_contents, ui::PAGE_TRANSITION_AUTO_BOOKMARK);
   1669 
   1670   // Close page C, page E should be selected. (C is no longer part of the
   1671   // A-B-C-D group, selection moves to the right).
   1672   strip.CloseWebContentsAt(2, TabStripModel::CLOSE_NONE);
   1673   EXPECT_EQ(page_e_contents, strip.GetWebContentsAt(strip.active_index()));
   1674 
   1675   strip.CloseAllTabs();
   1676 }
   1677 
   1678 // A test that the forgetting behavior tested in NavigationForgetsOpeners above
   1679 // doesn't cause the opener relationship for a New Tab opened at the end of the
   1680 // TabStrip to be reset (Test 1 below), unless another any other tab is
   1681 // selected (Test 2 below).
   1682 TEST_F(TabStripModelTest, NavigationForgettingDoesntAffectNewTab) {
   1683   TabStripDummyDelegate delegate;
   1684   TabStripModel strip(&delegate, profile());
   1685 
   1686   // Open a tab and several tabs from it, then select one of the tabs that was
   1687   // opened.
   1688   WebContents* page_a_contents = CreateWebContents();
   1689   strip.AddWebContents(page_a_contents, -1,
   1690                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   1691                        TabStripModel::ADD_ACTIVE);
   1692 
   1693   WebContents* page_b_contents = CreateWebContents();
   1694   WebContents* page_c_contents = CreateWebContents();
   1695   WebContents* page_d_contents = CreateWebContents();
   1696   strip.AddWebContents(page_b_contents, -1, ui::PAGE_TRANSITION_LINK,
   1697                        TabStripModel::ADD_NONE);
   1698   strip.AddWebContents(page_c_contents, -1, ui::PAGE_TRANSITION_LINK,
   1699                        TabStripModel::ADD_NONE);
   1700   strip.AddWebContents(page_d_contents, -1, ui::PAGE_TRANSITION_LINK,
   1701                        TabStripModel::ADD_NONE);
   1702 
   1703   strip.ActivateTabAt(2, true);
   1704 
   1705   // TEST 1: If the user is in a group of tabs and opens a new tab at the end
   1706   // of the strip, closing that new tab will select the tab that they were
   1707   // last on.
   1708 
   1709   // Now simulate opening a new tab at the end of the TabStrip.
   1710   WebContents* new_contents1 = CreateWebContents();
   1711   strip.AddWebContents(new_contents1, -1, ui::PAGE_TRANSITION_TYPED,
   1712                        TabStripModel::ADD_ACTIVE);
   1713 
   1714   // At this point, if we close this tab the last selected one should be
   1715   // re-selected.
   1716   strip.CloseWebContentsAt(strip.count() - 1, TabStripModel::CLOSE_NONE);
   1717   EXPECT_EQ(page_c_contents, strip.GetWebContentsAt(strip.active_index()));
   1718 
   1719   // TEST 2: If the user is in a group of tabs and opens a new tab at the end
   1720   // of the strip, selecting any other tab in the strip will cause that new
   1721   // tab's opener relationship to be forgotten.
   1722 
   1723   // Open a new tab again.
   1724   WebContents* new_contents2 = CreateWebContents();
   1725   strip.AddWebContents(new_contents2, -1, ui::PAGE_TRANSITION_TYPED,
   1726                        TabStripModel::ADD_ACTIVE);
   1727 
   1728   // Now select the first tab.
   1729   strip.ActivateTabAt(0, true);
   1730 
   1731   // Now select the last tab.
   1732   strip.ActivateTabAt(strip.count() - 1, true);
   1733 
   1734   // Now close the last tab. The next adjacent should be selected.
   1735   strip.CloseWebContentsAt(strip.count() - 1, TabStripModel::CLOSE_NONE);
   1736   EXPECT_EQ(page_d_contents, strip.GetWebContentsAt(strip.active_index()));
   1737 
   1738   strip.CloseAllTabs();
   1739 }
   1740 
   1741 // This fails on Linux when run with the rest of unit_tests (crbug.com/302156)
   1742 // and fails consistently on Mac and Windows.
   1743 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
   1744 #define MAYBE_FastShutdown \
   1745     DISABLED_FastShutdown
   1746 #else
   1747 #define MAYBE_FastShutdown \
   1748     FastShutdown
   1749 #endif
   1750 // Tests that fast shutdown is attempted appropriately.
   1751 TEST_F(TabStripModelTest, MAYBE_FastShutdown) {
   1752   TabStripDummyDelegate delegate;
   1753   TabStripModel tabstrip(&delegate, profile());
   1754   MockTabStripModelObserver observer(&tabstrip);
   1755   tabstrip.AddObserver(&observer);
   1756 
   1757   EXPECT_TRUE(tabstrip.empty());
   1758 
   1759   // Make sure fast shutdown is attempted when tabs that share a RPH are shut
   1760   // down.
   1761   {
   1762     WebContents* contents1 = CreateWebContents();
   1763     WebContents* contents2 = CreateWebContentsWithSharedRPH(contents1);
   1764 
   1765     SetID(contents1, 1);
   1766     SetID(contents2, 2);
   1767 
   1768     tabstrip.AppendWebContents(contents1, true);
   1769     tabstrip.AppendWebContents(contents2, true);
   1770 
   1771     // Turn on the fake unload listener so the tabs don't actually get shut
   1772     // down when we call CloseAllTabs()---we need to be able to check that
   1773     // fast shutdown was attempted.
   1774     delegate.set_run_unload_listener(true);
   1775     tabstrip.CloseAllTabs();
   1776     // On a mock RPH this checks whether we *attempted* fast shutdown.
   1777     // A real RPH would reject our attempt since there is an unload handler.
   1778     EXPECT_TRUE(contents1->GetRenderProcessHost()->FastShutdownStarted());
   1779     EXPECT_EQ(2, tabstrip.count());
   1780 
   1781     delegate.set_run_unload_listener(false);
   1782     tabstrip.CloseAllTabs();
   1783     EXPECT_TRUE(tabstrip.empty());
   1784   }
   1785 
   1786   // Make sure fast shutdown is not attempted when only some tabs that share a
   1787   // RPH are shut down.
   1788   {
   1789     WebContents* contents1 = CreateWebContents();
   1790     WebContents* contents2 = CreateWebContentsWithSharedRPH(contents1);
   1791 
   1792     SetID(contents1, 1);
   1793     SetID(contents2, 2);
   1794 
   1795     tabstrip.AppendWebContents(contents1, true);
   1796     tabstrip.AppendWebContents(contents2, true);
   1797 
   1798     tabstrip.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
   1799     EXPECT_FALSE(contents1->GetRenderProcessHost()->FastShutdownStarted());
   1800     EXPECT_EQ(1, tabstrip.count());
   1801 
   1802     tabstrip.CloseAllTabs();
   1803     EXPECT_TRUE(tabstrip.empty());
   1804   }
   1805 }
   1806 
   1807 // Tests various permutations of apps.
   1808 TEST_F(TabStripModelTest, Apps) {
   1809   TabStripDummyDelegate delegate;
   1810   TabStripModel tabstrip(&delegate, profile());
   1811   MockTabStripModelObserver observer(&tabstrip);
   1812   tabstrip.AddObserver(&observer);
   1813 
   1814   EXPECT_TRUE(tabstrip.empty());
   1815 
   1816   typedef MockTabStripModelObserver::State State;
   1817 
   1818 #if defined(OS_WIN)
   1819   base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
   1820 #elif defined(OS_POSIX)
   1821   base::FilePath path(FILE_PATH_LITERAL("/foo"));
   1822 #endif
   1823 
   1824   base::DictionaryValue manifest;
   1825   manifest.SetString("name", "hi!");
   1826   manifest.SetString("version", "1");
   1827   manifest.SetString("app.launch.web_url", "http://www.google.com");
   1828   std::string error;
   1829   scoped_refptr<Extension> extension_app(
   1830       Extension::Create(path, extensions::Manifest::INVALID_LOCATION,
   1831                         manifest, Extension::NO_FLAGS, &error));
   1832   WebContents* contents1 = CreateWebContents();
   1833   extensions::TabHelper::CreateForWebContents(contents1);
   1834   extensions::TabHelper::FromWebContents(contents1)
   1835       ->SetExtensionApp(extension_app.get());
   1836   WebContents* contents2 = CreateWebContents();
   1837   extensions::TabHelper::CreateForWebContents(contents2);
   1838   extensions::TabHelper::FromWebContents(contents2)
   1839       ->SetExtensionApp(extension_app.get());
   1840   WebContents* contents3 = CreateWebContents();
   1841 
   1842   SetID(contents1, 1);
   1843   SetID(contents2, 2);
   1844   SetID(contents3, 3);
   1845 
   1846   // Note! The ordering of these tests is important, each subsequent test
   1847   // builds on the state established in the previous. This is important if you
   1848   // ever insert tests rather than append.
   1849 
   1850   // Initial state, tab3 only and selected.
   1851   tabstrip.AppendWebContents(contents3, true);
   1852 
   1853   observer.ClearStates();
   1854 
   1855   // Attempt to insert tab1 (an app tab) at position 1. This isn't a legal
   1856   // position and tab1 should end up at position 0.
   1857   {
   1858     tabstrip.InsertWebContentsAt(1, contents1, TabStripModel::ADD_NONE);
   1859 
   1860     ASSERT_EQ(1, observer.GetStateCount());
   1861     State state(contents1, 0, MockTabStripModelObserver::INSERT);
   1862     EXPECT_TRUE(observer.StateEquals(0, state));
   1863 
   1864     // And verify the state.
   1865     EXPECT_EQ("1ap 3", GetTabStripStateString(tabstrip));
   1866 
   1867     observer.ClearStates();
   1868   }
   1869 
   1870   // Insert tab 2 at position 1.
   1871   {
   1872     tabstrip.InsertWebContentsAt(1, contents2, TabStripModel::ADD_NONE);
   1873 
   1874     ASSERT_EQ(1, observer.GetStateCount());
   1875     State state(contents2, 1, MockTabStripModelObserver::INSERT);
   1876     EXPECT_TRUE(observer.StateEquals(0, state));
   1877 
   1878     // And verify the state.
   1879     EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip));
   1880 
   1881     observer.ClearStates();
   1882   }
   1883 
   1884   // Try to move tab 3 to position 0. This isn't legal and should be ignored.
   1885   {
   1886     tabstrip.MoveWebContentsAt(2, 0, false);
   1887 
   1888     ASSERT_EQ(0, observer.GetStateCount());
   1889 
   1890     // And verify the state didn't change.
   1891     EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip));
   1892 
   1893     observer.ClearStates();
   1894   }
   1895 
   1896   // Try to move tab 0 to position 3. This isn't legal and should be ignored.
   1897   {
   1898     tabstrip.MoveWebContentsAt(0, 2, false);
   1899 
   1900     ASSERT_EQ(0, observer.GetStateCount());
   1901 
   1902     // And verify the state didn't change.
   1903     EXPECT_EQ("1ap 2ap 3", GetTabStripStateString(tabstrip));
   1904 
   1905     observer.ClearStates();
   1906   }
   1907 
   1908   // Try to move tab 0 to position 1. This is a legal move.
   1909   {
   1910     tabstrip.MoveWebContentsAt(0, 1, false);
   1911 
   1912     ASSERT_EQ(1, observer.GetStateCount());
   1913     State state(contents1, 1, MockTabStripModelObserver::MOVE);
   1914     state.src_index = 0;
   1915     EXPECT_TRUE(observer.StateEquals(0, state));
   1916 
   1917     // And verify the state didn't change.
   1918     EXPECT_EQ("2ap 1ap 3", GetTabStripStateString(tabstrip));
   1919 
   1920     observer.ClearStates();
   1921   }
   1922 
   1923   // Remove tab3 and insert at position 0. It should be forced to position 2.
   1924   {
   1925     tabstrip.DetachWebContentsAt(2);
   1926     observer.ClearStates();
   1927 
   1928     tabstrip.InsertWebContentsAt(0, contents3, TabStripModel::ADD_NONE);
   1929 
   1930     ASSERT_EQ(1, observer.GetStateCount());
   1931     State state(contents3, 2, MockTabStripModelObserver::INSERT);
   1932     EXPECT_TRUE(observer.StateEquals(0, state));
   1933 
   1934     // And verify the state didn't change.
   1935     EXPECT_EQ("2ap 1ap 3", GetTabStripStateString(tabstrip));
   1936 
   1937     observer.ClearStates();
   1938   }
   1939 
   1940   tabstrip.CloseAllTabs();
   1941 }
   1942 
   1943 // Tests various permutations of pinning tabs.
   1944 TEST_F(TabStripModelTest, Pinning) {
   1945   TabStripDummyDelegate delegate;
   1946   TabStripModel tabstrip(&delegate, profile());
   1947   MockTabStripModelObserver observer(&tabstrip);
   1948   tabstrip.AddObserver(&observer);
   1949 
   1950   EXPECT_TRUE(tabstrip.empty());
   1951 
   1952   typedef MockTabStripModelObserver::State State;
   1953 
   1954   WebContents* contents1 = CreateWebContents();
   1955   WebContents* contents2 = CreateWebContents();
   1956   WebContents* contents3 = CreateWebContents();
   1957 
   1958   SetID(contents1, 1);
   1959   SetID(contents2, 2);
   1960   SetID(contents3, 3);
   1961 
   1962   // Note! The ordering of these tests is important, each subsequent test
   1963   // builds on the state established in the previous. This is important if you
   1964   // ever insert tests rather than append.
   1965 
   1966   // Initial state, three tabs, first selected.
   1967   tabstrip.AppendWebContents(contents1, true);
   1968   tabstrip.AppendWebContents(contents2, false);
   1969   tabstrip.AppendWebContents(contents3, false);
   1970 
   1971   observer.ClearStates();
   1972 
   1973   // Pin the first tab, this shouldn't visually reorder anything.
   1974   {
   1975     tabstrip.SetTabPinned(0, true);
   1976 
   1977     // As the order didn't change, we should get a pinned notification.
   1978     ASSERT_EQ(1, observer.GetStateCount());
   1979     State state(contents1, 0, MockTabStripModelObserver::PINNED);
   1980     EXPECT_TRUE(observer.StateEquals(0, state));
   1981 
   1982     // And verify the state.
   1983     EXPECT_EQ("1p 2 3", GetTabStripStateString(tabstrip));
   1984 
   1985     observer.ClearStates();
   1986   }
   1987 
   1988   // Unpin the first tab.
   1989   {
   1990     tabstrip.SetTabPinned(0, false);
   1991 
   1992     // As the order didn't change, we should get a pinned notification.
   1993     ASSERT_EQ(1, observer.GetStateCount());
   1994     State state(contents1, 0, MockTabStripModelObserver::PINNED);
   1995     EXPECT_TRUE(observer.StateEquals(0, state));
   1996 
   1997     // And verify the state.
   1998     EXPECT_EQ("1 2 3", GetTabStripStateString(tabstrip));
   1999 
   2000     observer.ClearStates();
   2001   }
   2002 
   2003   // Pin the 3rd tab, which should move it to the front.
   2004   {
   2005     tabstrip.SetTabPinned(2, true);
   2006 
   2007     // The pinning should have resulted in a move and a pinned notification.
   2008     ASSERT_EQ(2, observer.GetStateCount());
   2009     State state(contents3, 0, MockTabStripModelObserver::MOVE);
   2010     state.src_index = 2;
   2011     EXPECT_TRUE(observer.StateEquals(0, state));
   2012 
   2013     state = State(contents3, 0, MockTabStripModelObserver::PINNED);
   2014     EXPECT_TRUE(observer.StateEquals(1, state));
   2015 
   2016     // And verify the state.
   2017     EXPECT_EQ("3p 1 2", GetTabStripStateString(tabstrip));
   2018 
   2019     observer.ClearStates();
   2020   }
   2021 
   2022   // Pin the tab "1", which shouldn't move anything.
   2023   {
   2024     tabstrip.SetTabPinned(1, true);
   2025 
   2026     // As the order didn't change, we should get a pinned notification.
   2027     ASSERT_EQ(1, observer.GetStateCount());
   2028     State state(contents1, 1, MockTabStripModelObserver::PINNED);
   2029     EXPECT_TRUE(observer.StateEquals(0, state));
   2030 
   2031     // And verify the state.
   2032     EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip));
   2033 
   2034     observer.ClearStates();
   2035   }
   2036 
   2037   // Try to move tab "2" to the front, it should be ignored.
   2038   {
   2039     tabstrip.MoveWebContentsAt(2, 0, false);
   2040 
   2041     // As the order didn't change, we should get a pinned notification.
   2042     ASSERT_EQ(0, observer.GetStateCount());
   2043 
   2044     // And verify the state.
   2045     EXPECT_EQ("3p 1p 2", GetTabStripStateString(tabstrip));
   2046 
   2047     observer.ClearStates();
   2048   }
   2049 
   2050   // Unpin tab "3", which implicitly moves it to the end.
   2051   {
   2052     tabstrip.SetTabPinned(0, false);
   2053 
   2054     ASSERT_EQ(2, observer.GetStateCount());
   2055     State state(contents3, 1, MockTabStripModelObserver::MOVE);
   2056     state.src_index = 0;
   2057     EXPECT_TRUE(observer.StateEquals(0, state));
   2058 
   2059     state = State(contents3, 1, MockTabStripModelObserver::PINNED);
   2060     EXPECT_TRUE(observer.StateEquals(1, state));
   2061 
   2062     // And verify the state.
   2063     EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip));
   2064 
   2065     observer.ClearStates();
   2066   }
   2067 
   2068   // Unpin tab "3", nothing should happen.
   2069   {
   2070     tabstrip.SetTabPinned(1, false);
   2071 
   2072     ASSERT_EQ(0, observer.GetStateCount());
   2073 
   2074     EXPECT_EQ("1p 3 2", GetTabStripStateString(tabstrip));
   2075 
   2076     observer.ClearStates();
   2077   }
   2078 
   2079   // Pin "3" and "1".
   2080   {
   2081     tabstrip.SetTabPinned(0, true);
   2082     tabstrip.SetTabPinned(1, true);
   2083 
   2084     EXPECT_EQ("1p 3p 2", GetTabStripStateString(tabstrip));
   2085 
   2086     observer.ClearStates();
   2087   }
   2088 
   2089   WebContents* contents4 = CreateWebContents();
   2090   SetID(contents4, 4);
   2091 
   2092   // Insert "4" between "1" and "3". As "1" and "4" are pinned, "4" should end
   2093   // up after them.
   2094   {
   2095     tabstrip.InsertWebContentsAt(1, contents4, TabStripModel::ADD_NONE);
   2096 
   2097     ASSERT_EQ(1, observer.GetStateCount());
   2098     State state(contents4, 2, MockTabStripModelObserver::INSERT);
   2099     EXPECT_TRUE(observer.StateEquals(0, state));
   2100 
   2101     EXPECT_EQ("1p 3p 4 2", GetTabStripStateString(tabstrip));
   2102   }
   2103 
   2104   tabstrip.CloseAllTabs();
   2105 }
   2106 
   2107 // Makes sure the TabStripModel calls the right observer methods during a
   2108 // replace.
   2109 TEST_F(TabStripModelTest, ReplaceSendsSelected) {
   2110   typedef MockTabStripModelObserver::State State;
   2111 
   2112   TabStripDummyDelegate delegate;
   2113   TabStripModel strip(&delegate, profile());
   2114 
   2115   WebContents* first_contents = CreateWebContents();
   2116   strip.AddWebContents(first_contents, -1, ui::PAGE_TRANSITION_TYPED,
   2117                        TabStripModel::ADD_ACTIVE);
   2118 
   2119   MockTabStripModelObserver tabstrip_observer(&strip);
   2120   strip.AddObserver(&tabstrip_observer);
   2121 
   2122   WebContents* new_contents = CreateWebContents();
   2123   delete strip.ReplaceWebContentsAt(0, new_contents);
   2124 
   2125   ASSERT_EQ(2, tabstrip_observer.GetStateCount());
   2126 
   2127   // First event should be for replaced.
   2128   State state(new_contents, 0, MockTabStripModelObserver::REPLACED);
   2129   state.src_contents = first_contents;
   2130   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
   2131 
   2132   // And the second for selected.
   2133   state = State(new_contents, 0, MockTabStripModelObserver::ACTIVATE);
   2134   state.src_contents = first_contents;
   2135   state.change_reason = TabStripModelObserver::CHANGE_REASON_REPLACED;
   2136   EXPECT_TRUE(tabstrip_observer.StateEquals(1, state));
   2137 
   2138   // Now add another tab and replace it, making sure we don't get a selected
   2139   // event this time.
   2140   WebContents* third_contents = CreateWebContents();
   2141   strip.AddWebContents(third_contents, 1, ui::PAGE_TRANSITION_TYPED,
   2142                        TabStripModel::ADD_NONE);
   2143 
   2144   tabstrip_observer.ClearStates();
   2145 
   2146   // And replace it.
   2147   new_contents = CreateWebContents();
   2148   delete strip.ReplaceWebContentsAt(1, new_contents);
   2149 
   2150   ASSERT_EQ(1, tabstrip_observer.GetStateCount());
   2151 
   2152   state = State(new_contents, 1, MockTabStripModelObserver::REPLACED);
   2153   state.src_contents = third_contents;
   2154   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state));
   2155 
   2156   strip.CloseAllTabs();
   2157 }
   2158 
   2159 // Ensures discarding tabs leaves TabStripModel in a good state.
   2160 TEST_F(TabStripModelTest, DiscardWebContentsAt) {
   2161   typedef MockTabStripModelObserver::State State;
   2162 
   2163   TabStripDummyDelegate delegate;
   2164   TabStripModel tabstrip(&delegate, profile());
   2165 
   2166   // Fill it with some tabs.
   2167   WebContents* contents1 = CreateWebContents();
   2168   tabstrip.AppendWebContents(contents1, true);
   2169   WebContents* contents2 = CreateWebContents();
   2170   tabstrip.AppendWebContents(contents2, true);
   2171 
   2172   // Start watching for events after the appends to avoid observing state
   2173   // transitions that aren't relevant to this test.
   2174   MockTabStripModelObserver tabstrip_observer(&tabstrip);
   2175   tabstrip.AddObserver(&tabstrip_observer);
   2176 
   2177   // Discard one of the tabs.
   2178   WebContents* null_contents1 = tabstrip.DiscardWebContentsAt(0);
   2179   ASSERT_EQ(2, tabstrip.count());
   2180   EXPECT_TRUE(tabstrip.IsTabDiscarded(0));
   2181   EXPECT_FALSE(tabstrip.IsTabDiscarded(1));
   2182   ASSERT_EQ(null_contents1, tabstrip.GetWebContentsAt(0));
   2183   ASSERT_EQ(contents2, tabstrip.GetWebContentsAt(1));
   2184   ASSERT_EQ(1, tabstrip_observer.GetStateCount());
   2185   State state1(null_contents1, 0, MockTabStripModelObserver::REPLACED);
   2186   state1.src_contents = contents1;
   2187   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state1));
   2188   tabstrip_observer.ClearStates();
   2189 
   2190   // Discard the same tab again.
   2191   WebContents* null_contents2 = tabstrip.DiscardWebContentsAt(0);
   2192   ASSERT_EQ(2, tabstrip.count());
   2193   EXPECT_TRUE(tabstrip.IsTabDiscarded(0));
   2194   EXPECT_FALSE(tabstrip.IsTabDiscarded(1));
   2195   ASSERT_EQ(null_contents2, tabstrip.GetWebContentsAt(0));
   2196   ASSERT_EQ(contents2, tabstrip.GetWebContentsAt(1));
   2197   ASSERT_EQ(1, tabstrip_observer.GetStateCount());
   2198   State state2(null_contents2, 0, MockTabStripModelObserver::REPLACED);
   2199   state2.src_contents = null_contents1;
   2200   EXPECT_TRUE(tabstrip_observer.StateEquals(0, state2));
   2201   tabstrip_observer.ClearStates();
   2202 
   2203   // Activating the tab should clear its discard state.
   2204   tabstrip.ActivateTabAt(0, true /* user_gesture */);
   2205   ASSERT_EQ(2, tabstrip.count());
   2206   EXPECT_FALSE(tabstrip.IsTabDiscarded(0));
   2207   EXPECT_FALSE(tabstrip.IsTabDiscarded(1));
   2208 
   2209   // Don't discard active tab.
   2210   tabstrip.DiscardWebContentsAt(0);
   2211   ASSERT_EQ(2, tabstrip.count());
   2212   EXPECT_FALSE(tabstrip.IsTabDiscarded(0));
   2213   EXPECT_FALSE(tabstrip.IsTabDiscarded(1));
   2214 
   2215   tabstrip.CloseAllTabs();
   2216 }
   2217 
   2218 // Makes sure TabStripModel handles the case of deleting a tab while removing
   2219 // another tab.
   2220 TEST_F(TabStripModelTest, DeleteFromDestroy) {
   2221   TabStripDummyDelegate delegate;
   2222   TabStripModel strip(&delegate, profile());
   2223   WebContents* contents1 = CreateWebContents();
   2224   WebContents* contents2 = CreateWebContents();
   2225   MockTabStripModelObserver tab_strip_model_observer(&strip);
   2226   strip.AppendWebContents(contents1, true);
   2227   strip.AppendWebContents(contents2, true);
   2228   // DeleteWebContentsOnDestroyedObserver deletes contents1 when contents2 sends
   2229   // out notification that it is being destroyed.
   2230   DeleteWebContentsOnDestroyedObserver observer(contents2, contents1, NULL);
   2231   strip.AddObserver(&tab_strip_model_observer);
   2232   strip.CloseAllTabs();
   2233 
   2234   int close_all_count = 0, close_all_canceled_count = 0;
   2235   tab_strip_model_observer.GetCloseCounts(&close_all_count,
   2236                                           &close_all_canceled_count);
   2237   EXPECT_EQ(1, close_all_count);
   2238   EXPECT_EQ(0, close_all_canceled_count);
   2239 
   2240   strip.RemoveObserver(&tab_strip_model_observer);
   2241 }
   2242 
   2243 // Makes sure TabStripModel handles the case of deleting another tab and the
   2244 // TabStrip while removing another tab.
   2245 TEST_F(TabStripModelTest, DeleteTabStripFromDestroy) {
   2246   TabStripDummyDelegate delegate;
   2247   TabStripModel* strip = new TabStripModel(&delegate, profile());
   2248   MockTabStripModelObserver tab_strip_model_observer(strip);
   2249   strip->AddObserver(&tab_strip_model_observer);
   2250   WebContents* contents1 = CreateWebContents();
   2251   WebContents* contents2 = CreateWebContents();
   2252   strip->AppendWebContents(contents1, true);
   2253   strip->AppendWebContents(contents2, true);
   2254   // DeleteWebContentsOnDestroyedObserver deletes |contents1| and |strip| when
   2255   // |contents2| sends out notification that it is being destroyed.
   2256   DeleteWebContentsOnDestroyedObserver observer(contents2, contents1, strip);
   2257   strip->CloseAllTabs();
   2258   EXPECT_TRUE(tab_strip_model_observer.empty());
   2259   EXPECT_TRUE(tab_strip_model_observer.deleted());
   2260 }
   2261 
   2262 TEST_F(TabStripModelTest, MoveSelectedTabsTo) {
   2263   struct TestData {
   2264     // Number of tabs the tab strip should have.
   2265     const int tab_count;
   2266 
   2267     // Number of pinned tabs.
   2268     const int pinned_count;
   2269 
   2270     // Index of the tabs to select.
   2271     const std::string selected_tabs;
   2272 
   2273     // Index to move the tabs to.
   2274     const int target_index;
   2275 
   2276     // Expected state after the move (space separated list of indices).
   2277     const std::string state_after_move;
   2278   } test_data[] = {
   2279     // 1 selected tab.
   2280     { 2, 0, "0", 1, "1 0" },
   2281     { 3, 0, "0", 2, "1 2 0" },
   2282     { 3, 0, "2", 0, "2 0 1" },
   2283     { 3, 0, "2", 1, "0 2 1" },
   2284     { 3, 0, "0 1", 0, "0 1 2" },
   2285 
   2286     // 2 selected tabs.
   2287     { 6, 0, "4 5", 1, "0 4 5 1 2 3" },
   2288     { 3, 0, "0 1", 1, "2 0 1" },
   2289     { 4, 0, "0 2", 1, "1 0 2 3" },
   2290     { 6, 0, "0 1", 3, "2 3 4 0 1 5" },
   2291 
   2292     // 3 selected tabs.
   2293     { 6, 0, "0 2 3", 3, "1 4 5 0 2 3" },
   2294     { 7, 0, "4 5 6", 1, "0 4 5 6 1 2 3" },
   2295     { 7, 0, "1 5 6", 4, "0 2 3 4 1 5 6" },
   2296 
   2297     // 5 selected tabs.
   2298     { 8, 0, "0 2 3 6 7", 3, "1 4 5 0 2 3 6 7" },
   2299 
   2300     // 7 selected tabs
   2301     { 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" },
   2302 
   2303     // With pinned tabs.
   2304     { 6, 2, "2 3", 2, "0p 1p 2 3 4 5" },
   2305     { 6, 2, "0 4", 3, "1p 0p 2 3 4 5" },
   2306     { 6, 3, "1 2 4", 0, "1p 2p 0p 4 3 5" },
   2307     { 8, 3, "1 3 4", 4, "0p 2p 1p 5 6 3 4 7" },
   2308 
   2309     { 7, 4, "2 3 4", 3, "0p 1p 2p 3p 5 4 6" },
   2310   };
   2311 
   2312   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
   2313     TabStripDummyDelegate delegate;
   2314     TabStripModel strip(&delegate, profile());
   2315     ASSERT_NO_FATAL_FAILURE(
   2316         PrepareTabstripForSelectionTest(&strip, test_data[i].tab_count,
   2317                                         test_data[i].pinned_count,
   2318                                         test_data[i].selected_tabs));
   2319     strip.MoveSelectedTabsTo(test_data[i].target_index);
   2320     EXPECT_EQ(test_data[i].state_after_move,
   2321               GetTabStripStateString(strip)) << i;
   2322     strip.CloseAllTabs();
   2323   }
   2324 }
   2325 
   2326 // Tests that moving a tab forgets all groups referencing it.
   2327 TEST_F(TabStripModelTest, MoveSelectedTabsTo_ForgetGroups) {
   2328   TabStripDummyDelegate delegate;
   2329   TabStripModel strip(&delegate, profile());
   2330 
   2331   // Open page A as a new tab and then A1 in the background from A.
   2332   WebContents* page_a_contents = CreateWebContents();
   2333   strip.AddWebContents(page_a_contents, -1,
   2334                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   2335                        TabStripModel::ADD_ACTIVE);
   2336   WebContents* page_a1_contents = CreateWebContents();
   2337   strip.AddWebContents(page_a1_contents, -1, ui::PAGE_TRANSITION_LINK,
   2338                        TabStripModel::ADD_NONE);
   2339 
   2340   // Likewise, open pages B and B1.
   2341   WebContents* page_b_contents = CreateWebContents();
   2342   strip.AddWebContents(page_b_contents, -1,
   2343                        ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
   2344                        TabStripModel::ADD_ACTIVE);
   2345   WebContents* page_b1_contents = CreateWebContents();
   2346   strip.AddWebContents(page_b1_contents, -1, ui::PAGE_TRANSITION_LINK,
   2347                        TabStripModel::ADD_NONE);
   2348 
   2349   EXPECT_EQ(page_a_contents, strip.GetWebContentsAt(0));
   2350   EXPECT_EQ(page_a1_contents, strip.GetWebContentsAt(1));
   2351   EXPECT_EQ(page_b_contents, strip.GetWebContentsAt(2));
   2352   EXPECT_EQ(page_b1_contents, strip.GetWebContentsAt(3));
   2353 
   2354   // Move page B to the start of the tab strip.
   2355   strip.MoveSelectedTabsTo(0);
   2356 
   2357   // Open page B2 in the background from B. It should end up after B.
   2358   WebContents* page_b2_contents = CreateWebContents();
   2359   strip.AddWebContents(page_b2_contents, -1, ui::PAGE_TRANSITION_LINK,
   2360                        TabStripModel::ADD_NONE);
   2361   EXPECT_EQ(page_b_contents, strip.GetWebContentsAt(0));
   2362   EXPECT_EQ(page_b2_contents, strip.GetWebContentsAt(1));
   2363   EXPECT_EQ(page_a_contents, strip.GetWebContentsAt(2));
   2364   EXPECT_EQ(page_a1_contents, strip.GetWebContentsAt(3));
   2365   EXPECT_EQ(page_b1_contents, strip.GetWebContentsAt(4));
   2366 
   2367   // Switch to A.
   2368   strip.ActivateTabAt(2, true);
   2369   EXPECT_EQ(page_a_contents, strip.GetActiveWebContents());
   2370 
   2371   // Open page A2 in the background from A. It should end up after A1.
   2372   WebContents* page_a2_contents = CreateWebContents();
   2373   strip.AddWebContents(page_a2_contents, -1, ui::PAGE_TRANSITION_LINK,
   2374                        TabStripModel::ADD_NONE);
   2375   EXPECT_EQ(page_b_contents, strip.GetWebContentsAt(0));
   2376   EXPECT_EQ(page_b2_contents, strip.GetWebContentsAt(1));
   2377   EXPECT_EQ(page_a_contents, strip.GetWebContentsAt(2));
   2378   EXPECT_EQ(page_a1_contents, strip.GetWebContentsAt(3));
   2379   EXPECT_EQ(page_a2_contents, strip.GetWebContentsAt(4));
   2380   EXPECT_EQ(page_b1_contents, strip.GetWebContentsAt(5));
   2381 
   2382   strip.CloseAllTabs();
   2383 }
   2384 
   2385 TEST_F(TabStripModelTest, CloseSelectedTabs) {
   2386   TabStripDummyDelegate delegate;
   2387   TabStripModel strip(&delegate, profile());
   2388   WebContents* contents1 = CreateWebContents();
   2389   WebContents* contents2 = CreateWebContents();
   2390   WebContents* contents3 = CreateWebContents();
   2391   strip.AppendWebContents(contents1, true);
   2392   strip.AppendWebContents(contents2, true);
   2393   strip.AppendWebContents(contents3, true);
   2394   strip.ToggleSelectionAt(1);
   2395   strip.CloseSelectedTabs();
   2396   EXPECT_EQ(1, strip.count());
   2397   EXPECT_EQ(0, strip.active_index());
   2398   strip.CloseAllTabs();
   2399 }
   2400 
   2401 TEST_F(TabStripModelTest, MultipleSelection) {
   2402   typedef MockTabStripModelObserver::State State;
   2403 
   2404   TabStripDummyDelegate delegate;
   2405   TabStripModel strip(&delegate, profile());
   2406   MockTabStripModelObserver observer(&strip);
   2407   WebContents* contents0 = CreateWebContents();
   2408   WebContents* contents1 = CreateWebContents();
   2409   WebContents* contents2 = CreateWebContents();
   2410   WebContents* contents3 = CreateWebContents();
   2411   strip.AppendWebContents(contents0, false);
   2412   strip.AppendWebContents(contents1, false);
   2413   strip.AppendWebContents(contents2, false);
   2414   strip.AppendWebContents(contents3, false);
   2415   strip.AddObserver(&observer);
   2416 
   2417   // Selection and active tab change.
   2418   strip.ActivateTabAt(3, true);
   2419   ASSERT_EQ(2, observer.GetStateCount());
   2420   ASSERT_EQ(observer.GetStateAt(0).action,
   2421             MockTabStripModelObserver::ACTIVATE);
   2422   State s1(contents3, 3, MockTabStripModelObserver::SELECT);
   2423   EXPECT_TRUE(observer.StateEquals(1, s1));
   2424   observer.ClearStates();
   2425 
   2426   // Adding all tabs to selection, active tab is now at 0.
   2427   strip.ExtendSelectionTo(0);
   2428   ASSERT_EQ(3, observer.GetStateCount());
   2429   ASSERT_EQ(observer.GetStateAt(0).action,
   2430             MockTabStripModelObserver::DEACTIVATE);
   2431   ASSERT_EQ(observer.GetStateAt(1).action,
   2432             MockTabStripModelObserver::ACTIVATE);
   2433   State s2(contents0, 0, MockTabStripModelObserver::SELECT);
   2434   s2.src_contents = contents3;
   2435   s2.src_index = 3;
   2436   EXPECT_TRUE(observer.StateEquals(2, s2));
   2437   observer.ClearStates();
   2438 
   2439   // Toggle the active tab, should make the next index active.
   2440   strip.ToggleSelectionAt(0);
   2441   EXPECT_EQ(1, strip.active_index());
   2442   EXPECT_EQ(3U, strip.selection_model().size());
   2443   EXPECT_EQ(4, strip.count());
   2444   ASSERT_EQ(3, observer.GetStateCount());
   2445   ASSERT_EQ(observer.GetStateAt(0).action,
   2446             MockTabStripModelObserver::DEACTIVATE);
   2447   ASSERT_EQ(observer.GetStateAt(1).action,
   2448             MockTabStripModelObserver::ACTIVATE);
   2449   ASSERT_EQ(observer.GetStateAt(2).action,
   2450             MockTabStripModelObserver::SELECT);
   2451   observer.ClearStates();
   2452 
   2453   // Toggle the first tab back to selected and active.
   2454   strip.ToggleSelectionAt(0);
   2455   EXPECT_EQ(0, strip.active_index());
   2456   EXPECT_EQ(4U, strip.selection_model().size());
   2457   EXPECT_EQ(4, strip.count());
   2458   ASSERT_EQ(3, observer.GetStateCount());
   2459   ASSERT_EQ(observer.GetStateAt(0).action,
   2460             MockTabStripModelObserver::DEACTIVATE);
   2461   ASSERT_EQ(observer.GetStateAt(1).action,
   2462             MockTabStripModelObserver::ACTIVATE);
   2463   ASSERT_EQ(observer.GetStateAt(2).action,
   2464             MockTabStripModelObserver::SELECT);
   2465   observer.ClearStates();
   2466 
   2467   // Closing one of the selected tabs, not the active one.
   2468   strip.CloseWebContentsAt(1, TabStripModel::CLOSE_NONE);
   2469   EXPECT_EQ(3, strip.count());
   2470   ASSERT_EQ(3, observer.GetStateCount());
   2471   ASSERT_EQ(observer.GetStateAt(0).action,
   2472             MockTabStripModelObserver::CLOSE);
   2473   ASSERT_EQ(observer.GetStateAt(1).action,
   2474             MockTabStripModelObserver::DETACH);
   2475   ASSERT_EQ(observer.GetStateAt(2).action,
   2476             MockTabStripModelObserver::SELECT);
   2477   observer.ClearStates();
   2478 
   2479   // Closing the active tab, while there are others tabs selected.
   2480   strip.CloseWebContentsAt(0, TabStripModel::CLOSE_NONE);
   2481   EXPECT_EQ(2, strip.count());
   2482   ASSERT_EQ(5, observer.GetStateCount());
   2483   ASSERT_EQ(observer.GetStateAt(0).action,
   2484             MockTabStripModelObserver::CLOSE);
   2485   ASSERT_EQ(observer.GetStateAt(1).action,
   2486             MockTabStripModelObserver::DETACH);
   2487   ASSERT_EQ(observer.GetStateAt(2).action,
   2488             MockTabStripModelObserver::DEACTIVATE);
   2489   ASSERT_EQ(observer.GetStateAt(3).action,
   2490             MockTabStripModelObserver::ACTIVATE);
   2491   ASSERT_EQ(observer.GetStateAt(4).action,
   2492             MockTabStripModelObserver::SELECT);
   2493   observer.ClearStates();
   2494 
   2495   // Active tab is at 0, deselecting all but the active tab.
   2496   strip.ToggleSelectionAt(1);
   2497   ASSERT_EQ(1, observer.GetStateCount());
   2498   ASSERT_EQ(observer.GetStateAt(0).action,
   2499             MockTabStripModelObserver::SELECT);
   2500   observer.ClearStates();
   2501 
   2502   // Attempting to deselect the only selected and therefore active tab,
   2503   // it is ignored (no notifications being sent) and tab at 0 remains selected
   2504   // and active.
   2505   strip.ToggleSelectionAt(0);
   2506   ASSERT_EQ(0, observer.GetStateCount());
   2507 
   2508   strip.RemoveObserver(&observer);
   2509   strip.CloseAllTabs();
   2510 }
   2511 
   2512 // Verifies that if we change the selection from a multi selection to a single
   2513 // selection, but not in a way that changes the selected_index that
   2514 // TabSelectionChanged is invoked.
   2515 TEST_F(TabStripModelTest, MultipleToSingle) {
   2516   typedef MockTabStripModelObserver::State State;
   2517 
   2518   TabStripDummyDelegate delegate;
   2519   TabStripModel strip(&delegate, profile());
   2520   WebContents* contents1 = CreateWebContents();
   2521   WebContents* contents2 = CreateWebContents();
   2522   strip.AppendWebContents(contents1, false);
   2523   strip.AppendWebContents(contents2, false);
   2524   strip.ToggleSelectionAt(0);
   2525   strip.ToggleSelectionAt(1);
   2526 
   2527   MockTabStripModelObserver observer(&strip);
   2528   strip.AddObserver(&observer);
   2529   // This changes the selection (0 is no longer selected) but the selected_index
   2530   // still remains at 1.
   2531   strip.ActivateTabAt(1, true);
   2532   ASSERT_EQ(1, observer.GetStateCount());
   2533   State s(contents2, 1, MockTabStripModelObserver::SELECT);
   2534   s.src_contents = contents2;
   2535   s.src_index = 1;
   2536   s.change_reason = TabStripModelObserver::CHANGE_REASON_NONE;
   2537   EXPECT_TRUE(observer.StateEquals(0, s));
   2538   strip.RemoveObserver(&observer);
   2539   strip.CloseAllTabs();
   2540 }
   2541 
   2542 // Verifies a newly inserted tab retains its previous blocked state.
   2543 // http://crbug.com/276334
   2544 TEST_F(TabStripModelTest, TabBlockedState) {
   2545   // Start with a source tab strip.
   2546   TabStripDummyDelegate dummy_tab_strip_delegate;
   2547   TabStripModel strip_src(&dummy_tab_strip_delegate, profile());
   2548   TabBlockedStateTestBrowser browser_src(&strip_src);
   2549 
   2550   // Add a tab.
   2551   WebContents* contents1 = CreateWebContents();
   2552   web_modal::WebContentsModalDialogManager::CreateForWebContents(contents1);
   2553   strip_src.AppendWebContents(contents1, false);
   2554 
   2555   // Add another tab.
   2556   WebContents* contents2 = CreateWebContents();
   2557   web_modal::WebContentsModalDialogManager::CreateForWebContents(contents2);
   2558   strip_src.AppendWebContents(contents2, false);
   2559 
   2560   // Create a destination tab strip.
   2561   TabStripModel strip_dst(&dummy_tab_strip_delegate, profile());
   2562   TabBlockedStateTestBrowser browser_dst(&strip_dst);
   2563 
   2564   // Setup a SingleWebContentsDialogManager for tab |contents2|.
   2565   web_modal::WebContentsModalDialogManager* modal_dialog_manager =
   2566       web_modal::WebContentsModalDialogManager::FromWebContents(contents2);
   2567   web_modal::PopupManager popup_manager(NULL);
   2568   popup_manager.RegisterWith(contents2);
   2569 
   2570   // Show a dialog that blocks tab |contents2|.
   2571   // DummySingleWebContentsDialogManager doesn't care about the
   2572   // NativeWebContentsModalDialog value, so any dummy value works.
   2573   DummySingleWebContentsDialogManager* native_manager =
   2574       new DummySingleWebContentsDialogManager(
   2575           reinterpret_cast<NativeWebContentsModalDialog>(0),
   2576           modal_dialog_manager);
   2577   modal_dialog_manager->ShowDialogWithManager(
   2578       reinterpret_cast<NativeWebContentsModalDialog>(0),
   2579       scoped_ptr<web_modal::SingleWebContentsDialogManager>(
   2580           native_manager).Pass());
   2581   EXPECT_TRUE(strip_src.IsTabBlocked(1));
   2582 
   2583   // Detach the tab.
   2584   WebContents* moved_contents = strip_src.DetachWebContentsAt(1);
   2585   EXPECT_EQ(contents2, moved_contents);
   2586 
   2587   // Attach the tab to the destination tab strip.
   2588   strip_dst.AppendWebContents(moved_contents, true);
   2589   EXPECT_TRUE(strip_dst.IsTabBlocked(0));
   2590 
   2591   strip_dst.CloseAllTabs();
   2592   strip_src.CloseAllTabs();
   2593 }
   2594