aura: Stop converting Rect to RectF implicitly.
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / tab_strip_unittest.cc
blob4196a7c12ac5077a4582f1164cad0d8d5d115148
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.
5 #include "chrome/browser/ui/views/tabs/tab_strip.h"
7 #include "base/message_loop/message_loop.h"
8 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h"
9 #include "chrome/browser/ui/views/tabs/tab.h"
10 #include "chrome/browser/ui/views/tabs/tab_strip.h"
11 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
12 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h"
13 #include "chrome/test/base/testing_profile.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gfx/canvas.h"
16 #include "ui/gfx/geometry/rect_conversions.h"
17 #include "ui/gfx/path.h"
18 #include "ui/gfx/skia_util.h"
19 #include "ui/views/test/views_test_base.h"
20 #include "ui/views/view.h"
21 #include "ui/views/view_targeter.h"
22 #include "ui/views/widget/widget.h"
24 namespace {
26 // Walks up the views hierarchy until it finds a tab view. It returns the
27 // found tab view, on NULL if none is found.
28 views::View* FindTabView(views::View* view) {
29 views::View* current = view;
30 while (current && strcmp(current->GetClassName(), Tab::kViewClassName)) {
31 current = current->parent();
33 return current;
36 } // namespace
38 class TestTabStripObserver : public TabStripObserver {
39 public:
40 explicit TestTabStripObserver(TabStrip* tab_strip)
41 : tab_strip_(tab_strip),
42 last_tab_added_(-1),
43 last_tab_removed_(-1),
44 last_tab_moved_from_(-1),
45 last_tab_moved_to_(-1),
46 tabstrip_deleted_(false) {
47 tab_strip_->AddObserver(this);
50 ~TestTabStripObserver() override {
51 if (tab_strip_)
52 tab_strip_->RemoveObserver(this);
55 int last_tab_added() const { return last_tab_added_; }
56 int last_tab_removed() const { return last_tab_removed_; }
57 int last_tab_moved_from() const { return last_tab_moved_from_; }
58 int last_tab_moved_to() const { return last_tab_moved_to_; }
59 bool tabstrip_deleted() const { return tabstrip_deleted_; }
61 private:
62 // TabStripObserver overrides.
63 void TabStripAddedTabAt(TabStrip* tab_strip, int index) override {
64 last_tab_added_ = index;
67 void TabStripMovedTab(TabStrip* tab_strip,
68 int from_index,
69 int to_index) override {
70 last_tab_moved_from_ = from_index;
71 last_tab_moved_to_ = to_index;
74 void TabStripRemovedTabAt(TabStrip* tab_strip, int index) override {
75 last_tab_removed_ = index;
78 void TabStripDeleted(TabStrip* tab_strip) override {
79 tabstrip_deleted_ = true;
80 tab_strip_ = NULL;
83 TabStrip* tab_strip_;
84 int last_tab_added_;
85 int last_tab_removed_;
86 int last_tab_moved_from_;
87 int last_tab_moved_to_;
88 bool tabstrip_deleted_;
90 DISALLOW_COPY_AND_ASSIGN(TestTabStripObserver);
93 class TabStripTest : public views::ViewsTestBase {
94 public:
95 TabStripTest()
96 : controller_(NULL),
97 tab_strip_(NULL) {
100 ~TabStripTest() override {}
102 void SetUp() override {
103 views::ViewsTestBase::SetUp();
105 controller_ = new FakeBaseTabStripController;
106 tab_strip_ = new TabStrip(controller_);
107 controller_->set_tab_strip(tab_strip_);
108 // Do this to force TabStrip to create the buttons.
109 parent_.AddChildView(tab_strip_);
110 parent_.set_owned_by_client();
112 widget_.reset(new views::Widget);
113 views::Widget::InitParams init_params =
114 CreateParams(views::Widget::InitParams::TYPE_POPUP);
115 init_params.ownership =
116 views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
117 init_params.bounds = gfx::Rect(0, 0, 200, 200);
118 widget_->Init(init_params);
119 widget_->SetContentsView(&parent_);
122 void TearDown() override {
123 widget_.reset();
124 views::ViewsTestBase::TearDown();
127 // Forces a call to OnPaint() for each tab in |tab_strip_| in order to
128 // trigger a layout, which is needed to update the visibility of tab
129 // close buttons after a tab switch or close. Note that painting does
130 // not occur in unit tests, which is why this helper is used.
131 void TriggerPaintOfAllTabs() {
132 gfx::Canvas canvas;
133 for (int i = 0; i < tab_strip_->tab_count(); ++i)
134 tab_strip_->tab_at(i)->OnPaint(&canvas);
137 protected:
138 // Returns the rectangular hit test region of |tab| in |tab|'s local
139 // coordinate space.
140 gfx::Rect GetTabHitTestMask(Tab* tab) {
141 views::ViewTargeter* targeter = tab->targeter();
142 DCHECK(targeter);
143 views::MaskedTargeterDelegate* delegate =
144 static_cast<views::MaskedTargeterDelegate*>(tab);
146 gfx::Path mask;
147 bool valid_mask = delegate->GetHitTestMask(&mask);
148 DCHECK(valid_mask);
150 return gfx::ToEnclosingRect((gfx::SkRectToRectF(mask.getBounds())));
153 // Returns the rectangular hit test region of the tab close button of
154 // |tab| in |tab|'s coordinate space (including padding if |padding|
155 // is true).
156 gfx::Rect GetTabCloseHitTestMask(Tab* tab, bool padding) {
157 gfx::RectF bounds_f = gfx::RectF(tab->close_button_->GetContentsBounds());
158 if (padding)
159 bounds_f = gfx::RectF(tab->close_button_->GetLocalBounds());
160 views::View::ConvertRectToTarget(tab->close_button_, tab, &bounds_f);
161 return gfx::ToEnclosingRect(bounds_f);
164 // Checks whether |tab| contains |point_in_tabstrip_coords|, where the point
165 // is in |tab_strip_| coordinates.
166 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords) {
167 gfx::Point point_in_tab_coords(point_in_tabstrip_coords);
168 views::View::ConvertPointToTarget(tab_strip_, tab, &point_in_tab_coords);
169 return tab->HitTestPoint(point_in_tab_coords);
172 // Owned by TabStrip.
173 FakeBaseTabStripController* controller_;
174 // Owns |tab_strip_|.
175 views::View parent_;
176 TabStrip* tab_strip_;
177 scoped_ptr<views::Widget> widget_;
179 private:
180 DISALLOW_COPY_AND_ASSIGN(TabStripTest);
183 TEST_F(TabStripTest, GetModelCount) {
184 EXPECT_EQ(0, tab_strip_->GetModelCount());
187 TEST_F(TabStripTest, IsValidModelIndex) {
188 EXPECT_FALSE(tab_strip_->IsValidModelIndex(0));
191 TEST_F(TabStripTest, tab_count) {
192 EXPECT_EQ(0, tab_strip_->tab_count());
195 TEST_F(TabStripTest, AddTabAt) {
196 TestTabStripObserver observer(tab_strip_);
197 tab_strip_->AddTabAt(0, TabRendererData(), false);
198 ASSERT_EQ(1, tab_strip_->tab_count());
199 EXPECT_EQ(0, observer.last_tab_added());
200 Tab* tab = tab_strip_->tab_at(0);
201 EXPECT_FALSE(tab == NULL);
204 // Confirms that TabStripObserver::TabStripDeleted() is sent.
205 TEST_F(TabStripTest, TabStripDeleted) {
206 FakeBaseTabStripController* controller = new FakeBaseTabStripController;
207 TabStrip* tab_strip = new TabStrip(controller);
208 controller->set_tab_strip(tab_strip);
209 TestTabStripObserver observer(tab_strip);
210 delete tab_strip;
211 EXPECT_TRUE(observer.tabstrip_deleted());
214 TEST_F(TabStripTest, MoveTab) {
215 TestTabStripObserver observer(tab_strip_);
216 tab_strip_->AddTabAt(0, TabRendererData(), false);
217 tab_strip_->AddTabAt(1, TabRendererData(), false);
218 tab_strip_->AddTabAt(2, TabRendererData(), false);
219 ASSERT_EQ(3, tab_strip_->tab_count());
220 EXPECT_EQ(2, observer.last_tab_added());
221 Tab* tab = tab_strip_->tab_at(0);
222 tab_strip_->MoveTab(0, 1, TabRendererData());
223 EXPECT_EQ(0, observer.last_tab_moved_from());
224 EXPECT_EQ(1, observer.last_tab_moved_to());
225 EXPECT_EQ(tab, tab_strip_->tab_at(1));
228 // Verifies child views are deleted after an animation completes.
229 TEST_F(TabStripTest, RemoveTab) {
230 TestTabStripObserver observer(tab_strip_);
231 controller_->AddTab(0, false);
232 controller_->AddTab(1, false);
233 const int child_view_count = tab_strip_->child_count();
234 EXPECT_EQ(2, tab_strip_->tab_count());
235 controller_->RemoveTab(0);
236 EXPECT_EQ(0, observer.last_tab_removed());
237 // When removing a tab the tabcount should immediately decrement.
238 EXPECT_EQ(1, tab_strip_->tab_count());
239 // But the number of views should remain the same (it's animatining closed).
240 EXPECT_EQ(child_view_count, tab_strip_->child_count());
241 tab_strip_->SetBounds(0, 0, 200, 20);
242 // Layout at a different size should force the animation to end and delete
243 // the tab that was removed.
244 tab_strip_->Layout();
245 EXPECT_EQ(child_view_count - 1, tab_strip_->child_count());
247 // Remove the last tab to make sure things are cleaned up correctly when
248 // the TabStrip is destroyed and an animation is ongoing.
249 controller_->RemoveTab(0);
250 EXPECT_EQ(0, observer.last_tab_removed());
253 TEST_F(TabStripTest, VisibilityInOverflow) {
254 tab_strip_->SetBounds(0, 0, 200, 20);
256 // The first tab added to a reasonable-width strip should be visible. If we
257 // add enough additional tabs, eventually one should be invisible due to
258 // overflow.
259 int invisible_tab_index = 0;
260 for (; invisible_tab_index < 100; ++invisible_tab_index) {
261 controller_->AddTab(invisible_tab_index, false);
262 if (!tab_strip_->tab_at(invisible_tab_index)->visible())
263 break;
265 EXPECT_GT(invisible_tab_index, 0);
266 EXPECT_LT(invisible_tab_index, 100);
268 // The tabs before the invisible tab should still be visible.
269 for (int i = 0; i < invisible_tab_index; ++i)
270 EXPECT_TRUE(tab_strip_->tab_at(i)->visible());
272 // Enlarging the strip should result in the last tab becoming visible.
273 tab_strip_->SetBounds(0, 0, 400, 20);
274 EXPECT_TRUE(tab_strip_->tab_at(invisible_tab_index)->visible());
276 // Shrinking it again should re-hide the last tab.
277 tab_strip_->SetBounds(0, 0, 200, 20);
278 EXPECT_FALSE(tab_strip_->tab_at(invisible_tab_index)->visible());
280 // Shrinking it still more should make more tabs invisible, though not all.
281 // All the invisible tabs should be at the end of the strip.
282 tab_strip_->SetBounds(0, 0, 100, 20);
283 int i = 0;
284 for (; i < invisible_tab_index; ++i) {
285 if (!tab_strip_->tab_at(i)->visible())
286 break;
288 ASSERT_GT(i, 0);
289 EXPECT_LT(i, invisible_tab_index);
290 invisible_tab_index = i;
291 for (int i = invisible_tab_index + 1; i < tab_strip_->tab_count(); ++i)
292 EXPECT_FALSE(tab_strip_->tab_at(i)->visible());
294 // When we're already in overflow, adding tabs at the beginning or end of
295 // the strip should not change how many tabs are visible.
296 controller_->AddTab(tab_strip_->tab_count(), false);
297 EXPECT_TRUE(tab_strip_->tab_at(invisible_tab_index - 1)->visible());
298 EXPECT_FALSE(tab_strip_->tab_at(invisible_tab_index)->visible());
299 controller_->AddTab(0, false);
300 EXPECT_TRUE(tab_strip_->tab_at(invisible_tab_index - 1)->visible());
301 EXPECT_FALSE(tab_strip_->tab_at(invisible_tab_index)->visible());
303 // If we remove enough tabs, all the tabs should be visible.
304 for (int i = tab_strip_->tab_count() - 1; i >= invisible_tab_index; --i)
305 controller_->RemoveTab(i);
306 EXPECT_TRUE(tab_strip_->tab_at(tab_strip_->tab_count() - 1)->visible());
309 TEST_F(TabStripTest, ImmersiveMode) {
310 // Immersive mode defaults to off.
311 EXPECT_FALSE(tab_strip_->IsImmersiveStyle());
313 // Tab strip defaults to normal tab height.
314 int normal_height = Tab::GetMinimumUnselectedSize().height();
315 EXPECT_EQ(normal_height, tab_strip_->GetPreferredSize().height());
317 // Tab strip can toggle immersive mode.
318 tab_strip_->SetImmersiveStyle(true);
319 EXPECT_TRUE(tab_strip_->IsImmersiveStyle());
321 // Now tabs have the immersive height.
322 int immersive_height = Tab::GetImmersiveHeight();
323 EXPECT_EQ(immersive_height, tab_strip_->GetPreferredSize().height());
325 // Sanity-check immersive tabs are shorter than normal tabs.
326 EXPECT_LT(immersive_height, normal_height);
329 // Creates a tab strip in stacked layout mode and verifies the correctness
330 // of hit tests against the visible/occluded regions of a tab and the tab
331 // close button of the active tab.
332 TEST_F(TabStripTest, TabHitTestMaskWhenStacked) {
333 tab_strip_->SetBounds(0, 0, 300, 20);
335 controller_->AddTab(0, false);
336 controller_->AddTab(1, true);
337 controller_->AddTab(2, false);
338 controller_->AddTab(3, false);
339 ASSERT_EQ(4, tab_strip_->tab_count());
341 Tab* left_tab = tab_strip_->tab_at(0);
342 left_tab->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), gfx::Size(200, 20)));
344 Tab* active_tab = tab_strip_->tab_at(1);
345 active_tab->SetBoundsRect(gfx::Rect(gfx::Point(150, 0), gfx::Size(200, 20)));
346 ASSERT_TRUE(active_tab->IsActive());
348 Tab* right_tab = tab_strip_->tab_at(2);
349 right_tab->SetBoundsRect(gfx::Rect(gfx::Point(300, 0), gfx::Size(200, 20)));
351 Tab* most_right_tab = tab_strip_->tab_at(3);
352 most_right_tab->SetBoundsRect(gfx::Rect(gfx::Point(450, 0),
353 gfx::Size(200, 20)));
355 // Switch to stacked layout mode and force a layout to ensure tabs stack.
356 tab_strip_->SetStackedLayout(true);
357 tab_strip_->DoLayout();
360 // Tests involving |left_tab|, which has part of its bounds occluded by
361 // |active_tab|.
363 // Bounds of the tab's hit test mask.
364 gfx::Rect tab_bounds = GetTabHitTestMask(left_tab);
365 EXPECT_EQ(gfx::Rect(6, 2, 61, 27).ToString(), tab_bounds.ToString());
367 // Hit tests in the non-occuluded region of the tab.
368 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(6, 2, 2, 2)));
369 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(6, 2, 1, 1)));
370 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(30, 15, 1, 1)));
371 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(30, 15, 25, 35)));
372 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(-10, -5, 20, 30)));
374 // Hit tests in the occluded region of the tab.
375 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(70, 15, 2, 2)));
376 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(70, -15, 30, 40)));
377 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(87, 20, 5, 3)));
379 // Hit tests completely outside of the tab.
380 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(-20, -25, 1, 1)));
381 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(-20, -25, 3, 19)));
384 // Tests involving |active_tab|, which is completely visible.
386 tab_bounds = GetTabHitTestMask(active_tab);
387 EXPECT_EQ(gfx::Rect(6, 2, 108, 27).ToString(), tab_bounds.ToString());
388 gfx::Rect contents_bounds = GetTabCloseHitTestMask(active_tab, false);
389 // TODO(tdanderson): Uncomment this line once crbug.com/311609 is resolved.
390 // EXPECT_EQ(gfx::Rect(84, 8, 18, 18).ToString(), contents_bounds.ToString());
392 // Verify that the tab close button is not occluded.
393 EXPECT_TRUE(tab_bounds.Contains(contents_bounds));
395 // Bounds of the tab close button (without padding) in the tab's
396 // coordinate space.
397 gfx::Rect local_bounds = GetTabCloseHitTestMask(active_tab, true);
398 EXPECT_EQ(gfx::Rect(81, 0, 39, 29).ToString(), local_bounds.ToString());
400 // Hit tests within the tab.
401 EXPECT_TRUE(active_tab->HitTestRect(gfx::Rect(30, 15, 1, 1)));
402 EXPECT_TRUE(active_tab->HitTestRect(gfx::Rect(30, 15, 2, 2)));
404 // Hit tests against the tab close button. Note that hit tests from either
405 // mouse or touch should both fail if they are strictly contained within
406 // the button's padding.
407 views::ImageButton* active_close = active_tab->close_button_;
408 EXPECT_FALSE(active_close->HitTestRect(gfx::Rect(1, 1, 1, 1)));
409 EXPECT_FALSE(active_close->HitTestRect(gfx::Rect(1, 1, 2, 2)));
410 EXPECT_TRUE(active_close->HitTestRect(gfx::Rect(10, 10, 1, 1)));
411 EXPECT_TRUE(active_close->HitTestRect(gfx::Rect(10, 10, 25, 35)));
414 // Tests involving |most_right_tab|, which has part of its bounds occluded
415 // by |right_tab|.
417 tab_bounds = GetTabHitTestMask(most_right_tab);
418 EXPECT_EQ(gfx::Rect(84, 2, 30, 27).ToString(), tab_bounds.ToString());
420 // Hit tests in the occluded region of the tab.
421 EXPECT_FALSE(most_right_tab->HitTestRect(gfx::Rect(20, 15, 1, 1)));
422 EXPECT_FALSE(most_right_tab->HitTestRect(gfx::Rect(20, 15, 5, 6)));
424 // Hit tests in the non-occluded region of the tab.
425 EXPECT_TRUE(most_right_tab->HitTestRect(gfx::Rect(85, 15, 1, 1)));
426 EXPECT_TRUE(most_right_tab->HitTestRect(gfx::Rect(85, 15, 2, 2)));
429 // Tests that the tab close buttons of non-active tabs are hidden when
430 // the tabstrip is in stacked tab mode.
431 TEST_F(TabStripTest, TabCloseButtonVisibilityWhenStacked) {
432 tab_strip_->SetBounds(0, 0, 300, 20);
433 controller_->AddTab(0, false);
434 controller_->AddTab(1, true);
435 controller_->AddTab(2, false);
436 ASSERT_EQ(3, tab_strip_->tab_count());
438 Tab* tab0 = tab_strip_->tab_at(0);
439 Tab* tab1 = tab_strip_->tab_at(1);
440 ASSERT_TRUE(tab1->IsActive());
441 Tab* tab2 = tab_strip_->tab_at(2);
443 // Ensure that all tab close buttons are initially visible.
444 TriggerPaintOfAllTabs();
445 EXPECT_TRUE(tab0->showing_close_button_);
446 EXPECT_TRUE(tab1->showing_close_button_);
447 EXPECT_TRUE(tab2->showing_close_button_);
449 // Enter stacked layout mode and verify this sets |touch_layout_|.
450 ASSERT_FALSE(tab_strip_->touch_layout_.get());
451 tab_strip_->SetStackedLayout(true);
452 TriggerPaintOfAllTabs();
453 ASSERT_TRUE(tab_strip_->touch_layout_.get());
455 // Only the close button of the active tab should be visible in stacked
456 // layout mode.
457 EXPECT_FALSE(tab0->showing_close_button_);
458 EXPECT_TRUE(tab1->showing_close_button_);
459 EXPECT_FALSE(tab2->showing_close_button_);
461 // An inactive tab added to the tabstrip should not show
462 // its tab close button.
463 controller_->AddTab(3, false);
464 Tab* tab3 = tab_strip_->tab_at(3);
465 EXPECT_FALSE(tab0->showing_close_button_);
466 EXPECT_TRUE(tab1->showing_close_button_);
467 EXPECT_FALSE(tab2->showing_close_button_);
468 EXPECT_FALSE(tab3->showing_close_button_);
470 // After switching tabs, the previously-active tab should have its
471 // tab close button hidden and the newly-active tab should show
472 // its tab close button.
473 tab_strip_->SelectTab(tab2);
474 TriggerPaintOfAllTabs();
475 ASSERT_FALSE(tab1->IsActive());
476 ASSERT_TRUE(tab2->IsActive());
477 EXPECT_FALSE(tab0->showing_close_button_);
478 EXPECT_FALSE(tab1->showing_close_button_);
479 EXPECT_TRUE(tab2->showing_close_button_);
480 EXPECT_FALSE(tab3->showing_close_button_);
482 // After closing the active tab, the tab which becomes active should
483 // show its tab close button.
484 tab_strip_->CloseTab(tab1, CLOSE_TAB_FROM_TOUCH);
485 tab1 = nullptr;
486 ASSERT_TRUE(tab2->IsActive());
487 TriggerPaintOfAllTabs();
488 EXPECT_FALSE(tab0->showing_close_button_);
489 EXPECT_TRUE(tab2->showing_close_button_);
490 EXPECT_FALSE(tab3->showing_close_button_);
492 // All tab close buttons should be shown when disengaging stacked tab mode.
493 tab_strip_->SetStackedLayout(false);
494 TriggerPaintOfAllTabs();
495 ASSERT_FALSE(tab_strip_->touch_layout_.get());
496 EXPECT_TRUE(tab0->showing_close_button_);
497 EXPECT_TRUE(tab2->showing_close_button_);
498 EXPECT_TRUE(tab3->showing_close_button_);
501 TEST_F(TabStripTest, GetEventHandlerForOverlappingArea) {
502 tab_strip_->SetBounds(0, 0, 1000, 20);
504 controller_->AddTab(0, false);
505 controller_->AddTab(1, true);
506 controller_->AddTab(2, false);
507 controller_->AddTab(3, false);
508 ASSERT_EQ(4, tab_strip_->tab_count());
510 // Verify that the active tab will be a tooltip handler for points that hit
511 // it.
512 Tab* left_tab = tab_strip_->tab_at(0);
513 left_tab->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), gfx::Size(200, 20)));
515 Tab* active_tab = tab_strip_->tab_at(1);
516 active_tab->SetBoundsRect(gfx::Rect(gfx::Point(150, 0), gfx::Size(200, 20)));
517 ASSERT_TRUE(active_tab->IsActive());
519 Tab* right_tab = tab_strip_->tab_at(2);
520 right_tab->SetBoundsRect(gfx::Rect(gfx::Point(300, 0), gfx::Size(200, 20)));
522 Tab* most_right_tab = tab_strip_->tab_at(3);
523 most_right_tab->SetBoundsRect(gfx::Rect(gfx::Point(450, 0),
524 gfx::Size(200, 20)));
526 // Test that active tabs gets events from area in which it overlaps with its
527 // left neighbour.
528 gfx::Point left_overlap(
529 (active_tab->x() + left_tab->bounds().right() + 1) / 2,
530 active_tab->bounds().bottom() - 1);
532 // Sanity check that the point is in both active and left tab.
533 ASSERT_TRUE(IsPointInTab(active_tab, left_overlap));
534 ASSERT_TRUE(IsPointInTab(left_tab, left_overlap));
536 EXPECT_EQ(active_tab,
537 FindTabView(tab_strip_->GetEventHandlerForPoint(left_overlap)));
539 // Test that active tabs gets events from area in which it overlaps with its
540 // right neighbour.
541 gfx::Point right_overlap((active_tab->bounds().right() + right_tab->x()) / 2,
542 active_tab->bounds().bottom() - 1);
544 // Sanity check that the point is in both active and right tab.
545 ASSERT_TRUE(IsPointInTab(active_tab, right_overlap));
546 ASSERT_TRUE(IsPointInTab(right_tab, right_overlap));
548 EXPECT_EQ(active_tab,
549 FindTabView(tab_strip_->GetEventHandlerForPoint(right_overlap)));
551 // Test that if neither of tabs is active, the left one is selected.
552 gfx::Point unactive_overlap(
553 (right_tab->x() + most_right_tab->bounds().right() + 1) / 2,
554 right_tab->bounds().bottom() - 1);
556 // Sanity check that the point is in both active and left tab.
557 ASSERT_TRUE(IsPointInTab(right_tab, unactive_overlap));
558 ASSERT_TRUE(IsPointInTab(most_right_tab, unactive_overlap));
560 EXPECT_EQ(right_tab,
561 FindTabView(tab_strip_->GetEventHandlerForPoint(unactive_overlap)));
564 TEST_F(TabStripTest, GetTooltipHandler) {
565 tab_strip_->SetBounds(0, 0, 1000, 20);
567 controller_->AddTab(0, false);
568 controller_->AddTab(1, true);
569 controller_->AddTab(2, false);
570 controller_->AddTab(3, false);
571 ASSERT_EQ(4, tab_strip_->tab_count());
573 // Verify that the active tab will be a tooltip handler for points that hit
574 // it.
575 Tab* left_tab = tab_strip_->tab_at(0);
576 left_tab->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), gfx::Size(200, 20)));
578 Tab* active_tab = tab_strip_->tab_at(1);
579 active_tab->SetBoundsRect(gfx::Rect(gfx::Point(150, 0), gfx::Size(200, 20)));
580 ASSERT_TRUE(active_tab->IsActive());
582 Tab* right_tab = tab_strip_->tab_at(2);
583 right_tab->SetBoundsRect(gfx::Rect(gfx::Point(300, 0), gfx::Size(200, 20)));
585 Tab* most_right_tab = tab_strip_->tab_at(3);
586 most_right_tab->SetBoundsRect(gfx::Rect(gfx::Point(450, 0),
587 gfx::Size(200, 20)));
589 // Test that active_tab handles tooltips from area in which it overlaps with
590 // its left neighbour.
591 gfx::Point left_overlap(
592 (active_tab->x() + left_tab->bounds().right() + 1) / 2,
593 active_tab->bounds().bottom() - 1);
595 // Sanity check that the point is in both active and left tab.
596 ASSERT_TRUE(IsPointInTab(active_tab, left_overlap));
597 ASSERT_TRUE(IsPointInTab(left_tab, left_overlap));
599 EXPECT_EQ(active_tab,
600 FindTabView(tab_strip_->GetTooltipHandlerForPoint(left_overlap)));
602 // Test that active_tab handles tooltips from area in which it overlaps with
603 // its right neighbour.
604 gfx::Point right_overlap((active_tab->bounds().right() + right_tab->x()) / 2,
605 active_tab->bounds().bottom() - 1);
607 // Sanity check that the point is in both active and right tab.
608 ASSERT_TRUE(IsPointInTab(active_tab, right_overlap));
609 ASSERT_TRUE(IsPointInTab(right_tab, right_overlap));
611 EXPECT_EQ(active_tab,
612 FindTabView(tab_strip_->GetTooltipHandlerForPoint(right_overlap)));
614 // Test that if neither of tabs is active, the left one is selected.
615 gfx::Point unactive_overlap(
616 (right_tab->x() + most_right_tab->bounds().right() + 1) / 2,
617 right_tab->bounds().bottom() - 1);
619 // Sanity check that the point is in both active and left tab.
620 ASSERT_TRUE(IsPointInTab(right_tab, unactive_overlap));
621 ASSERT_TRUE(IsPointInTab(most_right_tab, unactive_overlap));
623 EXPECT_EQ(
624 right_tab,
625 FindTabView(tab_strip_->GetTooltipHandlerForPoint(unactive_overlap)));
627 // Confirm that tab strip doe not return tooltip handler for points that
628 // don't hit it.
629 EXPECT_FALSE(tab_strip_->GetTooltipHandlerForPoint(gfx::Point(-1, 2)));