Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / events / cocoa / events_mac_unittest.mm
1 // Copyright 2014 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 "ui/events/event_utils.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/mac/scoped_cftyperef.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "ui/events/event_constants.h"
13 #import "ui/events/test/cocoa_test_event_utils.h"
14 #include "ui/gfx/point.h"
15 #import "ui/gfx/test/ui_cocoa_test_helper.h"
16
17 namespace {
18
19 NSWindow* g_test_window = nil;
20
21 }  // namespace
22
23 // Mac APIs for creating test events are frustrating. Quartz APIs have, e.g.,
24 // CGEventCreateMouseEvent() which can't set a window or modifier flags.
25 // Cocoa APIs have +[NSEvent mouseEventWithType:..] which can't set
26 // buttonNumber or scroll deltas. To work around this, these tests use some
27 // Objective C magic to donate member functions to NSEvent temporarily.
28 @interface MiddleMouseButtonNumberDonor : NSObject
29 @end
30
31 @interface TestWindowDonor : NSObject
32 @end
33
34 @implementation MiddleMouseButtonNumberDonor
35 - (NSUInteger)buttonNumber { return 2; }
36 @end
37
38 @implementation TestWindowDonor
39 - (NSWindow*)window { return g_test_window; }
40 @end
41
42 namespace ui {
43
44 namespace {
45
46 class EventsMacTest : public CocoaTest {
47  public:
48   EventsMacTest() {}
49
50   gfx::Point Flip(gfx::Point window_location) {
51     window_location.set_y(
52         NSHeight([test_window() frame]) - window_location.y());
53     return window_location;
54   }
55
56   void SwizzleMiddleMouseButton() {
57     DCHECK(!swizzler_);
58     swizzler_.reset(new ScopedClassSwizzler(
59         [NSEvent class],
60         [MiddleMouseButtonNumberDonor class],
61         @selector(buttonNumber)));
62   }
63
64   void SwizzleTestWindow() {
65     DCHECK(!g_test_window);
66     DCHECK(!swizzler_);
67     g_test_window = test_window();
68     swizzler_.reset(new ScopedClassSwizzler(
69         [NSEvent class],
70         [TestWindowDonor class],
71         @selector(window)));
72   }
73
74   void ClearSwizzle() {
75     swizzler_.reset();
76     g_test_window = nil;
77   }
78
79   NSEvent* TestMouseEvent(NSEventType type,
80                           const gfx::Point &window_location,
81                           NSInteger modifier_flags) {
82     NSPoint point = NSPointFromCGPoint(Flip(window_location).ToCGPoint());
83     return [NSEvent mouseEventWithType:type
84                               location:point
85                          modifierFlags:modifier_flags
86                              timestamp:0
87                           windowNumber:[test_window() windowNumber]
88                                context:nil
89                            eventNumber:0
90                             clickCount:0
91                               pressure:1.0];
92   }
93
94   NSEvent* TestScrollEvent(const gfx::Point& window_location,
95                            int32_t delta_x,
96                            int32_t delta_y) {
97     SwizzleTestWindow();
98     base::ScopedCFTypeRef<CGEventRef> scroll(
99         CGEventCreateScrollWheelEvent(NULL,
100                                       kCGScrollEventUnitLine,
101                                       2,
102                                       delta_y,
103                                       delta_x));
104     // CGEvents are always in global display coordinates. These are like screen
105     // coordinates, but flipped. But first the point needs to be converted out
106     // of window coordinates (which also requires flipping).
107     NSPoint window_point =
108         NSPointFromCGPoint(Flip(window_location).ToCGPoint());
109     NSPoint screen_point = [test_window() convertBaseToScreen:window_point];
110     CGFloat primary_screen_height =
111         NSHeight([[[NSScreen screens] objectAtIndex:0] frame]);
112     screen_point.y = primary_screen_height - screen_point.y;
113     CGEventSetLocation(scroll, NSPointToCGPoint(screen_point));
114     return [NSEvent eventWithCGEvent:scroll];
115   }
116
117  private:
118   scoped_ptr<ScopedClassSwizzler> swizzler_;
119
120   DISALLOW_COPY_AND_ASSIGN(EventsMacTest);
121 };
122
123 }  // namespace
124
125 TEST_F(EventsMacTest, EventFlagsFromNative) {
126   // Left click.
127   NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0);
128   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left));
129
130   // Right click.
131   NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp,
132                                                               0);
133   EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNative(right));
134
135   // Middle click.
136   NSEvent* middle = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp,
137                                                                0);
138   EXPECT_EQ(EF_MIDDLE_MOUSE_BUTTON, EventFlagsFromNative(middle));
139
140   // Caps + Left
141   NSEvent* caps = cocoa_test_event_utils::MouseEventWithType(
142       NSLeftMouseUp, NSAlphaShiftKeyMask);
143   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CAPS_LOCK_DOWN,
144             EventFlagsFromNative(caps));
145
146   // Shift + Left
147   NSEvent* shift = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
148                                                               NSShiftKeyMask);
149   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN, EventFlagsFromNative(shift));
150
151   // Ctrl + Left
152   NSEvent* ctrl = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
153                                                              NSControlKeyMask);
154   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CONTROL_DOWN, EventFlagsFromNative(ctrl));
155
156   // Alt + Left
157   NSEvent* alt = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
158                                                             NSAlternateKeyMask);
159   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_ALT_DOWN, EventFlagsFromNative(alt));
160
161   // Cmd + Left
162   NSEvent* cmd = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp,
163                                                             NSCommandKeyMask);
164   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN, EventFlagsFromNative(cmd));
165
166   // Shift + Ctrl + Left
167   NSEvent* shiftctrl = cocoa_test_event_utils::MouseEventWithType(
168       NSLeftMouseUp, NSShiftKeyMask | NSControlKeyMask);
169   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN,
170             EventFlagsFromNative(shiftctrl));
171
172   // Cmd + Alt + Right
173   NSEvent* cmdalt = cocoa_test_event_utils::MouseEventWithType(
174       NSLeftMouseUp, NSCommandKeyMask | NSAlternateKeyMask);
175   EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN,
176             EventFlagsFromNative(cmdalt));
177 }
178
179 // Tests mouse button presses and mouse wheel events.
180 TEST_F(EventsMacTest, ButtonEvents) {
181   gfx::Point location(5, 10);
182   gfx::Vector2d offset;
183
184   NSEvent* event = TestMouseEvent(NSLeftMouseDown, location, 0);
185   EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event));
186   EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(event));
187   EXPECT_EQ(location, ui::EventLocationFromNative(event));
188
189   SwizzleMiddleMouseButton();
190   event = TestMouseEvent(NSOtherMouseDown, location, NSShiftKeyMask);
191   EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event));
192   EXPECT_EQ(ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_SHIFT_DOWN,
193             ui::EventFlagsFromNative(event));
194   EXPECT_EQ(location, ui::EventLocationFromNative(event));
195   ClearSwizzle();
196
197   event = TestMouseEvent(NSRightMouseUp, location, 0);
198   EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(event));
199   EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(event));
200   EXPECT_EQ(location, ui::EventLocationFromNative(event));
201
202   // Scroll up.
203   event = TestScrollEvent(location, 0, 1);
204   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
205   EXPECT_EQ(0, ui::EventFlagsFromNative(event));
206   EXPECT_EQ(location.ToString(), ui::EventLocationFromNative(event).ToString());
207   offset = ui::GetMouseWheelOffset(event);
208   EXPECT_GT(offset.y(), 0);
209   EXPECT_EQ(0, offset.x());
210   ClearSwizzle();
211
212   // Scroll down.
213   event = TestScrollEvent(location, 0, -1);
214   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
215   EXPECT_EQ(0, ui::EventFlagsFromNative(event));
216   EXPECT_EQ(location, ui::EventLocationFromNative(event));
217   offset = ui::GetMouseWheelOffset(event);
218   EXPECT_LT(offset.y(), 0);
219   EXPECT_EQ(0, offset.x());
220   ClearSwizzle();
221
222   // Scroll left.
223   event = TestScrollEvent(location, 1, 0);
224   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
225   EXPECT_EQ(0, ui::EventFlagsFromNative(event));
226   EXPECT_EQ(location, ui::EventLocationFromNative(event));
227   offset = ui::GetMouseWheelOffset(event);
228   EXPECT_EQ(0, offset.y());
229   EXPECT_GT(offset.x(), 0);
230   ClearSwizzle();
231
232   // Scroll right.
233   event = TestScrollEvent(location, -1, 0);
234   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event));
235   EXPECT_EQ(0, ui::EventFlagsFromNative(event));
236   EXPECT_EQ(location, ui::EventLocationFromNative(event));
237   offset = ui::GetMouseWheelOffset(event);
238   EXPECT_EQ(0, offset.y());
239   EXPECT_LT(offset.x(), 0);
240   ClearSwizzle();
241 }
242
243 }  // namespace ui