1// Copyright (c) 2012 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 "ash/wm/workspace/workspace_window_resizer.h"
6
7#include "ash/display/display_manager.h"
8#include "ash/root_window_controller.h"
9#include "ash/screen_util.h"
10#include "ash/shelf/shelf_layout_manager.h"
11#include "ash/shell.h"
12#include "ash/shell_window_ids.h"
13#include "ash/test/ash_test_base.h"
14#include "ash/wm/window_state.h"
15#include "ash/wm/window_util.h"
16#include "ash/wm/wm_event.h"
17#include "ash/wm/workspace/phantom_window_controller.h"
18#include "ash/wm/workspace_controller.h"
19#include "base/command_line.h"
20#include "base/strings/string_number_conversions.h"
21#include "base/strings/stringprintf.h"
22#include "ui/aura/client/aura_constants.h"
23#include "ui/aura/test/test_window_delegate.h"
24#include "ui/aura/window_event_dispatcher.h"
25#include "ui/base/hit_test.h"
26#include "ui/events/gestures/gesture_configuration.h"
27#include "ui/events/test/event_generator.h"
28#include "ui/gfx/insets.h"
29#include "ui/gfx/screen.h"
30#include "ui/views/widget/widget.h"
31
32namespace ash {
33namespace {
34
35const int kRootHeight = 600;
36
37// A simple window delegate that returns the specified min size.
38class TestWindowDelegate : public aura::test::TestWindowDelegate {
39 public:
40  TestWindowDelegate() {
41  }
42  virtual ~TestWindowDelegate() {}
43
44  void set_min_size(const gfx::Size& size) {
45    min_size_ = size;
46  }
47
48  void set_max_size(const gfx::Size& size) {
49    max_size_ = size;
50  }
51
52 private:
53  // Overridden from aura::Test::TestWindowDelegate:
54  virtual gfx::Size GetMinimumSize() const OVERRIDE {
55    return min_size_;
56  }
57
58  virtual gfx::Size GetMaximumSize() const OVERRIDE {
59    return max_size_;
60  }
61
62  gfx::Size min_size_;
63  gfx::Size max_size_;
64
65  DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
66};
67
68}  // namespace
69
70class WorkspaceWindowResizerTest : public test::AshTestBase {
71 public:
72  WorkspaceWindowResizerTest() : workspace_resizer_(NULL) {}
73  virtual ~WorkspaceWindowResizerTest() {}
74
75  virtual void SetUp() OVERRIDE {
76    AshTestBase::SetUp();
77    UpdateDisplay(base::StringPrintf("800x%d", kRootHeight));
78    // Ignore the touch slop region.
79    ui::GestureConfiguration::set_max_touch_move_in_pixels_for_click(0);
80
81    aura::Window* root = Shell::GetPrimaryRootWindow();
82    gfx::Rect root_bounds(root->bounds());
83#if defined(OS_WIN)
84    // RootWindow and Display can't resize on Windows Ash.
85    // http://crbug.com/165962
86    EXPECT_EQ(kRootHeight, root_bounds.height());
87#endif
88    EXPECT_EQ(800, root_bounds.width());
89    Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
90    window_.reset(new aura::Window(&delegate_));
91    window_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
92    window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
93    ParentWindowInPrimaryRootWindow(window_.get());
94    window_->set_id(1);
95
96    window2_.reset(new aura::Window(&delegate2_));
97    window2_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
98    window2_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
99    ParentWindowInPrimaryRootWindow(window2_.get());
100    window2_->set_id(2);
101
102    window3_.reset(new aura::Window(&delegate3_));
103    window3_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
104    window3_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
105    ParentWindowInPrimaryRootWindow(window3_.get());
106    window3_->set_id(3);
107
108    window4_.reset(new aura::Window(&delegate4_));
109    window4_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
110    window4_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
111    ParentWindowInPrimaryRootWindow(window4_.get());
112    window4_->set_id(4);
113  }
114
115  virtual void TearDown() OVERRIDE {
116    window_.reset();
117    window2_.reset();
118    window3_.reset();
119    window4_.reset();
120    touch_resize_window_.reset();
121    AshTestBase::TearDown();
122  }
123
124  // Returns a string identifying the z-order of each of the known child windows
125  // of |parent|.  The returned string constains the id of the known windows and
126  // is ordered from topmost to bottomost windows.
127  std::string WindowOrderAsString(aura::Window* parent) const {
128    std::string result;
129    const aura::Window::Windows& windows = parent->children();
130    for (aura::Window::Windows::const_reverse_iterator i = windows.rbegin();
131         i != windows.rend(); ++i) {
132      if (*i == window_ || *i == window2_ || *i == window3_) {
133        if (!result.empty())
134          result += " ";
135        result += base::IntToString((*i)->id());
136      }
137    }
138    return result;
139  }
140
141 protected:
142  WindowResizer* CreateResizerForTest(
143      aura::Window* window,
144      const gfx::Point& point_in_parent,
145      int window_component) {
146    WindowResizer* resizer = CreateWindowResizer(
147        window,
148        point_in_parent,
149        window_component,
150        aura::client::WINDOW_MOVE_SOURCE_MOUSE).release();
151    workspace_resizer_ = WorkspaceWindowResizer::GetInstanceForTest();
152    return resizer;
153  }
154  WorkspaceWindowResizer* CreateWorkspaceResizerForTest(
155      aura::Window* window,
156      const gfx::Point& point_in_parent,
157      int window_component,
158      aura::client::WindowMoveSource source,
159      const std::vector<aura::Window*>& attached_windows) {
160    wm::WindowState* window_state = wm::GetWindowState(window);
161    window_state->CreateDragDetails(
162        window, point_in_parent, window_component, source);
163    return WorkspaceWindowResizer::Create(window_state, attached_windows);
164  }
165
166  PhantomWindowController* snap_phantom_window_controller() const {
167    return workspace_resizer_->snap_phantom_window_controller_.get();
168  }
169
170  gfx::Point CalculateDragPoint(const WindowResizer& resizer,
171                                int delta_x,
172                                int delta_y) const {
173    gfx::Point location = resizer.GetInitialLocation();
174    location.set_x(location.x() + delta_x);
175    location.set_y(location.y() + delta_y);
176    return location;
177  }
178
179  std::vector<aura::Window*> empty_windows() const {
180    return std::vector<aura::Window*>();
181  }
182
183  ShelfLayoutManager* shelf_layout_manager() {
184    return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
185  }
186
187  void InitTouchResizeWindow(const gfx::Rect& bounds, int window_component) {
188    touch_resize_delegate_.set_window_component(window_component);
189    touch_resize_window_.reset(
190        CreateTestWindowInShellWithDelegate(&touch_resize_delegate_, 0,
191                                            bounds));
192  }
193
194  TestWindowDelegate delegate_;
195  TestWindowDelegate delegate2_;
196  TestWindowDelegate delegate3_;
197  TestWindowDelegate delegate4_;
198  scoped_ptr<aura::Window> window_;
199  scoped_ptr<aura::Window> window2_;
200  scoped_ptr<aura::Window> window3_;
201  scoped_ptr<aura::Window> window4_;
202
203  TestWindowDelegate touch_resize_delegate_;
204  scoped_ptr<aura::Window> touch_resize_window_;
205  WorkspaceWindowResizer* workspace_resizer_;
206
207 private:
208  DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizerTest);
209};
210
211// Assertions around attached window resize dragging from the right with 2
212// windows.
213TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_2) {
214  window_->SetBounds(gfx::Rect(0, 300, 400, 300));
215  window2_->SetBounds(gfx::Rect(400, 200, 100, 200));
216
217  std::vector<aura::Window*> windows;
218  windows.push_back(window2_.get());
219  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
220      window_.get(), gfx::Point(), HTRIGHT,
221      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
222  ASSERT_TRUE(resizer.get());
223  // Move it 100 to the right, which should expand w1 and push w2.
224  resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
225  EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
226  EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
227
228  // Push off the screen, w2 should be resized to its min.
229  delegate2_.set_min_size(gfx::Size(20, 20));
230  resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
231  EXPECT_EQ("0,300 780x300", window_->bounds().ToString());
232  EXPECT_EQ("780,200 20x200", window2_->bounds().ToString());
233
234  // Move back to 100 and verify w2 gets its original size.
235  resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
236  EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
237  EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
238
239  // Revert and make sure everything moves back.
240  resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
241  resizer->RevertDrag();
242  EXPECT_EQ("0,300 400x300", window_->bounds().ToString());
243  EXPECT_EQ("400,200 100x200", window2_->bounds().ToString());
244}
245
246// Assertions around collapsing and expanding.
247TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_Compress) {
248  window_->SetBounds(gfx::Rect(   0, 300, 400, 300));
249  window2_->SetBounds(gfx::Rect(400, 200, 100, 200));
250
251  std::vector<aura::Window*> windows;
252  windows.push_back(window2_.get());
253  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
254      window_.get(), gfx::Point(), HTRIGHT,
255      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
256  ASSERT_TRUE(resizer.get());
257  // Move it 100 to the left, which should expand w2 and collapse w1.
258  resizer->Drag(CalculateDragPoint(*resizer, -100, 10), 0);
259  EXPECT_EQ("0,300 300x300", window_->bounds().ToString());
260  EXPECT_EQ("300,200 200x200", window2_->bounds().ToString());
261
262  // Collapse all the way to w1's min.
263  delegate_.set_min_size(gfx::Size(20, 20));
264  resizer->Drag(CalculateDragPoint(*resizer, -800, 20), 0);
265  EXPECT_EQ("0,300 20x300", window_->bounds().ToString());
266  EXPECT_EQ("20,200 480x200", window2_->bounds().ToString());
267
268  // Move 100 to the left.
269  resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
270  EXPECT_EQ("0,300 500x300", window_->bounds().ToString());
271  EXPECT_EQ("500,200 100x200", window2_->bounds().ToString());
272
273  // Back to -100.
274  resizer->Drag(CalculateDragPoint(*resizer, -100, 20), 0);
275  EXPECT_EQ("0,300 300x300", window_->bounds().ToString());
276  EXPECT_EQ("300,200 200x200", window2_->bounds().ToString());
277}
278
279// Assertions around attached window resize dragging from the right with 3
280// windows.
281TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3) {
282  window_->SetBounds(gfx::Rect( 100, 300, 200, 300));
283  window2_->SetBounds(gfx::Rect(300, 300, 150, 200));
284  window3_->SetBounds(gfx::Rect(450, 300, 100, 200));
285  delegate2_.set_min_size(gfx::Size(52, 50));
286  delegate3_.set_min_size(gfx::Size(38, 50));
287
288  std::vector<aura::Window*> windows;
289  windows.push_back(window2_.get());
290  windows.push_back(window3_.get());
291  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
292      window_.get(), gfx::Point(), HTRIGHT,
293      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
294  ASSERT_TRUE(resizer.get());
295  // Move it 100 to the right, which should expand w1 and push w2 and w3.
296  resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
297  EXPECT_EQ("100,300 300x300", window_->bounds().ToString());
298  EXPECT_EQ("400,300 150x200", window2_->bounds().ToString());
299  EXPECT_EQ("550,300 100x200", window3_->bounds().ToString());
300
301  // Move it 300, things should compress.
302  resizer->Drag(CalculateDragPoint(*resizer, 300, -10), 0);
303  EXPECT_EQ("100,300 500x300", window_->bounds().ToString());
304  EXPECT_EQ("600,300 120x200", window2_->bounds().ToString());
305  EXPECT_EQ("720,300 80x200", window3_->bounds().ToString());
306
307  // Move it so much the last two end up at their min.
308  resizer->Drag(CalculateDragPoint(*resizer, 800, 50), 0);
309  EXPECT_EQ("100,300 610x300", window_->bounds().ToString());
310  EXPECT_EQ("710,300 52x200", window2_->bounds().ToString());
311  EXPECT_EQ("762,300 38x200", window3_->bounds().ToString());
312
313  // Revert and make sure everything moves back.
314  resizer->RevertDrag();
315  EXPECT_EQ("100,300 200x300", window_->bounds().ToString());
316  EXPECT_EQ("300,300 150x200", window2_->bounds().ToString());
317  EXPECT_EQ("450,300 100x200", window3_->bounds().ToString());
318}
319
320// Assertions around attached window resizing (collapsing and expanding) with
321// 3 windows.
322TEST_F(WorkspaceWindowResizerTest, AttachedResize_RIGHT_3_Compress) {
323  window_->SetBounds(gfx::Rect( 100, 300, 200, 300));
324  window2_->SetBounds(gfx::Rect(300, 300, 200, 200));
325  window3_->SetBounds(gfx::Rect(450, 300, 100, 200));
326  delegate2_.set_min_size(gfx::Size(52, 50));
327  delegate3_.set_min_size(gfx::Size(38, 50));
328
329  std::vector<aura::Window*> windows;
330  windows.push_back(window2_.get());
331  windows.push_back(window3_.get());
332  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
333      window_.get(), gfx::Point(), HTRIGHT,
334      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
335  ASSERT_TRUE(resizer.get());
336  // Move it -100 to the right, which should collapse w1 and expand w2 and w3.
337  resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0);
338  EXPECT_EQ("100,300 100x300", window_->bounds().ToString());
339  EXPECT_EQ("200,300 266x200", window2_->bounds().ToString());
340  EXPECT_EQ("466,300 134x200", window3_->bounds().ToString());
341
342  // Move it 100 to the right.
343  resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
344  EXPECT_EQ("100,300 300x300", window_->bounds().ToString());
345  EXPECT_EQ("400,300 200x200", window2_->bounds().ToString());
346  EXPECT_EQ("600,300 100x200", window3_->bounds().ToString());
347
348  // 100 to the left again.
349  resizer->Drag(CalculateDragPoint(*resizer, -100, -10), 0);
350  EXPECT_EQ("100,300 100x300", window_->bounds().ToString());
351  EXPECT_EQ("200,300 266x200", window2_->bounds().ToString());
352  EXPECT_EQ("466,300 134x200", window3_->bounds().ToString());
353}
354
355// Assertions around collapsing and expanding from the bottom.
356TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_Compress) {
357  window_->SetBounds(gfx::Rect(   0, 100, 400, 300));
358  window2_->SetBounds(gfx::Rect(400, 400, 100, 200));
359
360  std::vector<aura::Window*> windows;
361  windows.push_back(window2_.get());
362  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
363      window_.get(), gfx::Point(), HTBOTTOM,
364      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
365  ASSERT_TRUE(resizer.get());
366  // Move it up 100, which should expand w2 and collapse w1.
367  resizer->Drag(CalculateDragPoint(*resizer, 10, -100), 0);
368  EXPECT_EQ("0,100 400x200", window_->bounds().ToString());
369  EXPECT_EQ("400,300 100x300", window2_->bounds().ToString());
370
371  // Collapse all the way to w1's min.
372  delegate_.set_min_size(gfx::Size(20, 20));
373  resizer->Drag(CalculateDragPoint(*resizer, 20, -800), 0);
374  EXPECT_EQ("0,100 400x20", window_->bounds().ToString());
375  EXPECT_EQ("400,120 100x480", window2_->bounds().ToString());
376
377  // Move 100 down.
378  resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
379  EXPECT_EQ("0,100 400x400", window_->bounds().ToString());
380  EXPECT_EQ("400,500 100x100", window2_->bounds().ToString());
381
382  // Back to -100.
383  resizer->Drag(CalculateDragPoint(*resizer, 20, -100), 0);
384  EXPECT_EQ("0,100 400x200", window_->bounds().ToString());
385  EXPECT_EQ("400,300 100x300", window2_->bounds().ToString());
386}
387
388// Assertions around attached window resize dragging from the bottom with 2
389// windows.
390TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_2) {
391  window_->SetBounds(gfx::Rect( 0,  50, 400, 200));
392  window2_->SetBounds(gfx::Rect(0, 250, 200, 100));
393
394  std::vector<aura::Window*> windows;
395  windows.push_back(window2_.get());
396  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
397      window_.get(), gfx::Point(), HTBOTTOM,
398      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
399  ASSERT_TRUE(resizer.get());
400  // Move it 100 to the bottom, which should expand w1 and push w2.
401  resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
402  EXPECT_EQ("0,50 400x300", window_->bounds().ToString());
403  EXPECT_EQ("0,350 200x100", window2_->bounds().ToString());
404
405  // Push off the screen, w2 should be resized to its min.
406  delegate2_.set_min_size(gfx::Size(20, 20));
407  resizer->Drag(CalculateDragPoint(*resizer, 50, 820), 0);
408  EXPECT_EQ("0,50 400x530", window_->bounds().ToString());
409  EXPECT_EQ("0,580 200x20", window2_->bounds().ToString());
410
411  // Move back to 100 and verify w2 gets its original size.
412  resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
413  EXPECT_EQ("0,50 400x300", window_->bounds().ToString());
414  EXPECT_EQ("0,350 200x100", window2_->bounds().ToString());
415
416  // Revert and make sure everything moves back.
417  resizer->Drag(CalculateDragPoint(*resizer, 800, 20), 0);
418  resizer->RevertDrag();
419  EXPECT_EQ("0,50 400x200", window_->bounds().ToString());
420  EXPECT_EQ("0,250 200x100", window2_->bounds().ToString());
421}
422
423#if defined(OS_WIN)
424// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
425#define MAYBE_AttachedResize_BOTTOM_3 DISABLED_AttachedResize_BOTTOM_3
426#else
427#define MAYBE_AttachedResize_BOTTOM_3 AttachedResize_BOTTOM_3
428#endif
429
430// Assertions around attached window resize dragging from the bottom with 3
431// windows.
432TEST_F(WorkspaceWindowResizerTest, MAYBE_AttachedResize_BOTTOM_3) {
433  UpdateDisplay("600x800");
434  aura::Window* root = Shell::GetPrimaryRootWindow();
435  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
436
437  window_->SetBounds(gfx::Rect( 300, 100, 300, 200));
438  window2_->SetBounds(gfx::Rect(300, 300, 200, 150));
439  window3_->SetBounds(gfx::Rect(300, 450, 200, 100));
440  delegate2_.set_min_size(gfx::Size(50, 52));
441  delegate3_.set_min_size(gfx::Size(50, 38));
442
443  std::vector<aura::Window*> windows;
444  windows.push_back(window2_.get());
445  windows.push_back(window3_.get());
446  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
447      window_.get(), gfx::Point(), HTBOTTOM,
448      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
449  ASSERT_TRUE(resizer.get());
450  // Move it 100 down, which should expand w1 and push w2 and w3.
451  resizer->Drag(CalculateDragPoint(*resizer, -10, 100), 0);
452  EXPECT_EQ("300,100 300x300", window_->bounds().ToString());
453  EXPECT_EQ("300,400 200x150", window2_->bounds().ToString());
454  EXPECT_EQ("300,550 200x100", window3_->bounds().ToString());
455
456  // Move it 296 things should compress.
457  resizer->Drag(CalculateDragPoint(*resizer, -10, 296), 0);
458  EXPECT_EQ("300,100 300x496", window_->bounds().ToString());
459  EXPECT_EQ("300,596 200x123", window2_->bounds().ToString());
460  EXPECT_EQ("300,719 200x81", window3_->bounds().ToString());
461
462  // Move it so much everything ends up at its min.
463  resizer->Drag(CalculateDragPoint(*resizer, 50, 798), 0);
464  EXPECT_EQ("300,100 300x610", window_->bounds().ToString());
465  EXPECT_EQ("300,710 200x52", window2_->bounds().ToString());
466  EXPECT_EQ("300,762 200x38", window3_->bounds().ToString());
467
468  // Revert and make sure everything moves back.
469  resizer->RevertDrag();
470  EXPECT_EQ("300,100 300x200", window_->bounds().ToString());
471  EXPECT_EQ("300,300 200x150", window2_->bounds().ToString());
472  EXPECT_EQ("300,450 200x100", window3_->bounds().ToString());
473}
474
475// Assertions around attached window resizing (collapsing and expanding) with
476// 3 windows.
477TEST_F(WorkspaceWindowResizerTest, AttachedResize_BOTTOM_3_Compress) {
478  window_->SetBounds(gfx::Rect(  0,   0, 200, 200));
479  window2_->SetBounds(gfx::Rect(10, 200, 200, 200));
480  window3_->SetBounds(gfx::Rect(20, 400, 100, 100));
481  delegate2_.set_min_size(gfx::Size(52, 50));
482  delegate3_.set_min_size(gfx::Size(38, 50));
483
484  std::vector<aura::Window*> windows;
485  windows.push_back(window2_.get());
486  windows.push_back(window3_.get());
487  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
488      window_.get(), gfx::Point(), HTBOTTOM,
489      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
490  ASSERT_TRUE(resizer.get());
491  // Move it 100 up, which should collapse w1 and expand w2 and w3.
492  resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0);
493  EXPECT_EQ("0,0 200x100", window_->bounds().ToString());
494  EXPECT_EQ("10,100 200x266", window2_->bounds().ToString());
495  EXPECT_EQ("20,366 100x134", window3_->bounds().ToString());
496
497  // Move it 100 down.
498  resizer->Drag(CalculateDragPoint(*resizer, 10, 100), 0);
499  EXPECT_EQ("0,0 200x300", window_->bounds().ToString());
500  EXPECT_EQ("10,300 200x200", window2_->bounds().ToString());
501  EXPECT_EQ("20,500 100x100", window3_->bounds().ToString());
502
503  // 100 up again.
504  resizer->Drag(CalculateDragPoint(*resizer, -10, -100), 0);
505  EXPECT_EQ("0,0 200x100", window_->bounds().ToString());
506  EXPECT_EQ("10,100 200x266", window2_->bounds().ToString());
507  EXPECT_EQ("20,366 100x134", window3_->bounds().ToString());
508}
509
510// Tests that touch-dragging a window does not lock the mouse cursor
511// and therefore shows the cursor on a mousemove.
512TEST_F(WorkspaceWindowResizerTest, MouseMoveWithTouchDrag) {
513  window_->SetBounds(gfx::Rect(0, 300, 400, 300));
514  window2_->SetBounds(gfx::Rect(400, 200, 100, 200));
515
516  Shell* shell = Shell::GetInstance();
517  ui::test::EventGenerator generator(window_->GetRootWindow());
518
519  // The cursor should not be locked initially.
520  EXPECT_FALSE(shell->cursor_manager()->IsCursorLocked());
521
522  std::vector<aura::Window*> windows;
523  windows.push_back(window2_.get());
524  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
525      window_.get(), gfx::Point(), HTRIGHT,
526      aura::client::WINDOW_MOVE_SOURCE_TOUCH, windows));
527  ASSERT_TRUE(resizer.get());
528
529  // Creating a WorkspaceWindowResizer should not lock the cursor.
530  EXPECT_FALSE(shell->cursor_manager()->IsCursorLocked());
531
532  // The cursor should be hidden after touching the screen and
533  // starting a drag.
534  EXPECT_TRUE(shell->cursor_manager()->IsCursorVisible());
535  generator.PressTouch();
536  resizer->Drag(CalculateDragPoint(*resizer, 100, 10), 0);
537  EXPECT_FALSE(shell->cursor_manager()->IsCursorVisible());
538  EXPECT_FALSE(shell->cursor_manager()->IsCursorLocked());
539
540  // Moving the mouse should show the cursor.
541  generator.MoveMouseBy(1, 1);
542  EXPECT_TRUE(shell->cursor_manager()->IsCursorVisible());
543  EXPECT_FALSE(shell->cursor_manager()->IsCursorLocked());
544
545  resizer->RevertDrag();
546}
547
548// Assertions around dragging to the left/right edge of the screen.
549TEST_F(WorkspaceWindowResizerTest, Edge) {
550  if (!SupportsHostWindowResize())
551    return;
552
553  // Resize host window to force insets update.
554  UpdateDisplay("800x700");
555  // TODO(varkha): Insets are reset after every drag because of
556  // http://crbug.com/292238.
557  // Window is wide enough not to get docked right away.
558  window_->SetBounds(gfx::Rect(20, 30, 400, 60));
559  window_->SetProperty(aura::client::kCanMaximizeKey, true);
560  wm::WindowState* window_state = wm::GetWindowState(window_.get());
561
562  {
563    gfx::Rect expected_bounds_in_parent(
564        wm::GetDefaultLeftSnappedWindowBoundsInParent(window_.get()));
565
566    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
567        window_.get(), gfx::Point(), HTCAPTION));
568    ASSERT_TRUE(resizer.get());
569    resizer->Drag(CalculateDragPoint(*resizer, 0, 10), 0);
570    resizer->CompleteDrag();
571
572    EXPECT_EQ(expected_bounds_in_parent.ToString(),
573              window_->bounds().ToString());
574    ASSERT_TRUE(window_state->HasRestoreBounds());
575    EXPECT_EQ("20,30 400x60",
576              window_state->GetRestoreBoundsInScreen().ToString());
577  }
578  // Try the same with the right side.
579  {
580    gfx::Rect expected_bounds_in_parent(
581        wm::GetDefaultRightSnappedWindowBoundsInParent(window_.get()));
582
583    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
584        window_.get(), gfx::Point(), HTCAPTION));
585    ASSERT_TRUE(resizer.get());
586    resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0);
587    resizer->CompleteDrag();
588    EXPECT_EQ(expected_bounds_in_parent.ToString(),
589              window_->bounds().ToString());
590    ASSERT_TRUE(window_state->HasRestoreBounds());
591    EXPECT_EQ("20,30 400x60",
592              window_state->GetRestoreBoundsInScreen().ToString());
593  }
594
595  // Test if the restore bounds is correct in multiple displays.
596  if (!SupportsMultipleDisplays())
597    return;
598
599  // Restore the window to clear snapped state.
600  window_state->Restore();
601
602  UpdateDisplay("800x600,500x600");
603  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
604  EXPECT_EQ(root_windows[0], window_->GetRootWindow());
605  // Window is wide enough not to get docked right away.
606  window_->SetBoundsInScreen(gfx::Rect(800, 10, 400, 60),
607                             ScreenUtil::GetSecondaryDisplay());
608  EXPECT_EQ(root_windows[1], window_->GetRootWindow());
609  {
610    EXPECT_EQ("800,10 400x60", window_->GetBoundsInScreen().ToString());
611
612    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
613        window_.get(), gfx::Point(), HTCAPTION));
614    ASSERT_TRUE(resizer.get());
615    resizer->Drag(CalculateDragPoint(*resizer, 499, 0), 0);
616    int bottom =
617        ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_.get()).bottom();
618    resizer->CompleteDrag();
619    // With the resolution of 500x600 we will hit in this case the 50% screen
620    // size setting.
621    // TODO(varkha): Insets are updated because of http://crbug.com/292238
622    EXPECT_EQ("250,0 250x" + base::IntToString(bottom),
623              window_->bounds().ToString());
624    EXPECT_EQ("800,10 400x60",
625              window_state->GetRestoreBoundsInScreen().ToString());
626  }
627}
628
629// Check that non resizable windows will not get resized.
630TEST_F(WorkspaceWindowResizerTest, NonResizableWindows) {
631  window_->SetBounds(gfx::Rect(20, 30, 50, 60));
632  window_->SetProperty(aura::client::kCanResizeKey, false);
633
634  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
635      window_.get(), gfx::Point(), HTCAPTION));
636  ASSERT_TRUE(resizer.get());
637  resizer->Drag(CalculateDragPoint(*resizer, -20, 0), 0);
638  resizer->CompleteDrag();
639  EXPECT_EQ("0,30 50x60", window_->bounds().ToString());
640}
641
642TEST_F(WorkspaceWindowResizerTest, CancelSnapPhantom) {
643  if (!SupportsMultipleDisplays())
644    return;
645
646  UpdateDisplay("800x600,800x600");
647  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
648  ASSERT_EQ(2U, root_windows.size());
649
650  window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60),
651                             Shell::GetScreen()->GetPrimaryDisplay());
652  EXPECT_EQ(root_windows[0], window_->GetRootWindow());
653  EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity());
654  {
655    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
656        window_.get(), gfx::Point(), HTCAPTION));
657    ASSERT_TRUE(resizer.get());
658    EXPECT_FALSE(snap_phantom_window_controller());
659
660    // The pointer is on the edge but not shared. The snap phantom window
661    // controller should be non-NULL.
662    resizer->Drag(CalculateDragPoint(*resizer, 799, 0), 0);
663    EXPECT_TRUE(snap_phantom_window_controller());
664
665    // Move the cursor across the edge. Now the snap phantom window controller
666    // should be canceled.
667    resizer->Drag(CalculateDragPoint(*resizer, 800, 0), 0);
668    EXPECT_FALSE(snap_phantom_window_controller());
669  }
670}
671
672// Verifies that dragging a snapped window unsnaps it.
673TEST_F(WorkspaceWindowResizerTest, DragSnapped) {
674  wm::WindowState* window_state = ash::wm::GetWindowState(window_.get());
675
676  const gfx::Rect kInitialBounds(100, 100, 100, 100);
677  window_->SetBounds(kInitialBounds);
678  window_->Show();
679  const wm::WMEvent snap_event(wm::WM_EVENT_SNAP_LEFT);
680  window_state->OnWMEvent(&snap_event);
681  EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
682  gfx::Rect snapped_bounds = window_->bounds();
683  EXPECT_NE(snapped_bounds.ToString(), kInitialBounds.ToString());
684  EXPECT_EQ(window_state->GetRestoreBoundsInParent().ToString(),
685            kInitialBounds.ToString());
686
687  // Dragging a side snapped window should unsnap it.
688  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
689      window_.get(), gfx::Point(), HTCAPTION));
690  resizer->Drag(CalculateDragPoint(*resizer, 10, 0), 0);
691  resizer->CompleteDrag();
692  EXPECT_EQ(wm::WINDOW_STATE_TYPE_NORMAL, window_state->GetStateType());
693  EXPECT_EQ("10,0 100x100", window_->bounds().ToString());
694  EXPECT_FALSE(window_state->HasRestoreBounds());
695}
696
697// Verifies the behavior of resizing a side snapped window.
698TEST_F(WorkspaceWindowResizerTest, ResizeSnapped) {
699  wm::WindowState* window_state = ash::wm::GetWindowState(window_.get());
700
701  const gfx::Rect kInitialBounds(100, 100, 100, 100);
702  window_->SetBounds(kInitialBounds);
703  window_->Show();
704
705  const wm::WMEvent snap_event(wm::WM_EVENT_SNAP_LEFT);
706  window_state->OnWMEvent(&snap_event);
707  EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
708  gfx::Rect snapped_bounds = window_->bounds();
709  EXPECT_NE(snapped_bounds.ToString(), kInitialBounds.ToString());
710  EXPECT_EQ(window_state->GetRestoreBoundsInParent().ToString(),
711            kInitialBounds.ToString());
712
713  {
714    // 1) Resizing a side snapped window to make it wider should not unsnap the
715    // window.
716    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
717        window_.get(), gfx::Point(), HTRIGHT));
718    resizer->Drag(CalculateDragPoint(*resizer, 10, 0), 0);
719    resizer->CompleteDrag();
720    EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
721    snapped_bounds.Inset(0, 0, -10, 0);
722    EXPECT_EQ(snapped_bounds.ToString(), window_->bounds().ToString());
723    EXPECT_EQ(window_state->GetRestoreBoundsInParent().ToString(),
724              kInitialBounds.ToString());
725  }
726
727  {
728    // 2) Resizing a side snapped window vertically and then undoing the change
729    // should not unsnap.
730    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
731        window_.get(), gfx::Point(), HTBOTTOM));
732    resizer->Drag(CalculateDragPoint(*resizer, 0, -30), 0);
733    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
734    resizer->CompleteDrag();
735    EXPECT_EQ(wm::WINDOW_STATE_TYPE_LEFT_SNAPPED, window_state->GetStateType());
736    EXPECT_EQ(snapped_bounds.ToString(), window_->bounds().ToString());
737    EXPECT_EQ(window_state->GetRestoreBoundsInParent().ToString(),
738              kInitialBounds.ToString());
739  }
740
741  {
742    // 3) Resizing a side snapped window vertically and then not undoing the
743    // change should unsnap.
744    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
745        window_.get(), gfx::Point(), HTBOTTOM));
746    resizer->Drag(CalculateDragPoint(*resizer, 0, -10), 0);
747    resizer->CompleteDrag();
748    EXPECT_EQ(wm::WINDOW_STATE_TYPE_NORMAL, window_state->GetStateType());
749    gfx::Rect expected_bounds(snapped_bounds);
750    expected_bounds.Inset(0, 0, 0, 10);
751    EXPECT_EQ(expected_bounds.ToString(), window_->bounds().ToString());
752    EXPECT_FALSE(window_state->HasRestoreBounds());
753  }
754}
755
756// Verifies windows are correctly restacked when reordering multiple windows.
757TEST_F(WorkspaceWindowResizerTest, RestackAttached) {
758  window_->SetBounds(gfx::Rect(   0, 0, 200, 300));
759  window2_->SetBounds(gfx::Rect(200, 0, 100, 200));
760  window3_->SetBounds(gfx::Rect(300, 0, 100, 100));
761
762  {
763    std::vector<aura::Window*> windows;
764    windows.push_back(window2_.get());
765    scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
766        window_.get(), gfx::Point(), HTRIGHT,
767        aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
768    ASSERT_TRUE(resizer.get());
769    // Move it 100 to the right, which should expand w1 and push w2 and w3.
770    resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
771
772    // 2 should be topmost since it's initially the highest in the stack.
773    EXPECT_EQ("2 1 3", WindowOrderAsString(window_->parent()));
774  }
775
776  {
777    std::vector<aura::Window*> windows;
778    windows.push_back(window3_.get());
779    scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
780        window2_.get(), gfx::Point(), HTRIGHT,
781        aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
782    ASSERT_TRUE(resizer.get());
783    // Move it 100 to the right, which should expand w1 and push w2 and w3.
784    resizer->Drag(CalculateDragPoint(*resizer, 100, -10), 0);
785
786    // 2 should be topmost since it's initially the highest in the stack.
787    EXPECT_EQ("2 3 1", WindowOrderAsString(window_->parent()));
788  }
789}
790
791// Makes sure we don't allow dragging below the work area.
792TEST_F(WorkspaceWindowResizerTest, DontDragOffBottom) {
793  Shell::GetInstance()->SetDisplayWorkAreaInsets(
794      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0));
795
796  ASSERT_EQ(1, Shell::GetScreen()->GetNumDisplays());
797
798  window_->SetBounds(gfx::Rect(100, 200, 300, 400));
799  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
800      window_.get(), gfx::Point(), HTCAPTION));
801  ASSERT_TRUE(resizer.get());
802  resizer->Drag(CalculateDragPoint(*resizer, 0, 600), 0);
803  int expected_y =
804      kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
805  EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
806            window_->bounds().ToString());
807}
808
809// Makes sure we don't allow dragging on the work area with multidisplay.
810TEST_F(WorkspaceWindowResizerTest, DontDragOffBottomWithMultiDisplay) {
811  if (!SupportsMultipleDisplays())
812    return;
813
814  UpdateDisplay("800x600,800x600");
815  ASSERT_EQ(2, Shell::GetScreen()->GetNumDisplays());
816
817  Shell::GetInstance()->SetDisplayWorkAreaInsets(
818      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0));
819
820  // Positions the secondary display at the bottom the primary display.
821  Shell::GetInstance()->display_manager()->SetLayoutForCurrentDisplays(
822      ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 0));
823
824  {
825    window_->SetBounds(gfx::Rect(100, 200, 300, 20));
826    DCHECK_LT(window_->bounds().height(),
827              WorkspaceWindowResizer::kMinOnscreenHeight);
828    // Drag down avoiding dragging along the edge as that would side-snap.
829    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
830        window_.get(), gfx::Point(10, 0), HTCAPTION));
831    ASSERT_TRUE(resizer.get());
832    resizer->Drag(CalculateDragPoint(*resizer, 0, 400), 0);
833    int expected_y = kRootHeight - window_->bounds().height() - 10;
834    // When the mouse cursor is in the primary display, the window cannot move
835    // on non-work area but can get all the way towards the bottom,
836    // restricted only by the window height.
837    EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x20",
838              window_->bounds().ToString());
839    // Revert the drag in order to not remember the restore bounds.
840    resizer->RevertDrag();
841  }
842
843  Shell::GetInstance()->SetDisplayWorkAreaInsets(
844      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 10, 0));
845  {
846    window_->SetBounds(gfx::Rect(100, 200, 300, 400));
847    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
848        window_.get(), gfx::Point(10, 0), HTCAPTION));
849    ASSERT_TRUE(resizer.get());
850    // Drag down avoiding dragging along the edge as that would side-snap.
851    resizer->Drag(CalculateDragPoint(*resizer, 0, 400), 0);
852    int expected_y =
853        kRootHeight - WorkspaceWindowResizer::kMinOnscreenHeight - 10;
854    // When the mouse cursor is in the primary display, the window cannot move
855    // on non-work area with kMinOnscreenHeight margin.
856    EXPECT_EQ("100," + base::IntToString(expected_y) + " 300x400",
857              window_->bounds().ToString());
858    resizer->CompleteDrag();
859  }
860
861  {
862    window_->SetBounds(gfx::Rect(100, 200, 300, 400));
863    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
864        window_.get(), window_->bounds().origin(), HTCAPTION));
865    ASSERT_TRUE(resizer.get());
866    // Drag down avoiding getting stuck against the shelf on the bottom screen.
867    resizer->Drag(CalculateDragPoint(*resizer, 0, 500), 0);
868    // The window can move to the secondary display beyond non-work area of
869    // the primary display.
870    EXPECT_EQ("100,700 300x400", window_->bounds().ToString());
871    resizer->CompleteDrag();
872  }
873}
874
875// Makes sure we don't allow dragging off the top of the work area.
876TEST_F(WorkspaceWindowResizerTest, DontDragOffTop) {
877  Shell::GetInstance()->SetDisplayWorkAreaInsets(
878      Shell::GetPrimaryRootWindow(), gfx::Insets(10, 0, 0, 0));
879
880  window_->SetBounds(gfx::Rect(100, 200, 300, 400));
881  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
882      window_.get(), gfx::Point(), HTCAPTION));
883  ASSERT_TRUE(resizer.get());
884  resizer->Drag(CalculateDragPoint(*resizer, 0, -600), 0);
885  EXPECT_EQ("100,10 300x400", window_->bounds().ToString());
886}
887
888TEST_F(WorkspaceWindowResizerTest, ResizeBottomOutsideWorkArea) {
889  Shell::GetInstance()->SetDisplayWorkAreaInsets(
890      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
891
892  window_->SetBounds(gfx::Rect(100, 200, 300, 380));
893  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
894      window_.get(), gfx::Point(), HTTOP));
895  ASSERT_TRUE(resizer.get());
896  resizer->Drag(CalculateDragPoint(*resizer, 8, 0), 0);
897  EXPECT_EQ("100,200 300x380", window_->bounds().ToString());
898}
899
900TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideLeftWorkArea) {
901  Shell::GetInstance()->SetDisplayWorkAreaInsets(
902      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
903  int left = ScreenUtil::GetDisplayWorkAreaBoundsInParent(window_.get()).x();
904  int pixels_to_left_border = 50;
905  int window_width = 300;
906  int window_x = left - window_width + pixels_to_left_border;
907  window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
908  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
909      window_.get(), gfx::Point(pixels_to_left_border, 0), HTRIGHT));
910  ASSERT_TRUE(resizer.get());
911  resizer->Drag(CalculateDragPoint(*resizer, -window_width, 0), 0);
912  EXPECT_EQ(base::IntToString(window_x) + ",100 " +
913            base::IntToString(kMinimumOnScreenArea - window_x) +
914            "x380", window_->bounds().ToString());
915}
916
917TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideRightWorkArea) {
918  Shell::GetInstance()->SetDisplayWorkAreaInsets(
919      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
920  int right = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
921      window_.get()).right();
922  int pixels_to_right_border = 50;
923  int window_width = 300;
924  int window_x = right - pixels_to_right_border;
925  window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
926  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
927      window_.get(), gfx::Point(window_x, 0), HTLEFT));
928  ASSERT_TRUE(resizer.get());
929  resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
930  EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) +
931            ",100 " +
932            base::IntToString(window_width - pixels_to_right_border +
933                              kMinimumOnScreenArea) +
934            "x380", window_->bounds().ToString());
935}
936
937TEST_F(WorkspaceWindowResizerTest, ResizeWindowOutsideBottomWorkArea) {
938  Shell::GetInstance()->SetDisplayWorkAreaInsets(
939      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
940  int bottom = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
941      window_.get()).bottom();
942  int delta_to_bottom = 50;
943  int height = 380;
944  window_->SetBounds(gfx::Rect(100, bottom - delta_to_bottom, 300, height));
945  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
946      window_.get(), gfx::Point(0, bottom - delta_to_bottom), HTTOP));
947  ASSERT_TRUE(resizer.get());
948  resizer->Drag(CalculateDragPoint(*resizer, 0, bottom), 0);
949  EXPECT_EQ("100," +
950            base::IntToString(bottom - kMinimumOnScreenArea) +
951            " 300x" +
952            base::IntToString(height - (delta_to_bottom -
953                                        kMinimumOnScreenArea)),
954            window_->bounds().ToString());
955}
956
957// Verifies that 'outside' check of the resizer take into account the extended
958// desktop in case of repositions.
959TEST_F(WorkspaceWindowResizerTest, DragWindowOutsideRightToSecondaryDisplay) {
960  // Only primary display.  Changes the window position to fit within the
961  // display.
962  Shell::GetInstance()->SetDisplayWorkAreaInsets(
963      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
964  int right = ScreenUtil::GetDisplayWorkAreaBoundsInParent(
965      window_.get()).right();
966  int pixels_to_right_border = 50;
967  int window_width = 300;
968  int window_x = right - pixels_to_right_border;
969  window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
970  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
971      window_.get(), gfx::Point(window_x, 0), HTCAPTION));
972  ASSERT_TRUE(resizer.get());
973  resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
974  EXPECT_EQ(base::IntToString(right - kMinimumOnScreenArea) +
975            ",100 " +
976            base::IntToString(window_width) +
977            "x380", window_->bounds().ToString());
978
979  if (!SupportsMultipleDisplays())
980    return;
981
982  // With secondary display.  Operation itself is same but doesn't change
983  // the position because the window is still within the secondary display.
984  UpdateDisplay("1000x600,600x400");
985  Shell::GetInstance()->SetDisplayWorkAreaInsets(
986      Shell::GetPrimaryRootWindow(), gfx::Insets(0, 0, 50, 0));
987  window_->SetBounds(gfx::Rect(window_x, 100, window_width, 380));
988  resizer->Drag(CalculateDragPoint(*resizer, window_width, 0), 0);
989  EXPECT_EQ(base::IntToString(window_x + window_width) +
990            ",100 " +
991            base::IntToString(window_width) +
992            "x380", window_->bounds().ToString());
993}
994
995// Verifies snapping to edges works.
996TEST_F(WorkspaceWindowResizerTest, SnapToEdge) {
997  Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager()->
998      SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
999  window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1000  // Click 50px to the right so that the mouse pointer does not leave the
1001  // workspace ensuring sticky behavior.
1002  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1003      window_.get(),
1004      window_->bounds().origin() + gfx::Vector2d(50, 0),
1005      HTCAPTION));
1006  ASSERT_TRUE(resizer.get());
1007  // Move to an x-coordinate of 15, which should not snap.
1008  resizer->Drag(CalculateDragPoint(*resizer, 15 - 96, 0), 0);
1009  // An x-coordinate of 7 should snap.
1010  resizer->Drag(CalculateDragPoint(*resizer, 7 - 96, 0), 0);
1011  EXPECT_EQ("0,112 320x160", window_->bounds().ToString());
1012  // Move to -15, should still snap to 0.
1013  resizer->Drag(CalculateDragPoint(*resizer, -15 - 96, 0), 0);
1014  EXPECT_EQ("0,112 320x160", window_->bounds().ToString());
1015  // At -32 should move past snap points.
1016  resizer->Drag(CalculateDragPoint(*resizer, -32 - 96, 0), 0);
1017  EXPECT_EQ("-32,112 320x160", window_->bounds().ToString());
1018  resizer->Drag(CalculateDragPoint(*resizer, -33 - 96, 0), 0);
1019  EXPECT_EQ("-33,112 320x160", window_->bounds().ToString());
1020
1021  // Right side should similarly snap.
1022  resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 15, 0), 0);
1023  EXPECT_EQ("465,112 320x160", window_->bounds().ToString());
1024  resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 - 7, 0), 0);
1025  EXPECT_EQ("480,112 320x160", window_->bounds().ToString());
1026  resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 15, 0), 0);
1027  EXPECT_EQ("480,112 320x160", window_->bounds().ToString());
1028  resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 32, 0), 0);
1029  EXPECT_EQ("512,112 320x160", window_->bounds().ToString());
1030  resizer->Drag(CalculateDragPoint(*resizer, 800 - 320 - 96 + 33, 0), 0);
1031  EXPECT_EQ("513,112 320x160", window_->bounds().ToString());
1032
1033  // And the bottom should snap too.
1034  resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 - 7), 0);
1035  EXPECT_EQ("96,437 320x160", window_->bounds().ToString());
1036  resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 3 + 15), 0);
1037  EXPECT_EQ("96,437 320x160", window_->bounds().ToString());
1038  resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 32), 0);
1039  EXPECT_EQ("96,470 320x160", window_->bounds().ToString());
1040  resizer->Drag(CalculateDragPoint(*resizer, 0, 600 - 160 - 112 - 2 + 33), 0);
1041  EXPECT_EQ("96,471 320x160", window_->bounds().ToString());
1042
1043  // And the top should snap too.
1044  resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 20), 0);
1045  EXPECT_EQ("96,20 320x160", window_->bounds().ToString());
1046  resizer->Drag(CalculateDragPoint(*resizer, 0, -112 + 7), 0);
1047  EXPECT_EQ("96,0 320x160", window_->bounds().ToString());
1048
1049  // And bottom/left should snap too.
1050  resizer->Drag(
1051      CalculateDragPoint(*resizer, 7 - 96, 600 - 160 - 112 - 3 - 7), 0);
1052  EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
1053  resizer->Drag(
1054      CalculateDragPoint(*resizer, -15 - 96, 600 - 160 - 112 - 3 + 15), 0);
1055  EXPECT_EQ("0,437 320x160", window_->bounds().ToString());
1056  // should move past snap points.
1057  resizer->Drag(
1058      CalculateDragPoint(*resizer, -32 - 96, 600 - 160 - 112 - 2 + 32), 0);
1059  EXPECT_EQ("-32,470 320x160", window_->bounds().ToString());
1060  resizer->Drag(
1061      CalculateDragPoint(*resizer, -33 - 96, 600 - 160 - 112 - 2 + 33), 0);
1062  EXPECT_EQ("-33,471 320x160", window_->bounds().ToString());
1063
1064  // No need to test dragging < 0 as we force that to 0.
1065}
1066
1067// Verifies a resize snap when dragging TOPLEFT.
1068TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPLEFT) {
1069  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1070  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1071      window_.get(), gfx::Point(), HTTOPLEFT));
1072  ASSERT_TRUE(resizer.get());
1073  resizer->Drag(CalculateDragPoint(*resizer, -98, -199), 0);
1074  EXPECT_EQ("0,0 120x230", window_->bounds().ToString());
1075}
1076
1077// Verifies a resize snap when dragging TOPRIGHT.
1078TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_TOPRIGHT) {
1079  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1080  gfx::Rect work_area(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
1081                          window_.get()));
1082  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1083      window_.get(), gfx::Point(), HTTOPRIGHT));
1084  ASSERT_TRUE(resizer.get());
1085  resizer->Drag(
1086      CalculateDragPoint(*resizer, work_area.right() - 120 - 1, -199), 0);
1087  EXPECT_EQ(100, window_->bounds().x());
1088  EXPECT_EQ(work_area.y(), window_->bounds().y());
1089  EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
1090  EXPECT_EQ(230, window_->bounds().height());
1091}
1092
1093// Verifies a resize snap when dragging BOTTOMRIGHT.
1094TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMRIGHT) {
1095  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1096  gfx::Rect work_area(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
1097                          window_.get()));
1098  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1099      window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1100  ASSERT_TRUE(resizer.get());
1101  resizer->Drag(
1102      CalculateDragPoint(*resizer, work_area.right() - 120 - 1,
1103                         work_area.bottom() - 220 - 2), 0);
1104  EXPECT_EQ(100, window_->bounds().x());
1105  EXPECT_EQ(200, window_->bounds().y());
1106  EXPECT_EQ(work_area.right() - 100, window_->bounds().width());
1107  EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1108}
1109
1110// Verifies a resize snap when dragging BOTTOMLEFT.
1111TEST_F(WorkspaceWindowResizerTest, SnapToWorkArea_BOTTOMLEFT) {
1112  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1113  gfx::Rect work_area(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
1114                          window_.get()));
1115  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1116      window_.get(), gfx::Point(), HTBOTTOMLEFT));
1117  ASSERT_TRUE(resizer.get());
1118  resizer->Drag(
1119      CalculateDragPoint(*resizer, -98, work_area.bottom() - 220 - 2), 0);
1120  EXPECT_EQ(0, window_->bounds().x());
1121  EXPECT_EQ(200, window_->bounds().y());
1122  EXPECT_EQ(120, window_->bounds().width());
1123  EXPECT_EQ(work_area.bottom() - 200, window_->bounds().height());
1124}
1125
1126// Verifies window sticks to both window and work area.
1127TEST_F(WorkspaceWindowResizerTest, StickToBothEdgeAndWindow) {
1128  window_->SetBounds(gfx::Rect(10, 10, 20, 50));
1129  window_->Show();
1130  window2_->SetBounds(gfx::Rect(150, 160, 25, 1000));
1131  window2_->Show();
1132
1133  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1134      window_.get(), gfx::Point(10, 10), HTCAPTION));
1135  ASSERT_TRUE(resizer.get());
1136
1137  // Move |window| one pixel to the left of |window2|. Should snap to right.
1138  resizer->Drag(CalculateDragPoint(*resizer, 119, 145), 0);
1139  gfx::Rect expected(130, 160, 20, 50);
1140  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1141
1142  gfx::Rect work_area(ScreenUtil::GetDisplayWorkAreaBoundsInParent(
1143                          window_.get()));
1144
1145  // The initial y position of |window_|.
1146  int initial_y = 10;
1147  // The drag position where the window is exactly attached to the bottom.
1148  int attach_y = work_area.bottom() - window_->bounds().height() - initial_y;
1149
1150  // Dragging 10px above should not attach to the bottom.
1151  resizer->Drag(CalculateDragPoint(*resizer, 119, attach_y - 10), 0);
1152  expected.set_y(attach_y + initial_y - 10);
1153  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1154
1155  // Stick to the work area.
1156  resizer->Drag(CalculateDragPoint(*resizer, 119, attach_y - 1), 0);
1157  expected.set_y(attach_y + initial_y);
1158  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1159
1160  resizer->Drag(CalculateDragPoint(*resizer, 119, attach_y), 0);
1161  expected.set_y(attach_y + initial_y);
1162  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1163
1164  resizer->Drag(CalculateDragPoint(*resizer, 119, attach_y + 1), 0);
1165  expected.set_y(attach_y + initial_y);
1166  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1167
1168  // Moving down further should move the window.
1169  resizer->Drag(CalculateDragPoint(*resizer, 119, attach_y + 18), 0);
1170  expected.set_y(attach_y + initial_y + 18);
1171  EXPECT_EQ(expected.ToString(), window_->bounds().ToString());
1172}
1173
1174TEST_F(WorkspaceWindowResizerTest, CtrlDragResizeToExactPosition) {
1175  window_->SetBounds(gfx::Rect(96, 112, 320, 160));
1176  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1177      window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1178  ASSERT_TRUE(resizer.get());
1179  // Resize the right bottom to add 10 in width, 12 in height.
1180  resizer->Drag(CalculateDragPoint(*resizer, 10, 12), ui::EF_CONTROL_DOWN);
1181  // Both bottom and right sides to resize to exact size requested.
1182  EXPECT_EQ("96,112 330x172", window_->bounds().ToString());
1183}
1184
1185// Verifies that a dragged, non-snapped window will clear restore bounds.
1186TEST_F(WorkspaceWindowResizerTest, RestoreClearedOnResize) {
1187  window_->SetBounds(gfx::Rect(10, 10, 100, 100));
1188  wm::WindowState* window_state = wm::GetWindowState(window_.get());
1189  window_state->SetRestoreBoundsInScreen(gfx::Rect(50, 50, 50, 50));
1190  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1191      window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1192  ASSERT_TRUE(resizer.get());
1193  // Drag the window to new position by adding (20, 30) to original point,
1194  // the original restore bound should be cleared.
1195  resizer->Drag(CalculateDragPoint(*resizer, 20, 30), 0);
1196  resizer->CompleteDrag();
1197  EXPECT_EQ("10,10 120x130", window_->bounds().ToString());
1198  EXPECT_FALSE(window_state->HasRestoreBounds());
1199}
1200
1201// Verifies that a dragged window will restore to its pre-maximized size.
1202TEST_F(WorkspaceWindowResizerTest, RestoreToPreMaximizeCoordinates) {
1203  window_->SetBounds(gfx::Rect(0, 0, 1000, 1000));
1204  wm::WindowState* window_state = wm::GetWindowState(window_.get());
1205  window_state->SetRestoreBoundsInScreen(gfx::Rect(96, 112, 320, 160));
1206  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1207      window_.get(), gfx::Point(), HTCAPTION));
1208  ASSERT_TRUE(resizer.get());
1209  // Drag the window to new position by adding (10, 10) to original point,
1210  // the window should get restored.
1211  resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
1212  resizer->CompleteDrag();
1213  EXPECT_EQ("10,10 320x160", window_->bounds().ToString());
1214  // The restore rectangle should get cleared as well.
1215  EXPECT_FALSE(window_state->HasRestoreBounds());
1216}
1217
1218// Verifies that a dragged window will restore to its pre-maximized size.
1219TEST_F(WorkspaceWindowResizerTest, RevertResizeOperation) {
1220  const gfx::Rect initial_bounds(0, 0, 200, 400);
1221  window_->SetBounds(initial_bounds);
1222
1223  wm::WindowState* window_state = wm::GetWindowState(window_.get());
1224  window_state->SetRestoreBoundsInScreen(gfx::Rect(96, 112, 320, 160));
1225  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1226      window_.get(), gfx::Point(), HTCAPTION));
1227  ASSERT_TRUE(resizer.get());
1228  // Drag the window to new poistion by adding (180, 16) to original point,
1229  // the window should get restored.
1230  resizer->Drag(CalculateDragPoint(*resizer, 180, 16), 0);
1231  resizer->RevertDrag();
1232  EXPECT_EQ(initial_bounds.ToString(), window_->bounds().ToString());
1233  EXPECT_EQ("96,112 320x160",
1234            window_state->GetRestoreBoundsInScreen().ToString());
1235}
1236
1237// Check that only usable sizes get returned by the resizer.
1238TEST_F(WorkspaceWindowResizerTest, MagneticallyAttach) {
1239  window_->SetBounds(gfx::Rect(10, 10, 20, 30));
1240  window2_->SetBounds(gfx::Rect(150, 160, 25, 20));
1241  window2_->Show();
1242
1243  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1244      window_.get(), gfx::Point(), HTCAPTION));
1245  ASSERT_TRUE(resizer.get());
1246  // Move |window| one pixel to the left of |window2|. Should snap to right and
1247  // top.
1248  resizer->Drag(CalculateDragPoint(*resizer, 119, 145), 0);
1249  EXPECT_EQ("130,160 20x30", window_->bounds().ToString());
1250
1251  // Move |window| one pixel to the right of |window2|. Should snap to left and
1252  // top.
1253  resizer->Drag(CalculateDragPoint(*resizer, 164, 145), 0);
1254  EXPECT_EQ("175,160 20x30", window_->bounds().ToString());
1255
1256  // Move |window| one pixel above |window2|. Should snap to top and left.
1257  resizer->Drag(CalculateDragPoint(*resizer, 142, 119), 0);
1258  EXPECT_EQ("150,130 20x30", window_->bounds().ToString());
1259
1260  // Move |window| one pixel above the bottom of |window2|. Should snap to
1261  // bottom and left.
1262  resizer->Drag(CalculateDragPoint(*resizer, 142, 169), 0);
1263  EXPECT_EQ("150,180 20x30", window_->bounds().ToString());
1264}
1265
1266// The following variants verify magnetic snapping during resize when dragging a
1267// particular edge.
1268TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOP) {
1269  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1270  window2_->SetBounds(gfx::Rect(99, 179, 10, 20));
1271  window2_->Show();
1272
1273  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1274      window_.get(), gfx::Point(), HTTOP));
1275  ASSERT_TRUE(resizer.get());
1276  resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1277  EXPECT_EQ("100,199 20x31", window_->bounds().ToString());
1278}
1279
1280TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPLEFT) {
1281  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1282  window2_->SetBounds(gfx::Rect(99, 179, 10, 20));
1283  window2_->Show();
1284
1285  {
1286    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1287        window_.get(), gfx::Point(), HTTOPLEFT));
1288    ASSERT_TRUE(resizer.get());
1289    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1290    EXPECT_EQ("99,199 21x31", window_->bounds().ToString());
1291    resizer->RevertDrag();
1292  }
1293
1294  {
1295    window2_->SetBounds(gfx::Rect(88, 201, 10, 20));
1296    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1297        window_.get(), gfx::Point(), HTTOPLEFT));
1298    ASSERT_TRUE(resizer.get());
1299    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1300    EXPECT_EQ("98,201 22x29", window_->bounds().ToString());
1301    resizer->RevertDrag();
1302  }
1303}
1304
1305TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_TOPRIGHT) {
1306  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1307  window2_->Show();
1308
1309  {
1310    window2_->SetBounds(gfx::Rect(111, 179, 10, 20));
1311    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1312        window_.get(), gfx::Point(), HTTOPRIGHT));
1313    ASSERT_TRUE(resizer.get());
1314    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1315    EXPECT_EQ("100,199 21x31", window_->bounds().ToString());
1316    resizer->RevertDrag();
1317  }
1318
1319  {
1320    window2_->SetBounds(gfx::Rect(121, 199, 10, 20));
1321    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1322        window_.get(), gfx::Point(), HTTOPRIGHT));
1323    ASSERT_TRUE(resizer.get());
1324    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1325    EXPECT_EQ("100,199 21x31", window_->bounds().ToString());
1326    resizer->RevertDrag();
1327  }
1328}
1329
1330TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_RIGHT) {
1331  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1332  window2_->SetBounds(gfx::Rect(121, 199, 10, 20));
1333  window2_->Show();
1334
1335  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1336      window_.get(), gfx::Point(), HTRIGHT));
1337  ASSERT_TRUE(resizer.get());
1338  resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1339  EXPECT_EQ("100,200 21x30", window_->bounds().ToString());
1340}
1341
1342TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMRIGHT) {
1343  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1344  window2_->Show();
1345
1346  {
1347    window2_->SetBounds(gfx::Rect(122, 212, 10, 20));
1348    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1349        window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1350    ASSERT_TRUE(resizer.get());
1351    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1352    EXPECT_EQ("100,200 22x32", window_->bounds().ToString());
1353    resizer->RevertDrag();
1354  }
1355
1356  {
1357    window2_->SetBounds(gfx::Rect(111, 233, 10, 20));
1358    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1359        window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1360    ASSERT_TRUE(resizer.get());
1361    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1362    EXPECT_EQ("100,200 21x33", window_->bounds().ToString());
1363    resizer->RevertDrag();
1364  }
1365}
1366
1367TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOM) {
1368  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1369  window2_->SetBounds(gfx::Rect(111, 233, 10, 20));
1370  window2_->Show();
1371
1372  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1373      window_.get(), gfx::Point(), HTBOTTOM));
1374  ASSERT_TRUE(resizer.get());
1375  resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1376  EXPECT_EQ("100,200 20x33", window_->bounds().ToString());
1377}
1378
1379TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_BOTTOMLEFT) {
1380  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1381  window2_->Show();
1382
1383  {
1384    window2_->SetBounds(gfx::Rect(99, 231, 10, 20));
1385    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1386        window_.get(), gfx::Point(), HTBOTTOMLEFT));
1387    ASSERT_TRUE(resizer.get());
1388    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1389    EXPECT_EQ("99,200 21x31", window_->bounds().ToString());
1390    resizer->RevertDrag();
1391  }
1392
1393  {
1394    window2_->SetBounds(gfx::Rect(89, 209, 10, 20));
1395    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1396        window_.get(), gfx::Point(), HTBOTTOMLEFT));
1397    ASSERT_TRUE(resizer.get());
1398    resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1399    EXPECT_EQ("99,200 21x29", window_->bounds().ToString());
1400    resizer->RevertDrag();
1401  }
1402}
1403
1404TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_LEFT) {
1405  window2_->SetBounds(gfx::Rect(89, 209, 10, 20));
1406  window_->SetBounds(gfx::Rect(100, 200, 20, 30));
1407  window2_->Show();
1408
1409  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1410      window_.get(), gfx::Point(), HTLEFT));
1411  ASSERT_TRUE(resizer.get());
1412  resizer->Drag(CalculateDragPoint(*resizer, 0, 0), 0);
1413  EXPECT_EQ("99,200 21x30", window_->bounds().ToString());
1414}
1415
1416// Test that the user user moved window flag is getting properly set.
1417TEST_F(WorkspaceWindowResizerTest, CheckUserWindowManagedFlags) {
1418  window_->SetBounds(gfx::Rect( 0,  50, 400, 200));
1419  window_->SetProperty(aura::client::kCanMaximizeKey, true);
1420
1421  std::vector<aura::Window*> no_attached_windows;
1422  // Check that an abort doesn't change anything.
1423  {
1424    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1425        window_.get(), gfx::Point(), HTCAPTION));
1426    ASSERT_TRUE(resizer.get());
1427    // Move it 100 to the bottom.
1428    resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0);
1429    EXPECT_EQ("0,150 400x200", window_->bounds().ToString());
1430    resizer->RevertDrag();
1431
1432    EXPECT_FALSE(wm::GetWindowState(window_.get())->bounds_changed_by_user());
1433  }
1434
1435  // Check that a completed move / size does change the user coordinates.
1436  {
1437    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1438        window_.get(), gfx::Point(), HTCAPTION));
1439    ASSERT_TRUE(resizer.get());
1440    // Move it 100 to the bottom.
1441    resizer->Drag(CalculateDragPoint(*resizer, 0, 100), 0);
1442    EXPECT_EQ("0,150 400x200", window_->bounds().ToString());
1443    resizer->CompleteDrag();
1444    EXPECT_TRUE(wm::GetWindowState(window_.get())->bounds_changed_by_user());
1445  }
1446}
1447
1448// Test that a window with a specified max size doesn't exceed it when dragged.
1449TEST_F(WorkspaceWindowResizerTest, TestMaxSizeEnforced) {
1450  window_->SetBounds(gfx::Rect(0, 0, 400, 300));
1451  delegate_.set_max_size(gfx::Size(401, 301));
1452
1453  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1454      window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1455  resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0);
1456  EXPECT_EQ(401, window_->bounds().width());
1457  EXPECT_EQ(301, window_->bounds().height());
1458}
1459
1460// Test that a window with a specified max width doesn't restrict its height.
1461TEST_F(WorkspaceWindowResizerTest, TestPartialMaxSizeEnforced) {
1462  window_->SetBounds(gfx::Rect(0, 0, 400, 300));
1463  delegate_.set_max_size(gfx::Size(401, 0));
1464
1465  scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1466      window_.get(), gfx::Point(), HTBOTTOMRIGHT));
1467  resizer->Drag(CalculateDragPoint(*resizer, 2, 2), 0);
1468  EXPECT_EQ(401, window_->bounds().width());
1469  EXPECT_EQ(302, window_->bounds().height());
1470}
1471
1472// Test that a window with a specified max size can't be snapped.
1473TEST_F(WorkspaceWindowResizerTest, PhantomSnapMaxSize) {
1474  {
1475    // With max size not set we get a phantom window controller for dragging off
1476    // the right hand side.
1477    // Make the window wider than maximum docked width.
1478    window_->SetBounds(gfx::Rect(0, 0, 400, 200));
1479
1480    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1481        window_.get(), gfx::Point(), HTCAPTION));
1482    EXPECT_FALSE(snap_phantom_window_controller());
1483    resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0);
1484    EXPECT_TRUE(snap_phantom_window_controller());
1485    resizer->RevertDrag();
1486  }
1487  {
1488    // With max size defined, we get no phantom window for snapping but we still
1489    // get a phantom window (docking guide).
1490    window_->SetBounds(gfx::Rect(0, 0, 400, 200));
1491    delegate_.set_max_size(gfx::Size(400, 200));
1492
1493    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1494        window_.get(), gfx::Point(), HTCAPTION));
1495    resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0);
1496    EXPECT_TRUE(snap_phantom_window_controller());
1497    resizer->RevertDrag();
1498  }
1499  {
1500    // With max size defined, we get no phantom window for snapping.
1501    window_->SetBounds(gfx::Rect(0, 0, 400, 200));
1502    delegate_.set_max_size(gfx::Size(400, 200));
1503    // With min size defined, we get no phantom window for docking.
1504    delegate_.set_min_size(gfx::Size(400, 200));
1505
1506    scoped_ptr<WindowResizer> resizer(CreateResizerForTest(
1507        window_.get(), gfx::Point(), HTCAPTION));
1508    resizer->Drag(CalculateDragPoint(*resizer, 801, 0), 0);
1509    EXPECT_FALSE(snap_phantom_window_controller());
1510    resizer->RevertDrag();
1511  }
1512}
1513
1514TEST_F(WorkspaceWindowResizerTest, DontRewardRightmostWindowForOverflows) {
1515  UpdateDisplay("600x800");
1516  aura::Window* root = Shell::GetPrimaryRootWindow();
1517  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1518
1519  // Four 100x100 windows flush against eachother, starting at 100,100.
1520  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1521  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1522  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1523  window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
1524  delegate2_.set_max_size(gfx::Size(101, 0));
1525
1526  std::vector<aura::Window*> windows;
1527  windows.push_back(window2_.get());
1528  windows.push_back(window3_.get());
1529  windows.push_back(window4_.get());
1530  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1531      window_.get(), gfx::Point(), HTRIGHT,
1532      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1533  ASSERT_TRUE(resizer.get());
1534  // Move it 51 to the left, which should contract w1 and expand w2-4.
1535  // w2 will hit its max size straight away, and in doing so will leave extra
1536  // pixels that a naive implementation may award to the rightmost window. A
1537  // fair implementation will give 25 pixels to each of the other windows.
1538  resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
1539  EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
1540  EXPECT_EQ("149,100 101x100", window2_->bounds().ToString());
1541  EXPECT_EQ("250,100 125x100", window3_->bounds().ToString());
1542  EXPECT_EQ("375,100 125x100", window4_->bounds().ToString());
1543}
1544
1545TEST_F(WorkspaceWindowResizerTest, DontExceedMaxWidth) {
1546  UpdateDisplay("600x800");
1547  aura::Window* root = Shell::GetPrimaryRootWindow();
1548  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1549
1550  // Four 100x100 windows flush against eachother, starting at 100,100.
1551  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1552  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1553  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1554  window4_->SetBounds(gfx::Rect(400, 100, 100, 100));
1555  delegate2_.set_max_size(gfx::Size(101, 0));
1556  delegate3_.set_max_size(gfx::Size(101, 0));
1557
1558  std::vector<aura::Window*> windows;
1559  windows.push_back(window2_.get());
1560  windows.push_back(window3_.get());
1561  windows.push_back(window4_.get());
1562  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1563      window_.get(), gfx::Point(), HTRIGHT,
1564      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1565  ASSERT_TRUE(resizer.get());
1566  // Move it 52 to the left, which should contract w1 and expand w2-4.
1567  resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
1568  EXPECT_EQ("100,100 48x100", window_->bounds().ToString());
1569  EXPECT_EQ("148,100 101x100", window2_->bounds().ToString());
1570  EXPECT_EQ("249,100 101x100", window3_->bounds().ToString());
1571  EXPECT_EQ("350,100 150x100", window4_->bounds().ToString());
1572}
1573
1574TEST_F(WorkspaceWindowResizerTest, DontExceedMaxHeight) {
1575  UpdateDisplay("600x800");
1576  aura::Window* root = Shell::GetPrimaryRootWindow();
1577  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1578
1579  // Four 100x100 windows flush against eachother, starting at 100,100.
1580  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1581  window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
1582  window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
1583  window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
1584  delegate2_.set_max_size(gfx::Size(0, 101));
1585  delegate3_.set_max_size(gfx::Size(0, 101));
1586
1587  std::vector<aura::Window*> windows;
1588  windows.push_back(window2_.get());
1589  windows.push_back(window3_.get());
1590  windows.push_back(window4_.get());
1591  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1592      window_.get(), gfx::Point(), HTBOTTOM,
1593      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1594  ASSERT_TRUE(resizer.get());
1595  // Move it 52 up, which should contract w1 and expand w2-4.
1596  resizer->Drag(CalculateDragPoint(*resizer, 0, -52), 0);
1597  EXPECT_EQ("100,100 100x48", window_->bounds().ToString());
1598  EXPECT_EQ("100,148 100x101", window2_->bounds().ToString());
1599  EXPECT_EQ("100,249 100x101", window3_->bounds().ToString());
1600  EXPECT_EQ("100,350 100x150", window4_->bounds().ToString());
1601}
1602
1603#if defined(OS_WIN)
1604// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
1605#define MAYBE_DontExceedMinHeight DISABLED_DontExceedMinHeight
1606#else
1607#define MAYBE_DontExceedMinHeight DontExceedMinHeight
1608#endif
1609
1610TEST_F(WorkspaceWindowResizerTest, MAYBE_DontExceedMinHeight) {
1611  UpdateDisplay("600x500");
1612  aura::Window* root = Shell::GetPrimaryRootWindow();
1613  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1614
1615  // Four 100x100 windows flush against eachother, starting at 100,100.
1616  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1617  window2_->SetBounds(gfx::Rect(100, 200, 100, 100));
1618  window3_->SetBounds(gfx::Rect(100, 300, 100, 100));
1619  window4_->SetBounds(gfx::Rect(100, 400, 100, 100));
1620  delegate2_.set_min_size(gfx::Size(0, 99));
1621  delegate3_.set_min_size(gfx::Size(0, 99));
1622
1623  std::vector<aura::Window*> windows;
1624  windows.push_back(window2_.get());
1625  windows.push_back(window3_.get());
1626  windows.push_back(window4_.get());
1627  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1628      window_.get(), gfx::Point(), HTBOTTOM,
1629      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1630  ASSERT_TRUE(resizer.get());
1631  // Move it 52 down, which should expand w1 and contract w2-4.
1632  resizer->Drag(CalculateDragPoint(*resizer, 0, 52), 0);
1633  EXPECT_EQ("100,100 100x152", window_->bounds().ToString());
1634  EXPECT_EQ("100,252 100x99", window2_->bounds().ToString());
1635  EXPECT_EQ("100,351 100x99", window3_->bounds().ToString());
1636  EXPECT_EQ("100,450 100x50", window4_->bounds().ToString());
1637}
1638
1639TEST_F(WorkspaceWindowResizerTest, DontExpandRightmostPastMaxWidth) {
1640  UpdateDisplay("600x800");
1641  aura::Window* root = Shell::GetPrimaryRootWindow();
1642  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1643
1644  // Three 100x100 windows flush against eachother, starting at 100,100.
1645  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1646  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1647  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1648  delegate3_.set_max_size(gfx::Size(101, 0));
1649
1650  std::vector<aura::Window*> windows;
1651  windows.push_back(window2_.get());
1652  windows.push_back(window3_.get());
1653  windows.push_back(window4_.get());
1654  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1655      window_.get(), gfx::Point(), HTRIGHT,
1656      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1657  ASSERT_TRUE(resizer.get());
1658  // Move it 51 to the left, which should contract w1 and expand w2-3.
1659  resizer->Drag(CalculateDragPoint(*resizer, -51, 0), 0);
1660  EXPECT_EQ("100,100 49x100", window_->bounds().ToString());
1661  EXPECT_EQ("149,100 150x100", window2_->bounds().ToString());
1662  EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
1663}
1664
1665TEST_F(WorkspaceWindowResizerTest, MoveAttachedWhenGrownToMaxSize) {
1666  UpdateDisplay("600x800");
1667  aura::Window* root = Shell::GetPrimaryRootWindow();
1668  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1669
1670  // Three 100x100 windows flush against eachother, starting at 100,100.
1671  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1672  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1673  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1674  delegate2_.set_max_size(gfx::Size(101, 0));
1675  delegate3_.set_max_size(gfx::Size(101, 0));
1676
1677  std::vector<aura::Window*> windows;
1678  windows.push_back(window2_.get());
1679  windows.push_back(window3_.get());
1680  windows.push_back(window4_.get());
1681  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1682      window_.get(), gfx::Point(), HTRIGHT,
1683      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1684  ASSERT_TRUE(resizer.get());
1685  // Move it 52 to the left, which should contract w1 and expand and move w2-3.
1686  resizer->Drag(CalculateDragPoint(*resizer, -52, 0), 0);
1687  EXPECT_EQ("100,100 48x100", window_->bounds().ToString());
1688  EXPECT_EQ("148,100 101x100", window2_->bounds().ToString());
1689  EXPECT_EQ("249,100 101x100", window3_->bounds().ToString());
1690}
1691
1692#if defined(OS_WIN)
1693// RootWindow and Display can't resize on Windows Ash. http://crbug.com/165962
1694#define MAYBE_MainWindowHonoursMaxWidth DISABLED_MainWindowHonoursMaxWidth
1695#else
1696#define MAYBE_MainWindowHonoursMaxWidth MainWindowHonoursMaxWidth
1697#endif
1698
1699TEST_F(WorkspaceWindowResizerTest, MAYBE_MainWindowHonoursMaxWidth) {
1700  UpdateDisplay("400x800");
1701  aura::Window* root = Shell::GetPrimaryRootWindow();
1702  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1703
1704  // Three 100x100 windows flush against eachother, starting at 100,100.
1705  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1706  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1707  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1708  delegate_.set_max_size(gfx::Size(102, 0));
1709
1710  std::vector<aura::Window*> windows;
1711  windows.push_back(window2_.get());
1712  windows.push_back(window3_.get());
1713  windows.push_back(window4_.get());
1714  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1715      window_.get(), gfx::Point(), HTRIGHT,
1716      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1717  ASSERT_TRUE(resizer.get());
1718  // Move it 50 to the right, which should expand w1 and contract w2-3, as they
1719  // won't fit in the root window in their original sizes.
1720  resizer->Drag(CalculateDragPoint(*resizer, 50, 0), 0);
1721  EXPECT_EQ("100,100 102x100", window_->bounds().ToString());
1722  EXPECT_EQ("202,100 99x100", window2_->bounds().ToString());
1723  EXPECT_EQ("301,100 99x100", window3_->bounds().ToString());
1724}
1725
1726TEST_F(WorkspaceWindowResizerTest, MainWindowHonoursMinWidth) {
1727  UpdateDisplay("400x800");
1728  aura::Window* root = Shell::GetPrimaryRootWindow();
1729  Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets());
1730
1731  // Three 100x100 windows flush against eachother, starting at 100,100.
1732  window_->SetBounds(gfx::Rect( 100, 100, 100, 100));
1733  window2_->SetBounds(gfx::Rect(200, 100, 100, 100));
1734  window3_->SetBounds(gfx::Rect(300, 100, 100, 100));
1735  delegate_.set_min_size(gfx::Size(98, 0));
1736
1737  std::vector<aura::Window*> windows;
1738  windows.push_back(window2_.get());
1739  windows.push_back(window3_.get());
1740  scoped_ptr<WorkspaceWindowResizer> resizer(CreateWorkspaceResizerForTest(
1741      window_.get(), gfx::Point(), HTRIGHT,
1742      aura::client::WINDOW_MOVE_SOURCE_MOUSE, windows));
1743  ASSERT_TRUE(resizer.get());
1744  // Move it 50 to the left, which should contract w1 and expand w2-3.
1745  resizer->Drag(CalculateDragPoint(*resizer, -50, 0), 0);
1746  EXPECT_EQ("100,100 98x100", window_->bounds().ToString());
1747  EXPECT_EQ("198,100 101x100", window2_->bounds().ToString());
1748  EXPECT_EQ("299,100 101x100", window3_->bounds().ToString());
1749}
1750
1751// The following variants test that windows are resized correctly to the edges
1752// of the screen using touch, when touch point is off of the window border.
1753TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_RIGHT) {
1754  shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1755
1756  InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTRIGHT);
1757  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1758            touch_resize_window_->bounds().ToString());
1759
1760  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1761                                     touch_resize_window_.get());
1762
1763  // Drag out of the right border a bit and check if the border is aligned with
1764  // the touch point.
1765  generator.GestureScrollSequence(gfx::Point(715, kRootHeight / 2),
1766                                  gfx::Point(725, kRootHeight / 2),
1767                                  base::TimeDelta::FromMilliseconds(10),
1768                                  5);
1769  EXPECT_EQ(gfx::Rect(100, 100, 625, kRootHeight - 200).ToString(),
1770            touch_resize_window_->bounds().ToString());
1771  // Drag more, but stop before being snapped to the edge.
1772  generator.GestureScrollSequence(gfx::Point(725, kRootHeight / 2),
1773                                  gfx::Point(760, kRootHeight / 2),
1774                                  base::TimeDelta::FromMilliseconds(10),
1775                                  5);
1776  EXPECT_EQ(gfx::Rect(100, 100, 660, kRootHeight - 200).ToString(),
1777            touch_resize_window_->bounds().ToString());
1778  // Drag even more to snap to the edge.
1779  generator.GestureScrollSequence(gfx::Point(760, kRootHeight / 2),
1780                                  gfx::Point(775, kRootHeight / 2),
1781                                  base::TimeDelta::FromMilliseconds(10),
1782                                  5);
1783  EXPECT_EQ(gfx::Rect(100, 100, 700, kRootHeight - 200).ToString(),
1784            touch_resize_window_->bounds().ToString());
1785}
1786
1787TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_LEFT) {
1788  shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1789
1790  InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTLEFT);
1791  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1792            touch_resize_window_->bounds().ToString());
1793
1794  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1795                                     touch_resize_window_.get());
1796
1797  // Drag out of the left border a bit and check if the border is aligned with
1798  // the touch point.
1799  generator.GestureScrollSequence(gfx::Point(85, kRootHeight / 2),
1800                                  gfx::Point(75, kRootHeight / 2),
1801                                  base::TimeDelta::FromMilliseconds(10),
1802                                  5);
1803  EXPECT_EQ(gfx::Rect(75, 100, 625, kRootHeight - 200).ToString(),
1804            touch_resize_window_->bounds().ToString());
1805  // Drag more, but stop before being snapped to the edge.
1806  generator.GestureScrollSequence(gfx::Point(75, kRootHeight / 2),
1807                                  gfx::Point(40, kRootHeight / 2),
1808                                  base::TimeDelta::FromMilliseconds(10),
1809                                  5);
1810  EXPECT_EQ(gfx::Rect(40, 100, 660, kRootHeight - 200).ToString(),
1811            touch_resize_window_->bounds().ToString());
1812  // Drag even more to snap to the edge.
1813  generator.GestureScrollSequence(gfx::Point(40, kRootHeight / 2),
1814                                  gfx::Point(25, kRootHeight / 2),
1815                                  base::TimeDelta::FromMilliseconds(10),
1816                                  5);
1817  EXPECT_EQ(gfx::Rect(0, 100, 700, kRootHeight - 200).ToString(),
1818            touch_resize_window_->bounds().ToString());
1819}
1820
1821TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_TOP) {
1822  shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1823
1824  InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTTOP);
1825  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1826            touch_resize_window_->bounds().ToString());
1827
1828  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1829                                     touch_resize_window_.get());
1830
1831  // Drag out of the top border a bit and check if the border is aligned with
1832  // the touch point.
1833  generator.GestureScrollSequence(gfx::Point(400, 85),
1834                                  gfx::Point(400, 75),
1835                                  base::TimeDelta::FromMilliseconds(10),
1836                                  5);
1837  EXPECT_EQ(gfx::Rect(100, 75, 600, kRootHeight - 175).ToString(),
1838            touch_resize_window_->bounds().ToString());
1839  // Drag more, but stop before being snapped to the edge.
1840  generator.GestureScrollSequence(gfx::Point(400, 75),
1841                                  gfx::Point(400, 40),
1842                                  base::TimeDelta::FromMilliseconds(10),
1843                                  5);
1844  EXPECT_EQ(gfx::Rect(100, 40, 600, kRootHeight - 140).ToString(),
1845            touch_resize_window_->bounds().ToString());
1846  // Drag even more to snap to the edge.
1847  generator.GestureScrollSequence(gfx::Point(400, 40),
1848                                  gfx::Point(400, 25),
1849                                  base::TimeDelta::FromMilliseconds(10),
1850                                  5);
1851  EXPECT_EQ(gfx::Rect(100, 0, 600, kRootHeight - 100).ToString(),
1852            touch_resize_window_->bounds().ToString());
1853}
1854
1855TEST_F(WorkspaceWindowResizerTest, TouchResizeToEdge_BOTTOM) {
1856  shelf_layout_manager()->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
1857
1858  InitTouchResizeWindow(gfx::Rect(100, 100, 600, kRootHeight - 200), HTBOTTOM);
1859  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 200).ToString(),
1860            touch_resize_window_->bounds().ToString());
1861
1862  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
1863                                     touch_resize_window_.get());
1864
1865  // Drag out of the bottom border a bit and check if the border is aligned with
1866  // the touch point.
1867  generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 85),
1868                                  gfx::Point(400, kRootHeight - 75),
1869                                  base::TimeDelta::FromMilliseconds(10),
1870                                  5);
1871  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 175).ToString(),
1872            touch_resize_window_->bounds().ToString());
1873  // Drag more, but stop before being snapped to the edge.
1874  generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 75),
1875                                  gfx::Point(400, kRootHeight - 40),
1876                                  base::TimeDelta::FromMilliseconds(10),
1877                                  5);
1878  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 140).ToString(),
1879            touch_resize_window_->bounds().ToString());
1880  // Drag even more to snap to the edge.
1881  generator.GestureScrollSequence(gfx::Point(400, kRootHeight - 40),
1882                                  gfx::Point(400, kRootHeight - 25),
1883                                  base::TimeDelta::FromMilliseconds(10),
1884                                  5);
1885  EXPECT_EQ(gfx::Rect(100, 100, 600, kRootHeight - 100).ToString(),
1886            touch_resize_window_->bounds().ToString());
1887}
1888
1889}  // namespace ash
1890