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
15namespace {
16
17struct 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
31class 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.
141TEST_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.
156TEST_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.
177TEST_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().
264TEST_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().
289TEST_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.
348TEST_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().
400TEST_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().
432TEST_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.
453TEST_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.
464TEST_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().
506TEST_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.
527TEST_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.
537TEST_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