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