Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / wm / workspace / workspace_window_resizer_unittest.cc
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
32 namespace ash {
33 namespace {
34
35 const int kRootHeight = 600;
36
37 // A simple window delegate that returns the specified min size.
38 class 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
70 class 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.
213 TEST_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.
247 TEST_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.
281 TEST_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.
322 TEST_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.
356 TEST_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.
390 TEST_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.
432 TEST_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.
477 TEST_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.
512 TEST_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.
549 TEST_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.
630 TEST_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
642 TEST_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.
673 TEST_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.
698 TEST_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.
757 TEST_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.
792 TEST_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.
810 TEST_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.
876 TEST_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
888 TEST_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
900 TEST_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
917 TEST_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
937 TEST_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.
959 TEST_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.
996 TEST_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.
1068 TEST_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.
1078 TEST_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.
1094 TEST_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.
1111 TEST_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.
1127 TEST_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
1174 TEST_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.
1186 TEST_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.
1202 TEST_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.
1219 TEST_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.
1238 TEST_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.
1268 TEST_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
1280 TEST_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
1305 TEST_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
1330 TEST_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
1342 TEST_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
1367 TEST_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
1379 TEST_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
1404 TEST_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.
1417 TEST_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.
1449 TEST_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.
1461 TEST_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.
1473 TEST_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
1514 TEST_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
1545 TEST_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
1574 TEST_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
1610 TEST_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
1639 TEST_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
1665 TEST_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
1699 TEST_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
1726 TEST_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.
1753 TEST_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
1787 TEST_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
1821 TEST_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
1855 TEST_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