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