tab_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/tab.h"
6#include "chrome/browser/ui/views/tabs/tab_controller.h"
7
8#include "base/strings/utf_string_conversions.h"
9#include "testing/gtest/include/gtest/gtest.h"
10#include "ui/base/models/list_selection_model.h"
11#include "ui/views/controls/button/image_button.h"
12#include "ui/views/test/views_test_base.h"
13#include "ui/views/widget/widget.h"
14
15using views::Widget;
16
17class FakeTabController : public TabController {
18 public:
19  FakeTabController() : immersive_style_(false) {
20  }
21  virtual ~FakeTabController() {}
22
23  void set_immersive_style(bool value) { immersive_style_ = value; }
24
25  virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE {
26    return selection_model_;
27  }
28  virtual bool SupportsMultipleSelection() OVERRIDE { return false; }
29  virtual void SelectTab(Tab* tab) OVERRIDE {}
30  virtual void ExtendSelectionTo(Tab* tab) OVERRIDE {}
31  virtual void ToggleSelected(Tab* tab) OVERRIDE {}
32  virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE {}
33  virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE {}
34  virtual void ShowContextMenuForTab(Tab* tab,
35                                     const gfx::Point& p) OVERRIDE {}
36  virtual bool IsActiveTab(const Tab* tab) const OVERRIDE { return false; }
37  virtual bool IsTabSelected(const Tab* tab) const OVERRIDE {
38    return false;
39  }
40  virtual bool IsTabPinned(const Tab* tab) const OVERRIDE { return false; }
41  virtual void MaybeStartDrag(
42      Tab* tab,
43      const ui::LocatedEvent& event,
44      const ui::ListSelectionModel& original_selection) OVERRIDE {}
45  virtual void ContinueDrag(views::View* view,
46                            const ui::LocatedEvent& event) OVERRIDE {}
47  virtual bool EndDrag(EndDragReason reason) OVERRIDE { return false; }
48  virtual Tab* GetTabAt(Tab* tab,
49                        const gfx::Point& tab_in_tab_coordinates) OVERRIDE {
50    return NULL;
51  }
52  virtual void OnMouseEventInTab(views::View* source,
53                                 const ui::MouseEvent& event) OVERRIDE {}
54  virtual bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) OVERRIDE {
55    return true;
56  }
57  virtual bool IsImmersiveStyle() const OVERRIDE { return immersive_style_; }
58
59 private:
60  ui::ListSelectionModel selection_model_;
61  bool immersive_style_;
62
63  DISALLOW_COPY_AND_ASSIGN(FakeTabController);
64};
65
66class TabTest : public views::ViewsTestBase {
67 public:
68  TabTest() {}
69  virtual ~TabTest() {}
70
71  static bool IconAnimationInvariant(const Tab& tab) {
72    bool capture_invariant =
73        tab.data().CaptureActive() == (tab.icon_animation_.get() != NULL);
74    bool audio_invariant =
75        !tab.data().AudioActive() || tab.tab_audio_indicator_->IsAnimating();
76    return capture_invariant && audio_invariant;
77  }
78};
79
80TEST_F(TabTest, HitTestTopPixel) {
81  Widget widget;
82  Widget::InitParams params(CreateParams(Widget::InitParams::TYPE_WINDOW));
83  params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
84  params.bounds.SetRect(10, 20, 300, 400);
85  widget.Init(params);
86
87  FakeTabController tab_controller;
88  Tab tab(&tab_controller);
89  widget.GetContentsView()->AddChildView(&tab);
90  tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize()));
91
92  // Tabs have some shadow in the top, so by default we don't hit the tab there.
93  int middle_x = tab.width() / 2;
94  EXPECT_FALSE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
95
96  // Tabs are slanted, so a click halfway down the left edge won't hit it.
97  int middle_y = tab.height() / 2;
98  EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, middle_y)));
99
100  // If the window is maximized, however, we want clicks in the top edge to
101  // select the tab.
102  widget.Maximize();
103  EXPECT_TRUE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
104
105  // But clicks in the area above the slanted sides should still miss.
106  EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, 0)));
107  EXPECT_FALSE(tab.HitTestPoint(gfx::Point(tab.width() - 1, 0)));
108}
109
110// Regression test for http://crbug.com/226253. Calling Layout() more than once
111// shouldn't change the insets of the close button.
112TEST_F(TabTest, CloseButtonLayout) {
113  FakeTabController tab_controller;
114  Tab tab(&tab_controller);
115  tab.SetBounds(0, 0, 100, 50);
116  tab.Layout();
117  gfx::Insets close_button_insets = tab.close_button_->GetInsets();
118  tab.Layout();
119  gfx::Insets close_button_insets_2 = tab.close_button_->GetInsets();
120  EXPECT_EQ(close_button_insets.top(), close_button_insets_2.top());
121  EXPECT_EQ(close_button_insets.left(), close_button_insets_2.left());
122  EXPECT_EQ(close_button_insets.bottom(), close_button_insets_2.bottom());
123  EXPECT_EQ(close_button_insets.right(), close_button_insets_2.right());
124
125  // Also make sure the close button is sized as large as the tab.
126  EXPECT_EQ(50, tab.close_button_->bounds().height());
127}
128
129TEST_F(TabTest, ActivityIndicators) {
130  FakeTabController controller;
131  Tab tab(&controller);
132
133  SkBitmap bitmap;
134  bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
135  bitmap.allocPixels();
136
137  TabRendererData data;
138  data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
139  tab.SetData(data);
140
141  // Audio starts and stops.
142  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
143  tab.SetData(data);
144  EXPECT_TRUE(IconAnimationInvariant(tab));
145  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
146  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
147  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
148  tab.SetData(data);
149  EXPECT_TRUE(IconAnimationInvariant(tab));
150  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
151  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
152  EXPECT_TRUE(IconAnimationInvariant(tab));
153
154  // Capture starts and stops.
155  data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
156  tab.SetData(data);
157  EXPECT_TRUE(IconAnimationInvariant(tab));
158  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
159  EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
160  data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
161  tab.SetData(data);
162  EXPECT_TRUE(IconAnimationInvariant(tab));
163  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
164  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
165  EXPECT_TRUE(IconAnimationInvariant(tab));
166
167  // Audio starts then capture starts, then audio stops then capture stops.
168  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
169  tab.SetData(data);
170  data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
171  tab.SetData(data);
172  EXPECT_TRUE(IconAnimationInvariant(tab));
173  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
174  EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
175
176  data.title = ASCIIToUTF16("test X");
177  tab.SetData(data);
178  EXPECT_TRUE(IconAnimationInvariant(tab));
179
180  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
181  tab.SetData(data);
182  EXPECT_TRUE(IconAnimationInvariant(tab));
183  EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
184  data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
185  tab.SetData(data);
186  EXPECT_TRUE(IconAnimationInvariant(tab));
187  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
188  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
189
190  // Audio starts then capture starts, then capture stops then audio stops.
191  data.audio_state = TabRendererData::AUDIO_STATE_PLAYING;
192  tab.SetData(data);
193  data.capture_state = TabRendererData::CAPTURE_STATE_RECORDING;
194  tab.SetData(data);
195  EXPECT_TRUE(IconAnimationInvariant(tab));
196  EXPECT_EQ(TabRendererData::AUDIO_STATE_PLAYING, tab.data().audio_state);
197  EXPECT_EQ(TabRendererData::CAPTURE_STATE_RECORDING, tab.data().capture_state);
198
199  data.title = ASCIIToUTF16("test Y");
200  tab.SetData(data);
201  EXPECT_TRUE(IconAnimationInvariant(tab));
202
203  data.capture_state = TabRendererData::CAPTURE_STATE_NONE;
204  tab.SetData(data);
205  EXPECT_TRUE(IconAnimationInvariant(tab));
206  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
207
208  data.audio_state = TabRendererData::AUDIO_STATE_NONE;
209  tab.SetData(data);
210  EXPECT_TRUE(IconAnimationInvariant(tab));
211  EXPECT_EQ(TabRendererData::AUDIO_STATE_NONE, tab.data().audio_state);
212  EXPECT_EQ(TabRendererData::CAPTURE_STATE_NONE, tab.data().capture_state);
213  EXPECT_TRUE(IconAnimationInvariant(tab));
214}
215