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#import "chrome/browser/ui/app_list/app_list_service_mac.h"
6
7#include "testing/gtest/include/gtest/gtest.h"
8#include "ui/gfx/display.h"
9#include "ui/gfx/point.h"
10#include "ui/gfx/rect.h"
11#include "ui/gfx/size.h"
12
13namespace {
14
15const int kScreenWidth = 800;
16const int kScreenHeight = 600;
17
18const int kWindowWidth = 100;
19const int kWindowHeight = 200;
20
21// Size of the menu bar along the top of the screen.
22const int kMenuBarSize = 22;
23// Size of the normal (non-hidden) dock.
24const int kDockSize = 30;
25// Size of the hidden dock.
26const int kHiddenDockSize = 4;
27
28// Distance to move during the opening animation.
29const int kAnimationOffset = 20;
30
31// The assumed size of the hidden dock.
32const int kExtraDistance = 50;
33
34// A cursor position that is within the dock. This must be < kDockSize.
35const int kCursorOnDock = kDockSize / 2;
36// A cursor position that is within kWindowWidth pixels of the dock.
37const int kCursorNearDockX = kDockSize + kWindowWidth;
38// A cursor position that is more than kWindowWidth pixels away from the dock.
39const int kCursorAwayFromDockX = kCursorNearDockX + 1;
40// A cursor position that is within kWindowHeight pixels of the dock.
41const int kCursorNearDockY = kDockSize + kWindowHeight;
42// A cursor position that is more than kWindowHeight pixels away from the dock.
43const int kCursorAwayFromDockY = kCursorNearDockY + 1;
44
45// A position for the center of the window that causes the window to overlap the
46// edge of the screen. This must be < kWindowWidth / 2 and < kWindowHeight / 2.
47const int kWindowNearEdge = kWindowWidth / 4;
48// A position for the center of the window that places the window away from all
49// edges of the screen. This must be > kWindowWidth / 2, > kWindowHeight / 2, <
50// kScreenWidth - kWindowWidth / 2 and < kScreenHeight - kWindowHeight / 2.
51const int kWindowAwayFromEdge = 158;
52
53enum DockLocation {
54  DOCK_LOCATION_BOTTOM,
55  DOCK_LOCATION_LEFT,
56  DOCK_LOCATION_RIGHT,
57};
58
59// Returns |point| offset by (|x_offset|, |y_offset|).
60NSPoint OffsetPoint(const NSPoint& point, CGFloat x_offset, CGFloat y_offset) {
61  return NSMakePoint(point.x + x_offset, point.y + y_offset);
62}
63
64}  // namespace
65
66class AppListServiceMacUnitTest : public testing::Test {
67 public:
68  virtual void SetUp() OVERRIDE {
69    display_.set_bounds(gfx::Rect(0, 0, kScreenWidth, kScreenHeight));
70    display_.set_work_area(
71        gfx::Rect(0, kMenuBarSize, kScreenWidth, kScreenHeight - kMenuBarSize));
72    window_size_ = gfx::Size(kWindowWidth, kWindowHeight);
73    cursor_is_visible_ = true;
74    cursor_ = gfx::Point();
75  }
76
77  // Sets up the test environment with the dock in a given location.
78  void PlaceDock(DockLocation location, bool hidden) {
79    int dock_size = hidden ? kHiddenDockSize : kDockSize;
80    switch (location) {
81      case DOCK_LOCATION_BOTTOM:
82        display_.set_work_area(
83            gfx::Rect(0,
84                      kMenuBarSize,
85                      kScreenWidth,
86                      kScreenHeight - kMenuBarSize - dock_size));
87        break;
88      case DOCK_LOCATION_LEFT:
89        display_.set_work_area(gfx::Rect(dock_size,
90                                         kMenuBarSize,
91                                         kScreenWidth - dock_size,
92                                         kScreenHeight - kMenuBarSize));
93        break;
94      case DOCK_LOCATION_RIGHT:
95        display_.set_work_area(gfx::Rect(0,
96                                         kMenuBarSize,
97                                         kScreenWidth - dock_size,
98                                         kScreenHeight - kMenuBarSize));
99        break;
100    }
101  }
102
103  // Set whether the test mouse cursor is visible.
104  void SetCursorVisible(bool visible) {
105    cursor_is_visible_ = visible;
106  }
107
108  // Set up the test mouse cursor in a given location.
109  void PlaceCursor(int x, int y) {
110    cursor_ = gfx::Point(x, y);
111  }
112
113  void DoFindAnchorPoint(NSPoint* target_origin,
114                         NSPoint* start_origin) {
115    AppListServiceMac::FindAnchorPoint(window_size_,
116                                       display_,
117                                       kScreenHeight,
118                                       cursor_is_visible_,
119                                       cursor_,
120                                       target_origin,
121                                       start_origin);
122  }
123
124 private:
125  gfx::Display display_;
126  gfx::Size window_size_;
127  bool cursor_is_visible_;
128  gfx::Point cursor_;
129};
130
131// Tests positioning the app list when there is no visible mouse cursor.
132TEST_F(AppListServiceMacUnitTest, FindAnchorPointNoCursor) {
133  SetCursorVisible(false);
134  PlaceCursor(0, 0);
135  NSPoint target_origin;
136  NSPoint start_origin;
137
138  // Bottom dock. Expect the app list to be centered on the dock.
139  PlaceDock(DOCK_LOCATION_BOTTOM, false);
140  DoFindAnchorPoint(&target_origin, &start_origin);
141  EXPECT_TRUE(
142      NSEqualPoints(NSMakePoint(kScreenWidth / 2 - kWindowWidth / 2, kDockSize),
143                    target_origin));
144  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
145                            start_origin));
146
147  // Left dock. Expect the app list to be centered on the dock.
148  PlaceDock(DOCK_LOCATION_LEFT, false);
149  DoFindAnchorPoint(&target_origin, &start_origin);
150  EXPECT_TRUE(NSEqualPoints(
151      NSMakePoint(kDockSize,
152                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
153      target_origin));
154  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, -kAnimationOffset, 0),
155                            start_origin));
156
157  // Right dock. Expect the app list to be centered on the dock.
158  PlaceDock(DOCK_LOCATION_RIGHT, false);
159  DoFindAnchorPoint(&target_origin, &start_origin);
160  EXPECT_TRUE(NSEqualPoints(
161      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
162                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
163      target_origin));
164  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, kAnimationOffset, 0),
165                            start_origin));
166}
167
168// Tests positioning the app list when there is no dock on the display.
169TEST_F(AppListServiceMacUnitTest, FindAnchorPointNoDock) {
170  SetCursorVisible(true);
171  PlaceCursor(0, 0);
172  NSPoint target_origin;
173  NSPoint start_origin;
174
175  // Expect the app list to be in the bottom-left corner.
176  DoFindAnchorPoint(&target_origin, &start_origin);
177  EXPECT_TRUE(NSEqualPoints(NSMakePoint(0, 0), target_origin));
178  EXPECT_TRUE(NSEqualPoints(target_origin, start_origin));
179
180  // No mouse cursor. This should have no effect.
181  SetCursorVisible(false);
182  DoFindAnchorPoint(&target_origin, &start_origin);
183  EXPECT_TRUE(NSEqualPoints(NSMakePoint(0, 0), target_origin));
184  EXPECT_TRUE(NSEqualPoints(target_origin, start_origin));
185}
186
187// Tests positioning the app list when the mouse is away from the dock.
188TEST_F(AppListServiceMacUnitTest, FindAnchorPointMouseOffDock) {
189  SetCursorVisible(true);
190  NSPoint target_origin;
191  NSPoint start_origin;
192
193  // Bottom dock. Expect the app list to be centered on the dock.
194  PlaceDock(DOCK_LOCATION_BOTTOM, false);
195  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorAwayFromDockY);
196  DoFindAnchorPoint(&target_origin, &start_origin);
197  EXPECT_TRUE(
198      NSEqualPoints(NSMakePoint(kScreenWidth / 2 - kWindowWidth / 2, kDockSize),
199                    target_origin));
200  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
201                            start_origin));
202
203  // Left dock. Expect the app list to be centered on the dock.
204  PlaceDock(DOCK_LOCATION_LEFT, false);
205  PlaceCursor(kCursorAwayFromDockX, kWindowAwayFromEdge);
206  DoFindAnchorPoint(&target_origin, &start_origin);
207  EXPECT_TRUE(NSEqualPoints(
208      NSMakePoint(kDockSize,
209                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
210      target_origin));
211  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, -kAnimationOffset, 0),
212                            start_origin));
213
214  // Right dock. Expect the app list to be centered on the dock.
215  PlaceDock(DOCK_LOCATION_RIGHT, false);
216  PlaceCursor(kScreenWidth - kCursorAwayFromDockX, kWindowAwayFromEdge);
217  DoFindAnchorPoint(&target_origin, &start_origin);
218  EXPECT_TRUE(NSEqualPoints(
219      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
220                  (kScreenHeight - kMenuBarSize) / 2 - kWindowHeight / 2),
221      target_origin));
222  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, kAnimationOffset, 0),
223                            start_origin));
224}
225
226// Tests positioning the app list when the dock is hidden.
227TEST_F(AppListServiceMacUnitTest, FindAnchorPointHiddenDock) {
228  SetCursorVisible(true);
229  NSPoint target_origin;
230  NSPoint start_origin;
231
232  // Bottom dock. Expect the app list to be kExtraDistance pixels from the dock
233  // centered on the mouse X coordinate.
234  PlaceDock(DOCK_LOCATION_BOTTOM, true);
235  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorAwayFromDockY);
236  DoFindAnchorPoint(&target_origin, &start_origin);
237  EXPECT_TRUE(NSEqualPoints(NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2,
238                                        kHiddenDockSize + kExtraDistance),
239                            target_origin));
240  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
241                            start_origin));
242
243  // Left dock. Expect the app list to be kExtraDistance pixels from the dock
244  // centered on the mouse Y coordinate.
245  PlaceDock(DOCK_LOCATION_LEFT, true);
246  PlaceCursor(kCursorAwayFromDockX, kWindowAwayFromEdge);
247  DoFindAnchorPoint(&target_origin, &start_origin);
248  EXPECT_TRUE(NSEqualPoints(
249      NSMakePoint(kHiddenDockSize + kExtraDistance,
250                  kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
251      target_origin));
252  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, -kAnimationOffset, 0),
253                            start_origin));
254
255  // Right dock. Expect the app list to be kExtraDistance pixels from the dock
256  // centered on the mouse Y coordinate.
257  PlaceDock(DOCK_LOCATION_RIGHT, true);
258  PlaceCursor(kScreenWidth - kCursorAwayFromDockX, kWindowAwayFromEdge);
259  DoFindAnchorPoint(&target_origin, &start_origin);
260  EXPECT_TRUE(NSEqualPoints(
261      NSMakePoint(
262          kScreenWidth - kHiddenDockSize - kWindowWidth - kExtraDistance,
263          kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
264      target_origin));
265  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, kAnimationOffset, 0),
266                            start_origin));
267}
268
269// Tests positioning the app list when the mouse is over the dock.
270TEST_F(AppListServiceMacUnitTest, FindAnchorPointMouseOnDock) {
271  SetCursorVisible(true);
272  NSPoint target_origin;
273  NSPoint start_origin;
274
275  // Bottom dock (mouse well within dock). Expect the app list to be at the
276  // bottom centered on the mouse X coordinate.
277  PlaceDock(DOCK_LOCATION_BOTTOM, false);
278  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorOnDock);
279  DoFindAnchorPoint(&target_origin, &start_origin);
280  EXPECT_TRUE(NSEqualPoints(
281      NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2, kDockSize),
282      target_origin));
283  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
284                            start_origin));
285
286  // Bottom dock (outside the dock but still close enough). Expect the app list
287  // to be at the bottom centered on the mouse X coordinate.
288  PlaceDock(DOCK_LOCATION_BOTTOM, false);
289  PlaceCursor(kWindowAwayFromEdge, kScreenHeight - kCursorNearDockY);
290  DoFindAnchorPoint(&target_origin, &start_origin);
291  EXPECT_TRUE(NSEqualPoints(
292      NSMakePoint(kWindowAwayFromEdge - kWindowWidth / 2, kDockSize),
293      target_origin));
294  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
295                            start_origin));
296
297  // Left dock. Expect the app list to be at the left centered on the mouse Y
298  // coordinate.
299  PlaceDock(DOCK_LOCATION_LEFT, false);
300  PlaceCursor(kCursorNearDockX, kWindowAwayFromEdge);
301  DoFindAnchorPoint(&target_origin, &start_origin);
302  EXPECT_TRUE(NSEqualPoints(
303      NSMakePoint(kDockSize,
304                  kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
305      target_origin));
306  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, -kAnimationOffset, 0),
307                            start_origin));
308
309  // Right dock. Expect the app list to be at the right centered on the mouse Y
310  // coordinate.
311  PlaceDock(DOCK_LOCATION_RIGHT, false);
312  PlaceCursor(kScreenWidth - kCursorNearDockX, kWindowAwayFromEdge);
313  DoFindAnchorPoint(&target_origin, &start_origin);
314  EXPECT_TRUE(NSEqualPoints(
315      NSMakePoint(kScreenWidth - kDockSize - kWindowWidth,
316                  kScreenHeight - kWindowAwayFromEdge - kWindowHeight / 2),
317      target_origin));
318  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, kAnimationOffset, 0),
319                            start_origin));
320
321  // Bottom dock. Mouse near left edge. App list must not go off screen.
322  PlaceDock(DOCK_LOCATION_BOTTOM, false);
323  PlaceCursor(kWindowNearEdge, kScreenHeight - kCursorOnDock);
324  DoFindAnchorPoint(&target_origin, &start_origin);
325  EXPECT_TRUE(NSEqualPoints(NSMakePoint(0, kDockSize), target_origin));
326  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
327                            start_origin));
328
329  // Bottom dock. Mouse near right edge. App list must not go off screen.
330  PlaceDock(DOCK_LOCATION_BOTTOM, false);
331  PlaceCursor(kScreenWidth - kWindowNearEdge, kScreenHeight - kCursorOnDock);
332  DoFindAnchorPoint(&target_origin, &start_origin);
333  EXPECT_TRUE(NSEqualPoints(NSMakePoint(kScreenWidth - kWindowWidth, kDockSize),
334                            target_origin));
335  EXPECT_TRUE(NSEqualPoints(OffsetPoint(target_origin, 0, -kAnimationOffset),
336                            start_origin));
337}
338