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 "ash/shell.h" 6#include "ash/test/ash_test_base.h" 7#include "base/strings/utf_string_conversions.h" 8#include "ui/aura/client/tooltip_client.h" 9#include "ui/aura/env.h" 10#include "ui/aura/root_window.h" 11#include "ui/aura/test/event_generator.h" 12#include "ui/aura/window.h" 13#include "ui/base/resource/resource_bundle.h" 14#include "ui/gfx/font.h" 15#include "ui/gfx/point.h" 16#include "ui/views/corewm/tooltip_controller.h" 17#include "ui/views/corewm/tooltip_controller_test_helper.h" 18#include "ui/views/view.h" 19#include "ui/views/widget/widget.h" 20 21using views::corewm::TooltipController; 22using views::corewm::test::TooltipTestView; 23using views::corewm::test::TooltipControllerTestHelper; 24 25// The tests in this file exercise bits of TooltipController that are hard to 26// test outside of ash. Meaning these tests require the shell and related things 27// to be installed. 28 29namespace ash { 30namespace test { 31 32namespace { 33 34views::Widget* CreateNewWidgetWithBoundsOn(int display, 35 const gfx::Rect& bounds) { 36 views::Widget* widget = new views::Widget; 37 views::Widget::InitParams params; 38 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS; 39 params.accept_events = true; 40 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 41 params.context = Shell::GetAllRootWindows().at(display); 42 params.child = true; 43 params.bounds = bounds; 44 widget->Init(params); 45 widget->Show(); 46 return widget; 47} 48 49views::Widget* CreateNewWidgetOn(int display) { 50 return CreateNewWidgetWithBoundsOn(display, gfx::Rect()); 51} 52 53void AddViewToWidgetAndResize(views::Widget* widget, views::View* view) { 54 if (!widget->GetContentsView()) { 55 views::View* contents_view = new views::View; 56 widget->SetContentsView(contents_view); 57 } 58 59 views::View* contents_view = widget->GetContentsView(); 60 contents_view->AddChildView(view); 61 view->SetBounds(contents_view->width(), 0, 100, 100); 62 gfx::Rect contents_view_bounds = contents_view->bounds(); 63 contents_view_bounds.Union(view->bounds()); 64 contents_view->SetBoundsRect(contents_view_bounds); 65 widget->SetBounds(gfx::Rect(widget->GetWindowBoundsInScreen().origin(), 66 contents_view_bounds.size())); 67} 68 69TooltipController* GetController() { 70 return static_cast<TooltipController*>( 71 aura::client::GetTooltipClient(Shell::GetPrimaryRootWindow())); 72} 73 74gfx::Font GetDefaultFont() { 75 return ui::ResourceBundle::GetSharedInstance().GetFont( 76 ui::ResourceBundle::BaseFont); 77} 78 79} // namespace 80 81class TooltipControllerTest : public AshTestBase { 82 public: 83 TooltipControllerTest() {} 84 virtual ~TooltipControllerTest() {} 85 86 virtual void SetUp() OVERRIDE { 87 AshTestBase::SetUp(); 88 helper_.reset(new TooltipControllerTestHelper(GetController())); 89 } 90 91 protected: 92 scoped_ptr<TooltipControllerTestHelper> helper_; 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(TooltipControllerTest); 96}; 97 98TEST_F(TooltipControllerTest, NonNullTooltipClient) { 99 EXPECT_TRUE(aura::client::GetTooltipClient(Shell::GetPrimaryRootWindow()) 100 != NULL); 101 EXPECT_EQ(base::string16(), helper_->GetTooltipText()); 102 EXPECT_EQ(NULL, helper_->GetTooltipWindow()); 103 EXPECT_FALSE(helper_->IsTooltipVisible()); 104} 105 106TEST_F(TooltipControllerTest, HideTooltipWhenCursorHidden) { 107 scoped_ptr<views::Widget> widget(CreateNewWidgetOn(0)); 108 TooltipTestView* view = new TooltipTestView; 109 AddViewToWidgetAndResize(widget.get(), view); 110 view->set_tooltip_text(ASCIIToUTF16("Tooltip Text")); 111 EXPECT_EQ(base::string16(), helper_->GetTooltipText()); 112 EXPECT_EQ(NULL, helper_->GetTooltipWindow()); 113 114 aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); 115 generator.MoveMouseRelativeTo(widget->GetNativeView(), 116 view->bounds().CenterPoint()); 117 base::string16 expected_tooltip = ASCIIToUTF16("Tooltip Text"); 118 119 // Fire tooltip timer so tooltip becomes visible. 120 helper_->FireTooltipTimer(); 121 EXPECT_TRUE(helper_->IsTooltipVisible()); 122 123 // Hide the cursor and check again. 124 ash::Shell::GetInstance()->cursor_manager()->DisableMouseEvents(); 125 helper_->FireTooltipTimer(); 126 EXPECT_FALSE(helper_->IsTooltipVisible()); 127 128 // Show the cursor and re-check. 129 ash::Shell::GetInstance()->cursor_manager()->EnableMouseEvents(); 130 helper_->FireTooltipTimer(); 131 EXPECT_TRUE(helper_->IsTooltipVisible()); 132} 133 134TEST_F(TooltipControllerTest, TooltipsOnMultiDisplayShouldNotCrash) { 135 if (!SupportsMultipleDisplays()) 136 return; 137 138 UpdateDisplay("1000x600,600x400"); 139 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 140 scoped_ptr<views::Widget> widget1(CreateNewWidgetWithBoundsOn( 141 0, gfx::Rect(10, 10, 100, 100))); 142 TooltipTestView* view1 = new TooltipTestView; 143 AddViewToWidgetAndResize(widget1.get(), view1); 144 view1->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 1")); 145 EXPECT_EQ(widget1->GetNativeView()->GetRootWindow(), root_windows[0]); 146 147 scoped_ptr<views::Widget> widget2(CreateNewWidgetWithBoundsOn( 148 1, gfx::Rect(1200, 10, 100, 100))); 149 TooltipTestView* view2 = new TooltipTestView; 150 AddViewToWidgetAndResize(widget2.get(), view2); 151 view2->set_tooltip_text(ASCIIToUTF16("Tooltip Text for view 2")); 152 EXPECT_EQ(widget2->GetNativeView()->GetRootWindow(), root_windows[1]); 153 154 // Show tooltip on second display. 155 aura::test::EventGenerator generator(root_windows[1]); 156 generator.MoveMouseRelativeTo(widget2->GetNativeView(), 157 view2->bounds().CenterPoint()); 158 helper_->FireTooltipTimer(); 159 EXPECT_TRUE(helper_->IsTooltipVisible()); 160 161 // Get rid of secondary display. This destroy's the tooltip's aura window. If 162 // we have handled this case, we will not crash in the following statement. 163 UpdateDisplay("1000x600"); 164#if !defined(OS_WIN) 165 // TODO(cpu): Detangle the window destruction notification. Currently 166 // the TooltipController::OnWindowDestroyed is not being called then the 167 // display is torn down so the tooltip is is still there. 168 EXPECT_FALSE(helper_->IsTooltipVisible()); 169#endif 170 EXPECT_EQ(widget2->GetNativeView()->GetRootWindow(), root_windows[0]); 171 172 // The tooltip should create a new aura window for itself, so we should still 173 // be able to show tooltips on the primary display. 174 aura::test::EventGenerator generator1(root_windows[0]); 175 generator1.MoveMouseRelativeTo(widget1->GetNativeView(), 176 view1->bounds().CenterPoint()); 177 helper_->FireTooltipTimer(); 178 EXPECT_TRUE(helper_->IsTooltipVisible()); 179} 180 181} // namespace test 182} // namespace ash 183