chrome_render_widget_host_view_mac_history_swiper_unit_test.mm revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1// Copyright 2013 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 "testing/gtest/include/gtest/gtest.h"
6#import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
7
8#include "base/mac/scoped_nsobject.h"
9
10#import "base/mac/sdk_forward_declarations.h"
11#import "chrome/browser/renderer_host/chrome_render_widget_host_view_mac_history_swiper.h"
12#import "third_party/ocmock/OCMock/OCMock.h"
13#import "third_party/ocmock/ocmock_extensions.h"
14
15@interface HistorySwiper (MacHistorySwiperTest)
16- (BOOL)systemSettingsAllowHistorySwiping:(NSEvent*)event;
17- (BOOL)browserCanNavigateInDirection:
18        (history_swiper::NavigationDirection)forward
19                                event:(NSEvent*)event;
20- (void)endHistorySwipe;
21- (void)beginHistorySwipeInDirection:
22        (history_swiper::NavigationDirection)goForward
23                               event:(NSEvent*)event;
24- (void)navigateBrowserInDirection:(history_swiper::NavigationDirection)forward;
25@end
26
27class MacHistorySwiperTest : public CocoaTest {
28 public:
29  virtual void SetUp() OVERRIDE {
30    CocoaTest::SetUp();
31
32    view_ = [[NSView alloc] init];
33    id mockDelegate =
34        [OCMockObject mockForProtocol:@protocol(HistorySwiperDelegate)];
35    [[[mockDelegate stub] andReturn:view_] viewThatWantsHistoryOverlay];
36    [[[mockDelegate stub] andReturnBool:YES] shouldAllowHistorySwiping];
37
38    base::scoped_nsobject<HistorySwiper> historySwiper(
39        [[HistorySwiper alloc] initWithDelegate:mockDelegate]);
40    id mockHistorySwiper = [OCMockObject partialMockForObject:historySwiper];
41    [[[mockHistorySwiper stub] andReturnBool:YES]
42        systemSettingsAllowHistorySwiping:[OCMArg any]];
43    [[[mockHistorySwiper stub] andReturnBool:YES]
44        browserCanNavigateInDirection:history_swiper::kForwards
45                                event:[OCMArg any]];
46    [[[mockHistorySwiper stub] andReturnBool:YES]
47        browserCanNavigateInDirection:history_swiper::kBackwards
48                                event:[OCMArg any]];
49    [[[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
50      ++begin_count_;
51    }] andForwardToRealObject]
52        beginHistorySwipeInDirection:history_swiper::kForwards
53                               event:[OCMArg any]];
54    [[[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
55      ++begin_count_;
56    }] andForwardToRealObject]
57        beginHistorySwipeInDirection:history_swiper::kBackwards
58                               event:[OCMArg any]];
59    [[[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
60      ++end_count_;
61    }] andForwardToRealObject] endHistorySwipe];
62    [[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
63        navigated_right_ = true;
64    }] navigateBrowserInDirection:history_swiper::kForwards];
65    [[[mockHistorySwiper stub] andDo:^(NSInvocation* invocation) {
66        navigated_left_ = true;
67    }] navigateBrowserInDirection:history_swiper::kBackwards];
68    historySwiper_ = [mockHistorySwiper retain];
69
70    begin_count_ = 0;
71    end_count_ = 0;
72    navigated_right_ = false;
73    navigated_left_ = false;
74  }
75
76  virtual void TearDown() OVERRIDE {
77    [view_ release];
78    [historySwiper_ release];
79    CocoaTest::TearDown();
80  }
81
82  void startGestureInMiddle();
83  void moveGestureInMiddle();
84  void moveGestureAtPoint(NSPoint point);
85  void endGestureAtPoint(NSPoint point);
86
87  HistorySwiper* historySwiper_;
88  NSView* view_;
89  int begin_count_;
90  int end_count_;
91  bool navigated_right_;
92  bool navigated_left_;
93};
94
95NSPoint makePoint(CGFloat x, CGFloat y) {
96  NSPoint point;
97  point.x = x;
98  point.y = y;
99  return point;
100}
101
102id mockEventWithPoint(NSPoint point, NSEventType type) {
103  id mockEvent = [OCMockObject mockForClass:[NSEvent class]];
104  id mockTouch = [OCMockObject mockForClass:[NSTouch class]];
105  [[[mockTouch stub] andReturnNSPoint:point] normalizedPosition];
106  NSArray* touches = @[mockTouch];
107  [[[mockEvent stub] andReturn:touches] touchesMatchingPhase:NSTouchPhaseAny
108    inView:[OCMArg any]];
109  [[[mockEvent stub] andReturnBool:NO] isDirectionInvertedFromDevice];
110  [(NSEvent*)[[mockEvent stub] andReturnValue:OCMOCK_VALUE(type)] type];
111
112  return mockEvent;
113}
114
115id scrollWheelEventWithPhase(NSEventPhase phase) {
116  // The point isn't used, so we pass in bogus data.
117  id event = mockEventWithPoint(makePoint(0,0), NSScrollWheel);
118  [(NSEvent*)[[event stub] andReturnValue:OCMOCK_VALUE(phase)] phase];
119  return event;
120}
121
122void MacHistorySwiperTest::startGestureInMiddle() {
123  NSEvent* event = mockEventWithPoint(makePoint(0.5, 0.5), NSEventTypeGesture);
124  [historySwiper_ touchesBeganWithEvent:event];
125  [historySwiper_ beginGestureWithEvent:event];
126  NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseBegan);
127  [historySwiper_ handleEvent:scrollEvent];
128}
129
130void MacHistorySwiperTest::moveGestureInMiddle() {
131  moveGestureAtPoint(makePoint(0.5, 0.5));
132
133  // Callbacks from blink to set the relevant state for history swiping.
134  [historySwiper_ gotUnhandledWheelEvent];
135  [historySwiper_ scrollOffsetPinnedToLeft:YES toRight:YES];
136  [historySwiper_ setHasHorizontalScrollbar:NO];
137}
138
139void MacHistorySwiperTest::moveGestureAtPoint(NSPoint point) {
140  NSEvent* event = mockEventWithPoint(point, NSEventTypeGesture);
141  [historySwiper_ touchesMovedWithEvent:event];
142
143  NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseChanged);
144  [historySwiper_ handleEvent:scrollEvent];
145}
146
147void MacHistorySwiperTest::endGestureAtPoint(NSPoint point) {
148  NSEvent* event = mockEventWithPoint(point, NSEventTypeGesture);
149  [historySwiper_ touchesEndedWithEvent:event];
150
151  NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseEnded);
152  [historySwiper_ handleEvent:scrollEvent];
153}
154
155// Test that a simple left-swipe causes navigation.
156TEST_F(MacHistorySwiperTest, SwipeLeft) {
157  // These tests require 10.7+ APIs.
158  if (![NSEvent
159          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
160    return;
161
162  startGestureInMiddle();
163  moveGestureInMiddle();
164
165  EXPECT_EQ(begin_count_, 0);
166  EXPECT_EQ(end_count_, 0);
167
168  moveGestureAtPoint(makePoint(0.2, 0.5));
169  EXPECT_EQ(begin_count_, 1);
170  EXPECT_EQ(end_count_, 0);
171  EXPECT_FALSE(navigated_right_);
172  EXPECT_FALSE(navigated_left_);
173
174  endGestureAtPoint(makePoint(0.2, 0.5));
175  EXPECT_EQ(begin_count_, 1);
176  EXPECT_EQ(end_count_, 1);
177  EXPECT_FALSE(navigated_right_);
178  EXPECT_TRUE(navigated_left_);
179}
180
181// Test that a simple right-swipe causes navigation.
182TEST_F(MacHistorySwiperTest, SwipeRight) {
183  // These tests require 10.7+ APIs.
184  if (![NSEvent
185          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
186    return;
187
188  startGestureInMiddle();
189  moveGestureInMiddle();
190
191  EXPECT_EQ(begin_count_, 0);
192  EXPECT_EQ(end_count_, 0);
193
194  moveGestureAtPoint(makePoint(0.8, 0.5));
195  EXPECT_EQ(begin_count_, 1);
196  EXPECT_EQ(end_count_, 0);
197  EXPECT_FALSE(navigated_right_);
198  EXPECT_FALSE(navigated_left_);
199
200  endGestureAtPoint(makePoint(0.8, 0.5));
201  EXPECT_EQ(begin_count_, 1);
202  EXPECT_EQ(end_count_, 1);
203  EXPECT_TRUE(navigated_right_);
204  EXPECT_FALSE(navigated_left_);
205}
206
207// If the user doesn't swipe enough, the history swiper should begin, but the
208// browser should not navigate.
209TEST_F(MacHistorySwiperTest, SwipeLeftSmallAmount) {
210  // These tests require 10.7+ APIs.
211  if (![NSEvent
212          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
213    return;
214
215  startGestureInMiddle();
216  moveGestureInMiddle();
217  moveGestureAtPoint(makePoint(0.45, 0.5));
218  endGestureAtPoint(makePoint(0.45, 0.5));
219  EXPECT_EQ(begin_count_, 1);
220  EXPECT_EQ(end_count_, 1);
221  EXPECT_FALSE(navigated_right_);
222  EXPECT_FALSE(navigated_left_);
223}
224
225// Diagonal swipes with a slight horizontal bias should not start the history
226// swiper.
227TEST_F(MacHistorySwiperTest, SwipeDiagonal) {
228  // These tests require 10.7+ APIs.
229  if (![NSEvent
230          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
231    return;
232
233  startGestureInMiddle();
234  moveGestureInMiddle();
235  moveGestureAtPoint(makePoint(0.6, 0.59));
236  endGestureAtPoint(makePoint(0.6, 0.59));
237
238  EXPECT_EQ(begin_count_, 0);
239  EXPECT_EQ(end_count_, 0);
240  EXPECT_FALSE(navigated_right_);
241  EXPECT_FALSE(navigated_left_);
242}
243
244// Swiping left and then down should cancel the history swiper without
245// navigating.
246TEST_F(MacHistorySwiperTest, SwipeLeftThenDown) {
247  // These tests require 10.7+ APIs.
248  if (![NSEvent
249          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
250    return;
251
252  startGestureInMiddle();
253  moveGestureInMiddle();
254  moveGestureAtPoint(makePoint(0.4, 0.5));
255  moveGestureAtPoint(makePoint(0.4, 0.3));
256  endGestureAtPoint(makePoint(0.2, 0.2));
257  EXPECT_EQ(begin_count_, 1);
258  EXPECT_EQ(end_count_, 1);
259  EXPECT_FALSE(navigated_right_);
260  EXPECT_FALSE(navigated_left_);
261}
262
263// User starts a swipe but doesn't move.
264TEST_F(MacHistorySwiperTest, NoSwipe) {
265  // These tests require 10.7+ APIs.
266  if (![NSEvent
267          respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
268    return;
269
270  startGestureInMiddle();
271  moveGestureInMiddle();
272  moveGestureAtPoint(makePoint(0.5, 0.5));
273  endGestureAtPoint(makePoint(0.5, 0.5));
274
275  EXPECT_EQ(begin_count_, 0);
276  EXPECT_EQ(end_count_, 0);
277}
278