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/views/tabs/stacked_tab_strip_layout.h"
      6 
      7 #include <string>
      8 
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/string_util.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 #include "ui/views/view.h"
     13 #include "ui/views/view_model.h"
     14 
     15 namespace {
     16 
     17 struct CommonTestData {
     18   const int initial_x;
     19   const int width;
     20   const int tab_size;
     21   const int tab_padding;
     22   const int stacked_offset;
     23   const int mini_tab_count;
     24   const int active_index;
     25   const std::string start_bounds;
     26   const std::string expected_bounds;
     27 };
     28 
     29 }  // namespace
     30 
     31 class StackedTabStripLayoutTest : public testing::Test {
     32  public:
     33   StackedTabStripLayoutTest() {}
     34 
     35  protected:
     36   void Reset(StackedTabStripLayout* layout,
     37              int x,
     38              int width,
     39              int mini_tab_count,
     40              int active_index) {
     41     layout->Reset(x, width, mini_tab_count, active_index);
     42   }
     43 
     44   void CreateLayout(const CommonTestData& data) {
     45     if (!data.start_bounds.empty())
     46       PrepareChildViewsFromString(data.start_bounds);
     47     else
     48       PrepareChildViewsFromString(data.expected_bounds);
     49     layout_.reset(new StackedTabStripLayout(
     50                      gfx::Size(data.tab_size, 10), data.tab_padding,
     51                      data.stacked_offset, 4, &view_model_));
     52     if (data.start_bounds.empty()) {
     53       PrepareChildViewsFromString(data.expected_bounds);
     54       layout_->Reset(data.initial_x, data.width, data.mini_tab_count,
     55                      data.active_index);
     56     } else {
     57       ASSERT_NO_FATAL_FAILURE(SetBoundsFromString(data.start_bounds));
     58       layout_->Reset(data.initial_x, data.width, data.mini_tab_count,
     59                      data.active_index);
     60       ASSERT_NO_FATAL_FAILURE(SetBoundsFromString(data.start_bounds));
     61     }
     62   }
     63 
     64   void AddViewToViewModel(int index) {
     65     views::View* child_view = new views::View;
     66     view_.AddChildView(child_view);
     67     view_model_.Add(child_view, index);
     68   }
     69 
     70   void PrepareChildViewsFromString(const std::string& bounds) {
     71     std::vector<std::string> positions;
     72     Tokenize(bounds, " ", &positions);
     73     PrepareChildViews(static_cast<int>(positions.size()));
     74   }
     75 
     76   void PrepareChildViews(int count) {
     77     view_model_.Clear();
     78     view_.RemoveAllChildViews(true);
     79     for (int i = 0; i < count; ++i)
     80       AddViewToViewModel(i);
     81   }
     82 
     83   void SetBoundsFromString(const std::string& bounds) {
     84     std::vector<std::string> positions;
     85     Tokenize(bounds, " ", &positions);
     86     PrepareChildViews(static_cast<int>(positions.size()));
     87     for (int i = 0; i < view_model_.view_size(); ++i) {
     88       int x = 0;
     89       gfx::Rect bounds(view_model_.ideal_bounds(i));
     90       ASSERT_TRUE(base::StringToInt(positions[i], &x));
     91       bounds.set_x(x);
     92       view_model_.set_ideal_bounds(i, bounds);
     93     }
     94   }
     95 
     96   std::string BoundsString() const {
     97     std::string result;
     98     for (int i = 0; i < view_model_.view_size(); ++i) {
     99       if (!result.empty())
    100         result += " ";
    101       result += base::IntToString(view_model_.ideal_bounds(i).x());
    102     }
    103     return result;
    104   }
    105 
    106   std::string BoundsString2(int active_index) const {
    107     std::string result;
    108     for (int i = 0; i < view_model_.view_size(); ++i) {
    109       if (!result.empty())
    110         result += " ";
    111       if (i == active_index)
    112         result += "[";
    113       result += base::IntToString(view_model_.ideal_bounds(i).x());
    114       if (i == active_index)
    115         result += "]";
    116     }
    117     return result;
    118   }
    119 
    120   void Validate(int active_index, int max_width) {
    121     // Make sure none of the tabs are more than 90 apart
    122     // (tab_size(100) + padding (-10)).
    123     for (int j = 1; j < view_model_.view_size(); ++j)
    124       EXPECT_LE(ideal_x(j) - ideal_x(j - 1), max_width - 100);
    125   }
    126 
    127   int ideal_x(int index) const {
    128     return view_model_.ideal_bounds(index).x();
    129   }
    130 
    131   scoped_ptr<StackedTabStripLayout> layout_;
    132   views::ViewModel view_model_;
    133 
    134  private:
    135   views::View view_;
    136 
    137   DISALLOW_COPY_AND_ASSIGN(StackedTabStripLayoutTest);
    138 };
    139 
    140 // Random data.
    141 TEST_F(StackedTabStripLayoutTest, ValidateInitialLayout) {
    142   StackedTabStripLayout layout(gfx::Size(100, 10), -10, 2, 4, &view_model_);
    143   PrepareChildViews(12);
    144 
    145   for (int i = 120; i < 600; ++i) {
    146     for (int j = 0; j < 12; ++j) {
    147       Reset(&layout, 0, i, 0, j);
    148       Validate(j, i);
    149       if (HasNonfatalFailure())
    150         return;
    151     }
    152   }
    153 }
    154 
    155 // Ensure initial layout is correct.
    156 TEST_F(StackedTabStripLayoutTest, InitialLayout) {
    157   struct CommonTestData test_data[] = {
    158     { 0, 198, 100, -10, 1, 0, 9, "",
    159       "0 0 0 0 0 0 1 2 3 4 94 95 96 97 98 98 98 98" },
    160     { 0, 198, 100, -10, 1, 0, 0, "", "0 90 94 95 96 97 98 98 98" },
    161     { 0, 300, 100, -10, 1, 0, 0, "",
    162       "0 90 180 196 197 198 199 200 200 200 200" },
    163     { 0, 300, 100, -10, 1, 0, 10, "", "0 0 0 0 1 2 3 4 20 110 200" },
    164     { 0, 300, 100, -10, 1, 0, 1, "", "0 90 180 196 197 198 199 200 200" },
    165     { 0, 643, 160, -27, 6, 0, 0, "", "0 133 266 399" },
    166     { 0, 300, 100, -10, 1, 0, 7, "", "0 1 2 3 4 20 110 200" },
    167     { 0, 300, 100, -10, 1, 0, 6, "", "0 1 2 3 4 20 110 200" },
    168     { 0, 300, 100, -10, 1, 0, 4, "", "0 1 2 3 4 94 184 199 200" },
    169   };
    170   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    171     CreateLayout(test_data[i]);
    172     EXPECT_EQ(test_data[i].expected_bounds, BoundsString()) << " at " << i;
    173   }
    174 }
    175 
    176 // Assertions for dragging from an existing configuration.
    177 TEST_F(StackedTabStripLayoutTest, DragActiveTabExisting) {
    178   struct TestData {
    179     struct CommonTestData common_data;
    180     const int delta;
    181   } test_data[] = {
    182     //
    183     // The following set of tests create 6 tabs, the first two are pinned and
    184     // the 2nd tab is selected.
    185     //
    186     // 1 pixel to the right, should push only mini-tabs and first non-mini-tab.
    187     { { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    188         "1 6 11 101 138 140" }, 1 },
    189     // Push enough to collapse the 4th tab.
    190     { { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    191         "36 41 46 136 138 140" }, 36 },
    192     // 1 past collapsing the 4th.
    193     { { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    194         "37 42 47 136 138 140" }, 37 },
    195     // Collapse the third.
    196     { { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    197         "124 129 134 136 138 140" }, 124 },
    198     // One past collapsing the third.
    199     { { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    200         "124 129 134 136 138 140" }, 125 },
    201 
    202     //
    203     // The following set of tests create 6 tabs, the first two are pinned and
    204     // the 5th is selected.
    205     //
    206     // 1 pixel to the right, should expose part of a tab.
    207     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140", "0 5 10 90 131 140" },
    208       1 },
    209     // Push the tab as far to the right as it'll go.
    210     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140", "0 5 10 90 138 140" },
    211       8 },
    212     // One past as far to the right as it'll go. Should expose more of the tab
    213     // before it.
    214     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140", "0 5 10 91 138 140" },
    215       9 },
    216     // Enough so that the pinned tabs start pulling in.
    217     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140", "1 6 11 101 138 140" },
    218       19 },
    219     // One more than last.
    220     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140", "2 7 12 102 138 140" },
    221       20 },
    222     // Enough to collapse the fourth as small it can get.
    223     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140",
    224         "36 41 46 136 138 140" }, 54 },
    225     // Enough to collapse the third as small it can get.
    226     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140",
    227         "124 129 134 136 138 140" }, 142 },
    228     // One more than last, shouldn't change anything.
    229     { { 10, 240, 100, -10, 2, 2, 4, "0 5 10 90 130 140",
    230         "124 129 134 136 138 140" }, 143 },
    231 
    232     //
    233     // The following set of tests create 3 tabs with the second selected.
    234     //
    235     // Drags in 2, pulling the rightmost tab along.
    236     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "2 92 140" }, 2 },
    237     // Drags the rightmost tab as far to right as possible.
    238     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "48 138 140" }, 48 },
    239     // Drags so much that the left most tabs pulls in.
    240     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "135 138 140" }, 135 },
    241     // Drags so far that no more tabs pull in.
    242     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "136 138 140" }, 200 },
    243     // Drags to the left most position before the right tabs start pulling in.
    244     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "0 50 140" }, -40 },
    245     // Drags 1 beyond the left most position, which should pull in the right
    246     // tab slightly.
    247     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "0 49 139" }, -41 },
    248     // Drags to the left as far as the tab goes.
    249     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "0 2 92" }, -88 },
    250     // Drags one past as far to the left as the tab goes. Should keep pulling
    251     // in the rightmost tab.
    252     { { 0, 240, 100, -10, 2, 0, 1, "0 90 140", "0 2 91" }, -89 },
    253   };
    254 
    255   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    256     CreateLayout(test_data[i].common_data);
    257     layout_->DragActiveTab(test_data[i].delta);
    258     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    259         " at " << i;
    260   }
    261 }
    262 
    263 // Assertions for SizeToFit().
    264 TEST_F(StackedTabStripLayoutTest, SizeToFit) {
    265   struct CommonTestData test_data[] = {
    266     // Dragged to the right.
    267     { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140", "1 6 11 101 138 140"},
    268     { 10, 240, 100, -10, 2, 2, 1, "0 5 10 100 138 140",
    269       "124 129 134 136 138 140" },
    270 
    271     // Dragged to the left.
    272     { 0, 240, 100, -10, 2, 0, 1, "0 50 140", "0 49 139" },
    273 
    274     // Dragged to the left.
    275     { 0, 240, 100, -10, 2, 0, 1, "0 49 89 140", "0 49 89 139" },
    276   };
    277 
    278   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    279     CreateLayout(test_data[i]);
    280     SetBoundsFromString(test_data[i].expected_bounds);
    281     layout_->SizeToFit();
    282     // NOTE: because of the way the code is structured this asserts on
    283     // |start_bound|, not |expected_bounds|.
    284     EXPECT_EQ(test_data[i].start_bounds, BoundsString()) << " at " << i;
    285   }
    286 }
    287 
    288 // Assertions for AddTab().
    289 TEST_F(StackedTabStripLayoutTest, AddTab) {
    290   struct TestData {
    291     CommonTestData common_data;
    292     int add_index;
    293     bool add_active;
    294     bool add_mini;
    295   } test_data[] = {
    296     // Adding a background tab test cases.
    297     { { 0, 300, 100, -10, 2, 0, 1, "0 90 180 198 200", "0 16 106 196 198 200"},
    298       3, false, false },
    299     { { 0, 300, 100, -10, 2, 0, 1, "0 90 180 198 200", "0 2 4 20 110 200"},
    300       5, false, false },
    301     { { 0, 300, 100, -10, 2, 0, 1, "0 90 180 198 200", "0 90 180 196 198 200"},
    302       2, false, false },
    303     { { 0, 300, 100, -10, 2, 0, 1, "0 90 180 198 200", "0 2 4 94 184 200"},
    304       0, false, false },
    305 
    306     { { 4, 200, 100, -10, 2, 1, 2, "0 4 10 100", "0 0 8 10 100"},
    307       1, false, true },
    308     { { 4, 200, 100, -10, 2, 1, 2, "0 4 10 100", "0 0 8 98 100"},
    309       1, true, true },
    310     { { 4, 200, 100, -10, 2, 1, 2, "0 4 10 100", "0 0 8 98 100"},
    311       0, true, true },
    312     { { 0, 200, 100, -10, 2, 0, 2, "0 2 10 100", "0 4 94 98 100"},
    313       0, true, true },
    314 
    315     { { 0, 200, 100, -10, 2, 0, 0, "0 90 92 92 94 96 98 100",
    316                                    "0 0 0 2 4 6 8 98 100"},
    317       7, true, false },
    318     { { 0, 200, 100, -10, 2, 0, 7, "0 2 4 6 8 8 10 100",
    319                                    "0 0 2 4 6 8 96 98 100"},
    320       5, true, false },
    321     { { 0, 200, 100, -10, 2, 0, 7, "0 2 4 6 8 8 10 100",
    322                                    "0 2 4 6 8 94 96 98 100"},
    323       4, true, false },
    324     { { 0, 200, 100, -10, 2, 0, 2, "0 2 10 100", "0 2 10 98 100"},
    325       2, true, false },
    326     { { 0, 200, 100, -10, 2, 0, 2, "0 2 10 100", "0 2 4 10 100"},
    327       4, true, false },
    328     { { 0, 200, 100, -10, 2, 0, 2, "0 2 10 100", "0 90 96 98 100"},
    329       0, true, false },
    330   };
    331   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    332     CreateLayout(test_data[i].common_data);
    333     int add_types = 0;
    334     if (test_data[i].add_active)
    335       add_types |= StackedTabStripLayout::kAddTypeActive;
    336     if (test_data[i].add_mini)
    337       add_types |= StackedTabStripLayout::kAddTypeMini;
    338     AddViewToViewModel(test_data[i].add_index);
    339     layout_->AddTab(test_data[i].add_index, add_types,
    340                     test_data[i].common_data.initial_x +
    341                     (test_data[i].add_mini ? 4 : 0));
    342     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    343         " at " << i;
    344   }
    345 }
    346 
    347 // Assertions around removing tabs.
    348 TEST_F(StackedTabStripLayoutTest, RemoveTab) {
    349   // TODO: add coverage of removing mini tabs!
    350   struct TestData {
    351     struct CommonTestData common_data;
    352     const int remove_index;
    353     const int x_after_remove;
    354   } test_data[] = {
    355     { { 0, 882, 220, -29, 2, 0, 4, "0 23 214 405 596 602",
    356         "0 191 382 573 662" }, 1, 0 },
    357 
    358     // Remove before active.
    359     { { 0, 200, 100, -10, 2, 0, 4, "0 2 4 6 8 10 80 98 100",
    360         "0 2 6 8 10 80 98 100" },
    361       2, 0 },
    362 
    363     // Stacked tabs on both sides.
    364     { { 0, 200, 100, -10, 2, 0, 4, "0 2 4 6 8 10 80 98 100",
    365         "0 2 4 6 10 80 98 100" },
    366       4, 0 },
    367 
    368     // Mini-tabs.
    369     { { 8, 200, 100, -10, 2, 1, 0, "0 8 94 96 98 100", "0 86 88 90 100" },
    370       0, 0 },
    371     { { 16, 200, 100, -10, 2, 2, 0, "0 8 16 94 96 98 100", "8 8 86 88 90 100" },
    372       0, 8 },
    373     { { 16, 200, 100, -10, 2, 2, 0, "0 8 16 94 96 98 100", "0 8 86 88 90 100" },
    374       1, 8 },
    375 
    376     // Remove from ideal layout.
    377     { { 0, 200, 100, -10, 2, 0, 0, "0 90 94 96 98 100", "0 90 96 98 100" },
    378       0, 0 },
    379     { { 0, 200, 100, -10, 2, 0, 0, "0 90 94 96 98 100", "0 90 96 98 100" },
    380       1, 0 },
    381     { { 0, 200, 100, -10, 2, 0, 0, "0 90 94 96 98 100", "0 90 96 98 100" },
    382       2, 0 },
    383     { { 0, 200, 100, -10, 2, 0, 0, "0 90 94 96 98 100", "0 90 94 98 100" },
    384       3, 0 },
    385     { { 0, 200, 100, -10, 2, 0, 0, "0 90 94 96 98 100", "0 90 94 96 100" },
    386       5, 0 },
    387   };
    388   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    389     CreateLayout(test_data[i].common_data);
    390     int old_x = view_model_.ideal_bounds(test_data[i].remove_index).x();
    391     view_model_.Remove(test_data[i].remove_index);
    392     layout_->RemoveTab(test_data[i].remove_index, test_data[i].x_after_remove,
    393                        old_x);
    394     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    395         " at " << i;
    396   }
    397 }
    398 
    399 // Assertions for SetWidth().
    400 TEST_F(StackedTabStripLayoutTest, SetWidth) {
    401   struct TestData {
    402     CommonTestData common_data;
    403     int new_width;
    404   } test_data[] = {
    405     { { 0, 500, 100, -10, 2, 0, 4, "0 90 180 270 360 400",
    406                                    "0 90 180 196 198 200"}, 300 },
    407 
    408     // Verifies a bug in AdjustTrailingStackedTabs().
    409     { { 0, 103, 100, -10, 2, 0, 0, "", "0 2"}, 102 },
    410 
    411     { { 8, 250, 100, -10, 2, 2, 2, "0 4 8 98 148 150", "0 4 8 98 160 250"},
    412       350 },
    413     { { 8, 250, 100, -10, 2, 2, 2, "0 4 8 98 148 150", "0 4 8 96 98 100"},
    414       200 },
    415 
    416     { { 0, 250, 100, -10, 2, 0, 2, "0 40 90 120 150", "0 40 90 98 100"}, 200 },
    417     { { 0, 250, 100, -10, 2, 0, 2, "0 2 60 150", "0 2 60 100"}, 200 },
    418     { { 0, 250, 100, -10, 2, 0, 2, "0 40 120 150", "0 40 98 100"}, 200 },
    419 
    420     { { 0, 200, 100, -10, 2, 0, 2, "0 2 10 100", "0 2 60 150"}, 250 },
    421     { { 0, 200, 100, -10, 2, 0, 2, "0 2 4 10 100", "0 2 20 110 200"}, 300 },
    422   };
    423   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    424     CreateLayout(test_data[i].common_data);
    425     layout_->SetWidth(test_data[i].new_width);
    426     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    427         " at " << i;
    428   }
    429 }
    430 
    431 // Assertions for SetActiveIndex().
    432 TEST_F(StackedTabStripLayoutTest, SetActiveIndex) {
    433   struct TestData {
    434     CommonTestData common_data;
    435     int new_index;
    436   } test_data[] = {
    437     { { 0, 250, 100, -10, 2, 0, 2, "0 4 8 98 148 150", "0 90 144 146 148 150"},
    438       0 },
    439     { { 0, 250, 100, -10, 2, 0, 2, "0 4 8 98 148 150", "0 2 4 58 148 150"}, 4 },
    440     { { 0, 250, 100, -10, 2, 0, 2, "0 4 8 98 148 150", "0 2 4 6 60 150"}, 5 },
    441     { { 4, 250, 100, -10, 2, 1, 2, "0 4 8 98 148 150", "0 4 94 146 148 150"},
    442       0 },
    443   };
    444   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    445     CreateLayout(test_data[i].common_data);
    446     layout_->SetActiveIndex(test_data[i].new_index);
    447     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    448         " at " << i;
    449   }
    450 }
    451 
    452 // Makes sure don't crash when resized and only one tab.
    453 TEST_F(StackedTabStripLayoutTest, EmptyTest) {
    454   StackedTabStripLayout layout(gfx::Size(160, 10), -27, 6, 4, &view_model_);
    455   PrepareChildViews(1);
    456   layout.AddTab(0, StackedTabStripLayout::kAddTypeActive, 0);
    457   layout.SetWidth(100);
    458   layout.SetWidth(50);
    459   layout.SetWidth(0);
    460   layout.SetWidth(500);
    461 }
    462 
    463 // Assertions around removing tabs.
    464 TEST_F(StackedTabStripLayoutTest, MoveTab) {
    465   // TODO: add coverage of removing mini tabs!
    466   struct TestData {
    467     struct CommonTestData common_data;
    468     const int from;
    469     const int to;
    470     const int new_active_index;
    471     const int new_start_x;
    472     const int new_mini_tab_count;
    473   } test_data[] = {
    474     // Moves and unpins.
    475     { { 10, 300, 100, -10, 2, 2, 0, "", "0 5 10 100 190 198 200" },
    476       0, 1, 2, 5, 1 },
    477 
    478     // Moves and pins.
    479     { { 0, 300, 100, -10, 2, 0, 4, "", "0 5 95 185 196 198 200" },
    480       2, 0, 0, 5, 1 },
    481     { { 0, 300, 100, -10, 2, 1, 2, "", "0 5 10 100 190 198 200" },
    482       2, 0, 0, 10, 2 },
    483 
    484     { { 0, 200, 100, -10, 2, 0, 4, "0 2 4 6 96 98 100", "0 2 4 6 96 98 100" },
    485       2, 0, 4, 0, 0 },
    486     { { 0, 200, 100, -10, 2, 0, 4, "0 2 4 6 96 98 100", "0 2 4 6 8 10 100" },
    487       0, 6, 6, 0, 0 },
    488   };
    489   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    490     CreateLayout(test_data[i].common_data);
    491     view_model_.MoveViewOnly(test_data[i].from, test_data[i].to);
    492     for (int j = 0; j < test_data[i].new_mini_tab_count; ++j) {
    493       gfx::Rect bounds;
    494       bounds.set_x(j * 5);
    495       view_model_.set_ideal_bounds(j, bounds);
    496     }
    497     layout_->MoveTab(test_data[i].from, test_data[i].to,
    498                      test_data[i].new_active_index, test_data[i].new_start_x,
    499                      test_data[i].new_mini_tab_count);
    500     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    501         " at " << i;
    502   }
    503 }
    504 
    505 // Assertions around IsStacked().
    506 TEST_F(StackedTabStripLayoutTest, IsStacked) {
    507   // A single tab with enough space should never be stacked.
    508   PrepareChildViews(1);
    509   layout_.reset(new StackedTabStripLayout(
    510                     gfx::Size(100, 10), -10, 2, 4, &view_model_));
    511   Reset(layout_.get(), 0, 400, 0, 0);
    512   EXPECT_FALSE(layout_->IsStacked(0));
    513 
    514   // First tab active, remaining tabs stacked.
    515   PrepareChildViews(8);
    516   Reset(layout_.get(), 0, 400, 0, 0);
    517   EXPECT_FALSE(layout_->IsStacked(0));
    518   EXPECT_TRUE(layout_->IsStacked(7));
    519 
    520   // Last tab active, preceeding tabs stacked.
    521   layout_->SetActiveIndex(7);
    522   EXPECT_FALSE(layout_->IsStacked(7));
    523   EXPECT_TRUE(layout_->IsStacked(0));
    524 }
    525 
    526 // Assertions around SetXAndMiniCount.
    527 TEST_F(StackedTabStripLayoutTest, SetXAndMiniCount) {
    528   // Verifies we don't crash when transitioning to all mini-tabs.
    529   PrepareChildViews(1);
    530   layout_.reset(new StackedTabStripLayout(
    531                     gfx::Size(100, 10), -10, 2, 4, &view_model_));
    532   Reset(layout_.get(), 0, 400, 0, 0);
    533   layout_->SetXAndMiniCount(0, 1);
    534 }
    535 
    536 // Assertions around SetXAndMiniCount.
    537 TEST_F(StackedTabStripLayoutTest, SetActiveTabLocation) {
    538   struct TestData {
    539     struct CommonTestData common_data;
    540     const int location;
    541   } test_data[] = {
    542     // Active tab is the first tab, can't be moved.
    543     { { 0, 300, 100, -10, 2, 0, 0, "", "0 90 180 194 196 198 200" }, 50 },
    544 
    545     // Active tab is pinned; should result in nothing.
    546     { { 0, 300, 100, -10, 2, 2, 1, "", "0 0 0 90 180 198 200" }, 199 },
    547 
    548     // Location is too far to the right, ends up being pushed in.
    549     { { 0, 300, 100, -10, 2, 0, 3, "", "0 14 104 194 196 198 200" }, 199 },
    550 
    551     // Location can be honored.
    552     { { 0, 300, 100, -10, 2, 0, 3, "", "0 2 4 40 130 198 200" }, 40 },
    553   };
    554   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
    555     CreateLayout(test_data[i].common_data);
    556     layout_->SetActiveTabLocation(test_data[i].location);
    557     EXPECT_EQ(test_data[i].common_data.expected_bounds, BoundsString()) <<
    558         " at " << i;
    559   }
    560 }
    561