- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / bubble / bubble_delegate_unittest.cc
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 "base/run_loop.h"
6 #include "ui/base/hit_test.h"
7 #include "ui/views/bubble/bubble_delegate.h"
8 #include "ui/views/bubble/bubble_frame_view.h"
9 #include "ui/views/test/test_widget_observer.h"
10 #include "ui/views/test/views_test_base.h"
11 #include "ui/views/widget/widget.h"
12 #include "ui/views/widget/widget_observer.h"
13
14 #if defined(USE_AURA)
15 #include "ui/aura/env.h"
16 #endif
17
18 namespace views {
19
20 namespace {
21
22 class TestBubbleDelegateView : public BubbleDelegateView {
23  public:
24   TestBubbleDelegateView(View* anchor_view)
25       : BubbleDelegateView(anchor_view, BubbleBorder::TOP_LEFT),
26         view_(new View()) {
27     view_->set_focusable(true);
28     AddChildView(view_);
29   }
30   virtual ~TestBubbleDelegateView() {}
31
32   void SetAnchorRectForTest(gfx::Rect rect) {
33     set_anchor_rect(rect);
34   }
35
36   void SetAnchorViewForTest(View* view) {
37     SetAnchorView(view);
38   }
39
40   // BubbleDelegateView overrides:
41   virtual View* GetInitiallyFocusedView() OVERRIDE { return view_; }
42   virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(200, 200); }
43   virtual int GetFadeDuration() OVERRIDE { return 1; }
44
45  private:
46   View* view_;
47
48   DISALLOW_COPY_AND_ASSIGN(TestBubbleDelegateView);
49 };
50
51 class BubbleDelegateTest : public ViewsTestBase {
52  public:
53   BubbleDelegateTest() {}
54   virtual ~BubbleDelegateTest() {}
55
56   // Creates a test widget that owns its native widget.
57   Widget* CreateTestWidget() {
58     Widget* widget = new Widget();
59     Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
60     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
61     widget->Init(params);
62     return widget;
63   }
64
65  private:
66   DISALLOW_COPY_AND_ASSIGN(BubbleDelegateTest);
67 };
68
69 }  // namespace
70
71 TEST_F(BubbleDelegateTest, CreateDelegate) {
72   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
73   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
74       anchor_widget->GetContentsView(), BubbleBorder::NONE);
75   bubble_delegate->set_color(SK_ColorGREEN);
76   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
77   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
78   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
79   test::TestWidgetObserver bubble_observer(bubble_widget);
80   bubble_widget->Show();
81
82   BubbleBorder* border = bubble_delegate->GetBubbleFrameView()->bubble_border();
83   EXPECT_EQ(bubble_delegate->arrow(), border->arrow());
84   EXPECT_EQ(bubble_delegate->color(), border->background_color());
85
86   EXPECT_FALSE(bubble_observer.widget_closed());
87   bubble_widget->CloseNow();
88   EXPECT_TRUE(bubble_observer.widget_closed());
89 }
90
91 TEST_F(BubbleDelegateTest, CloseAnchorWidget) {
92   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
93   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
94       anchor_widget->GetContentsView(), BubbleBorder::NONE);
95   // Preventing close on deactivate should not prevent closing with the anchor.
96   bubble_delegate->set_close_on_deactivate(false);
97   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
98   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
99   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
100   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
101   test::TestWidgetObserver bubble_observer(bubble_widget);
102   EXPECT_FALSE(bubble_observer.widget_closed());
103
104   bubble_widget->Show();
105   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
106   EXPECT_FALSE(bubble_observer.widget_closed());
107
108 #if defined(USE_AURA)
109   // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
110   //            aura::test::TestActivationClient::OnWindowDestroyed().
111   scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
112   EXPECT_FALSE(bubble_observer.widget_closed());
113 #endif
114
115   // Ensure that closing the anchor widget also closes the bubble itself.
116   anchor_widget->CloseNow();
117   EXPECT_TRUE(bubble_observer.widget_closed());
118 }
119
120 // This test checks that the bubble delegate is capable to handle an early
121 // destruction of the used anchor view. (Animations and delayed closure of the
122 // bubble will call upon the anchor view to get its location).
123 TEST_F(BubbleDelegateTest, CloseAnchorViewTest) {
124   // Create an anchor widget and add a view to be used as an anchor view.
125   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
126   scoped_ptr<View> anchor_view(new View());
127   anchor_widget->GetContentsView()->AddChildView(anchor_view.get());
128   TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView(
129       anchor_view.get());
130   // Prevent flakes by avoiding closing on activation changes.
131   bubble_delegate->set_close_on_deactivate(false);
132   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
133
134   // Check that the anchor view is correct and set up an anchor view rect.
135   // Make sure that this rect will get ignored (as long as the anchor view is
136   // attached).
137   EXPECT_EQ(anchor_view, bubble_delegate->GetAnchorView());
138   const gfx::Rect set_anchor_rect = gfx::Rect(10, 10, 100, 100);
139   bubble_delegate->SetAnchorRectForTest(set_anchor_rect);
140   const gfx::Rect view_rect = bubble_delegate->GetAnchorRect();
141   EXPECT_NE(view_rect.ToString(), set_anchor_rect.ToString());
142
143   // Create the bubble.
144   bubble_widget->Show();
145   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
146
147   // Remove now the anchor view and make sure that the original found rect
148   // is still kept, so that the bubble does not jump when the view gets deleted.
149   anchor_widget->GetContentsView()->RemoveChildView(anchor_view.get());
150   anchor_view.reset();
151   EXPECT_EQ(NULL, bubble_delegate->GetAnchorView());
152   EXPECT_EQ(view_rect.ToString(), bubble_delegate->GetAnchorRect().ToString());
153 }
154
155 // Testing that a move of the anchor view will lead to new bubble locations.
156 TEST_F(BubbleDelegateTest, TestAnchorRectMovesWithViewTest) {
157   // Create an anchor widget and add a view to be used as anchor view.
158   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
159   TestBubbleDelegateView* bubble_delegate = new TestBubbleDelegateView(
160       anchor_widget->GetContentsView());
161   BubbleDelegateView::CreateBubble(bubble_delegate);
162
163   anchor_widget->GetContentsView()->SetBounds(10, 10, 100, 100);
164   const gfx::Rect view_rect = bubble_delegate->GetAnchorRect();
165
166   anchor_widget->GetContentsView()->SetBounds(20, 10, 100, 100);
167   const gfx::Rect view_rect_2 = bubble_delegate->GetAnchorRect();
168   EXPECT_NE(view_rect.ToString(), view_rect_2.ToString());
169 }
170
171 TEST_F(BubbleDelegateTest, ResetAnchorWidget) {
172   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
173   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
174       anchor_widget->GetContentsView(), BubbleBorder::NONE);
175
176   // Make sure the bubble widget is parented to a widget other than the anchor
177   // widget so that closing the anchor widget does not close the bubble widget.
178   scoped_ptr<Widget> parent_widget(CreateTestWidget());
179   bubble_delegate->set_parent_window(parent_widget->GetNativeView());
180   // Preventing close on deactivate should not prevent closing with the parent.
181   bubble_delegate->set_close_on_deactivate(false);
182   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
183   EXPECT_EQ(bubble_delegate, bubble_widget->widget_delegate());
184   EXPECT_EQ(bubble_widget, bubble_delegate->GetWidget());
185   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
186   test::TestWidgetObserver bubble_observer(bubble_widget);
187   EXPECT_FALSE(bubble_observer.widget_closed());
188
189   // Showing and hiding the bubble widget should have no effect on its anchor.
190   bubble_widget->Show();
191   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
192   bubble_widget->Hide();
193   EXPECT_EQ(anchor_widget, bubble_delegate->anchor_widget());
194
195   // Ensure that closing the anchor widget clears the bubble's reference to that
196   // anchor widget, but the bubble itself does not close.
197   anchor_widget->CloseNow();
198   EXPECT_NE(anchor_widget, bubble_delegate->anchor_widget());
199   EXPECT_FALSE(bubble_observer.widget_closed());
200
201 #if defined(USE_AURA)
202   // TODO(msw): Remove activation hack to prevent bookkeeping errors in:
203   //            aura::test::TestActivationClient::OnWindowDestroyed().
204   scoped_ptr<Widget> smoke_and_mirrors_widget(CreateTestWidget());
205   EXPECT_FALSE(bubble_observer.widget_closed());
206 #endif
207
208   // Ensure that closing the parent widget also closes the bubble itself.
209   parent_widget->CloseNow();
210   EXPECT_TRUE(bubble_observer.widget_closed());
211 }
212
213 TEST_F(BubbleDelegateTest, InitiallyFocusedView) {
214   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
215   BubbleDelegateView* bubble_delegate = new BubbleDelegateView(
216       anchor_widget->GetContentsView(), BubbleBorder::NONE);
217   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
218   EXPECT_EQ(bubble_delegate->GetInitiallyFocusedView(),
219             bubble_widget->GetFocusManager()->GetFocusedView());
220   bubble_widget->CloseNow();
221 }
222
223 TEST_F(BubbleDelegateTest, NonClientHitTest) {
224   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
225   TestBubbleDelegateView* bubble_delegate =
226       new TestBubbleDelegateView(anchor_widget->GetContentsView());
227   BubbleDelegateView::CreateBubble(bubble_delegate);
228   BubbleFrameView* frame = bubble_delegate->GetBubbleFrameView();
229   const int border = frame->bubble_border()->GetBorderThickness();
230
231   struct {
232     const int point;
233     const int hit;
234   } cases[] = {
235     { border,      HTNOWHERE },
236     { border + 50, HTCLIENT  },
237     { 1000,        HTNOWHERE },
238   };
239
240   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
241     gfx::Point point(cases[i].point, cases[i].point);
242     EXPECT_EQ(cases[i].hit, frame->NonClientHitTest(point))
243         << " with border: " << border << ", at point " << cases[i].point;
244   }
245 }
246
247 // This class provides functionality to verify that the BubbleView shows up
248 // when we call BubbleDelegateView::StartFade(true) and is destroyed when we
249 // call BubbleDelegateView::StartFade(false).
250 class BubbleWidgetClosingTest : public BubbleDelegateTest,
251                                 public views::WidgetObserver {
252  public:
253   BubbleWidgetClosingTest() : bubble_destroyed_(false) {
254 #if defined(USE_AURA)
255     aura::Env::CreateInstance();
256     loop_.set_dispatcher(aura::Env::GetInstance()->GetDispatcher());
257 #endif
258   }
259
260   virtual ~BubbleWidgetClosingTest() {}
261
262   void Observe(views::Widget* widget) {
263     widget->AddObserver(this);
264   }
265
266   // views::WidgetObserver overrides.
267   virtual void OnWidgetDestroyed(Widget* widget) OVERRIDE {
268     bubble_destroyed_ = true;
269     widget->RemoveObserver(this);
270     loop_.Quit();
271   }
272
273   bool bubble_destroyed() const { return bubble_destroyed_; }
274
275   void RunNestedLoop() {
276     loop_.Run();
277   }
278
279  private:
280   bool bubble_destroyed_;
281   base::RunLoop loop_;
282
283   DISALLOW_COPY_AND_ASSIGN(BubbleWidgetClosingTest);
284 };
285
286 TEST_F(BubbleWidgetClosingTest, TestBubbleVisibilityAndClose) {
287   scoped_ptr<Widget> anchor_widget(CreateTestWidget());
288   TestBubbleDelegateView* bubble_delegate =
289       new TestBubbleDelegateView(anchor_widget->GetContentsView());
290   Widget* bubble_widget = BubbleDelegateView::CreateBubble(bubble_delegate);
291   EXPECT_FALSE(bubble_widget->IsVisible());
292
293   bubble_delegate->StartFade(true);
294   EXPECT_TRUE(bubble_widget->IsVisible());
295
296   EXPECT_EQ(bubble_delegate->GetInitiallyFocusedView(),
297             bubble_widget->GetFocusManager()->GetFocusedView());
298
299   Observe(bubble_widget);
300
301   bubble_delegate->StartFade(false);
302   RunNestedLoop();
303   EXPECT_TRUE(bubble_destroyed());
304 }
305
306 }  // namespace views