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#import "components/remote_cocoa/app_shim/mouse_capture.h" 6 7#import <Cocoa/Cocoa.h> 8 9#import "base/mac/scoped_nsobject.h" 10#include "base/macros.h" 11#import "components/remote_cocoa/app_shim/mouse_capture_delegate.h" 12#import "ui/base/test/cocoa_helper.h" 13#import "ui/events/test/cocoa_test_event_utils.h" 14 15// Simple test view that counts calls to -[NSView mouseDown:]. 16@interface CocoaMouseCaptureTestView : NSView { 17 @private 18 int _mouseDownCount; 19} 20@property(readonly, nonatomic) int mouseDownCount; 21@end 22 23@implementation CocoaMouseCaptureTestView 24 25@synthesize mouseDownCount = _mouseDownCount; 26 27- (void)mouseDown:(NSEvent*)theEvent { 28 ++_mouseDownCount; 29} 30 31@end 32 33namespace remote_cocoa { 34namespace { 35 36// Simple capture delegate that just counts events forwarded. 37class TestCaptureDelegate : public CocoaMouseCaptureDelegate { 38 public: 39 explicit TestCaptureDelegate(NSWindow* window) 40 : event_count_(0), capture_lost_count_(0), window_(window) {} 41 42 void Acquire() { mouse_capture_ = std::make_unique<CocoaMouseCapture>(this); } 43 bool IsActive() { return mouse_capture_ && mouse_capture_->IsActive(); } 44 void SimulateDestroy() { mouse_capture_.reset(); } 45 46 int event_count() { return event_count_; } 47 int capture_lost_count() { return capture_lost_count_; } 48 49 // CocoaMouseCaptureDelegate: 50 void PostCapturedEvent(NSEvent* event) override { ++event_count_; } 51 void OnMouseCaptureLost() override { ++capture_lost_count_; } 52 NSWindow* GetWindow() const override { return window_; } 53 54 private: 55 std::unique_ptr<CocoaMouseCapture> mouse_capture_; 56 int event_count_; 57 int capture_lost_count_; 58 NSWindow* window_; 59 60 DISALLOW_COPY_AND_ASSIGN(TestCaptureDelegate); 61}; 62 63} // namespace 64 65using CocoaMouseCaptureTest = ui::CocoaTest; 66 67// Test that a new capture properly "steals" capture from an existing one. 68TEST_F(CocoaMouseCaptureTest, OnCaptureLost) { 69 TestCaptureDelegate capture(nil); 70 71 capture.Acquire(); 72 EXPECT_TRUE(capture.IsActive()); 73 { 74 TestCaptureDelegate capture2(nil); 75 EXPECT_EQ(0, capture.capture_lost_count()); 76 77 // A second capture steals from the first. 78 capture2.Acquire(); 79 EXPECT_TRUE(capture2.IsActive()); 80 EXPECT_FALSE(capture.IsActive()); 81 EXPECT_EQ(1, capture.capture_lost_count()); 82 EXPECT_EQ(0, capture2.capture_lost_count()); 83 84 // Simulate capture2 going out of scope. Inspect it. 85 capture2.SimulateDestroy(); 86 EXPECT_FALSE(capture2.IsActive()); 87 EXPECT_EQ(1, capture2.capture_lost_count()); 88 } 89 90 // Re-acquiring is fine (not stealing). 91 EXPECT_FALSE(capture.IsActive()); 92 capture.Acquire(); 93 EXPECT_TRUE(capture.IsActive()); 94 95 // Having no CocoaMouseCapture instance is fine. 96 capture.SimulateDestroy(); 97 EXPECT_FALSE(capture.IsActive()); 98 // Receives OnMouseCaptureLost again, since reacquired. 99 EXPECT_EQ(2, capture.capture_lost_count()); 100} 101 102// Test event capture. 103TEST_F(CocoaMouseCaptureTest, CaptureEvents) { 104 base::scoped_nsobject<CocoaMouseCaptureTestView> view( 105 [[CocoaMouseCaptureTestView alloc] initWithFrame:NSZeroRect]); 106 [test_window() setContentView:view]; 107 std::pair<NSEvent*, NSEvent*> click = 108 cocoa_test_event_utils::MouseClickInView(view, 1); 109 110 // First check that the view receives events normally. 111 EXPECT_EQ(0, [view mouseDownCount]); 112 [NSApp sendEvent:click.first]; 113 EXPECT_EQ(1, [view mouseDownCount]); 114 115 { 116 TestCaptureDelegate capture(test_window()); 117 capture.Acquire(); 118 119 // Now check that the capture captures events. 120 EXPECT_EQ(0, capture.event_count()); 121 [NSApp sendEvent:click.first]; 122 EXPECT_EQ(1, [view mouseDownCount]); 123 EXPECT_EQ(1, capture.event_count()); 124 } 125 126 // After the capture goes away, events should be received again. 127 [NSApp sendEvent:click.first]; 128 EXPECT_EQ(2, [view mouseDownCount]); 129} 130 131} // namespace remote_cocoa 132