Index: ui/events/cocoa/events_mac_unittest.mm |
diff --git a/ui/events/cocoa/cocoa_event_utils_unittest.mm b/ui/events/cocoa/events_mac_unittest.mm |
similarity index 32% |
rename from ui/events/cocoa/cocoa_event_utils_unittest.mm |
rename to ui/events/cocoa/events_mac_unittest.mm |
index 4e24fd2c775ba9b9b2fbaf608b4e68fca90f3ab0..9b930845705bd3de3417bc30c4d339b54a2d5c62 100644 |
--- a/ui/events/cocoa/cocoa_event_utils_unittest.mm |
+++ b/ui/events/cocoa/events_mac_unittest.mm |
@@ -2,25 +2,127 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "ui/events/cocoa/cocoa_event_utils.h" |
+#include "ui/events/event_utils.h" |
-#import <objc/objc-class.h> |
+#import <Cocoa/Cocoa.h> |
+#include "base/mac/scoped_cftyperef.h" |
+#include "base/memory/scoped_ptr.h" |
#include "testing/gtest/include/gtest/gtest.h" |
-#include "testing/platform_test.h" |
#include "ui/events/event_constants.h" |
-#include "ui/events/event_utils.h" |
#import "ui/events/test/cocoa_test_event_utils.h" |
+#include "ui/gfx/point.h" |
#import "ui/gfx/test/ui_cocoa_test_helper.h" |
+namespace { |
+ |
+NSWindow* g_test_window = nil; |
+ |
+} // namespace |
+ |
+// Mac APIs for creating test events are frustrating. Quartz APIs have, e.g., |
+// CGEventCreateMouseEvent() which can't set a window or modifier flags. |
+// Cocoa APIs have +[NSEvent mouseEventWithType:..] which can't set |
+// buttonNumber or scroll deltas. To work around this, these tests use some |
+// Objective C magic to donate member functions to NSEvent temporarily. |
+@interface MiddleMouseButtonNumberDonor : NSObject |
+@end |
+ |
+@interface TestWindowDonor : NSObject |
+@end |
+ |
+@implementation MiddleMouseButtonNumberDonor |
+- (NSUInteger)buttonNumber { return 2; } |
+@end |
+ |
+@implementation TestWindowDonor |
+- (NSWindow*)window { return g_test_window; } |
+@end |
+ |
namespace ui { |
namespace { |
-class CocoaEventUtilsTest : public CocoaTest { |
+class EventsMacTest : public CocoaTest { |
+ public: |
+ EventsMacTest() {} |
+ |
+ gfx::Point Flip(gfx::Point window_location) { |
+ window_location.set_y( |
+ NSHeight([test_window() frame]) - window_location.y()); |
+ return window_location; |
+ } |
+ |
+ void SwizzleMiddleMouseButton() { |
+ DCHECK(!swizzler_); |
+ swizzler_.reset(new ScopedClassSwizzler( |
+ [NSEvent class], |
+ [MiddleMouseButtonNumberDonor class], |
+ @selector(buttonNumber))); |
+ } |
+ |
+ void SwizzleTestWindow() { |
+ DCHECK(!g_test_window); |
+ DCHECK(!swizzler_); |
+ g_test_window = test_window(); |
+ swizzler_.reset(new ScopedClassSwizzler( |
+ [NSEvent class], |
+ [TestWindowDonor class], |
+ @selector(window))); |
+ } |
+ |
+ void ClearSwizzle() { |
+ swizzler_.reset(); |
+ g_test_window = nil; |
+ } |
+ |
+ NSEvent* TestMouseEvent(NSEventType type, |
+ const gfx::Point &window_location, |
+ NSInteger modifier_flags) { |
+ NSPoint point = NSPointFromCGPoint(Flip(window_location).ToCGPoint()); |
+ return [NSEvent mouseEventWithType:type |
+ location:point |
+ modifierFlags:modifier_flags |
+ timestamp:0 |
+ windowNumber:[test_window() windowNumber] |
+ context:nil |
+ eventNumber:0 |
+ clickCount:0 |
+ pressure:1.0]; |
+ } |
+ |
+ NSEvent* TestScrollEvent(const gfx::Point& window_location, |
+ int32_t delta_x, |
+ int32_t delta_y) { |
+ SwizzleTestWindow(); |
+ base::ScopedCFTypeRef<CGEventRef> scroll( |
+ CGEventCreateScrollWheelEvent(NULL, |
+ kCGScrollEventUnitLine, |
+ 2, |
+ delta_y, |
+ delta_x)); |
+ // CGEvents are always in global display coordinates. These are like screen |
+ // coordinates, but flipped. But first the point needs to be converted out |
+ // of window coordinates (which also requires flipping). |
+ NSPoint window_point = |
+ NSPointFromCGPoint(Flip(window_location).ToCGPoint()); |
+ NSPoint screen_point = [test_window() convertBaseToScreen:window_point]; |
+ CGFloat primary_screen_height = |
+ NSHeight([[[NSScreen screens] objectAtIndex:0] frame]); |
+ screen_point.y = primary_screen_height - screen_point.y; |
+ CGEventSetLocation(scroll, NSPointToCGPoint(screen_point)); |
+ return [NSEvent eventWithCGEvent:scroll]; |
+ } |
+ |
+ private: |
+ scoped_ptr<ScopedClassSwizzler> swizzler_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(EventsMacTest); |
}; |
-TEST_F(CocoaEventUtilsTest, EventFlagsFromNative) { |
+} // namespace |
+ |
+TEST_F(EventsMacTest, EventFlagsFromNative) { |
// Left click. |
NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); |
EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left)); |
@@ -74,6 +176,68 @@ TEST_F(CocoaEventUtilsTest, EventFlagsFromNative) { |
EventFlagsFromNative(cmdalt)); |
} |
-} // namespace |
+// Tests mouse button presses and mouse wheel events. |
+TEST_F(EventsMacTest, ButtonEvents) { |
+ gfx::Point location(5, 10); |
+ gfx::Vector2d offset; |
+ |
+ NSEvent* event = TestMouseEvent(NSLeftMouseDown, location, 0); |
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ |
+ SwizzleMiddleMouseButton(); |
+ event = TestMouseEvent(NSOtherMouseDown, location, NSShiftKeyMask); |
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_SHIFT_DOWN, |
+ ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ ClearSwizzle(); |
+ |
+ event = TestMouseEvent(NSRightMouseUp, location, 0); |
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ |
+ // Scroll up. |
+ event = TestScrollEvent(location, 0, 1); |
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location.ToString(), ui::EventLocationFromNative(event).ToString()); |
+ offset = ui::GetMouseWheelOffset(event); |
+ EXPECT_GT(offset.y(), 0); |
+ EXPECT_EQ(0, offset.x()); |
+ ClearSwizzle(); |
+ |
+ // Scroll down. |
+ event = TestScrollEvent(location, 0, -1); |
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ offset = ui::GetMouseWheelOffset(event); |
+ EXPECT_LT(offset.y(), 0); |
+ EXPECT_EQ(0, offset.x()); |
+ ClearSwizzle(); |
+ |
+ // Scroll left. |
+ event = TestScrollEvent(location, 1, 0); |
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ offset = ui::GetMouseWheelOffset(event); |
+ EXPECT_EQ(0, offset.y()); |
+ EXPECT_GT(offset.x(), 0); |
+ ClearSwizzle(); |
+ |
+ // Scroll right. |
+ event = TestScrollEvent(location, -1, 0); |
+ EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
+ EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
+ EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
+ offset = ui::GetMouseWheelOffset(event); |
+ EXPECT_EQ(0, offset.y()); |
+ EXPECT_LT(offset.x(), 0); |
+ ClearSwizzle(); |
+} |
} // namespace ui |