Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / ash / tab_scrubber_browsertest.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 "chrome/browser/ui/views/ash/tab_scrubber.h"
6
7 #include "ash/display/event_transformation_handler.h"
8 #include "ash/shell.h"
9 #include "base/command_line.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "chrome/browser/ui/browser_tabstrip.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
16 #include "chrome/browser/ui/views/frame/browser_view.h"
17 #include "chrome/browser/ui/views/tabs/tab.h"
18 #include "chrome/browser/ui/views/tabs/tab_strip.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/test/test_utils.h"
25 #include "ui/aura/window.h"
26 #include "ui/events/event_utils.h"
27 #include "ui/events/test/event_generator.h"
28
29 #if defined(OS_CHROMEOS)
30 #include "chromeos/chromeos_switches.h"
31 #endif
32
33 namespace {
34
35 class TabScrubberTest : public InProcessBrowserTest,
36                         public TabStripModelObserver {
37  public:
38   TabScrubberTest()
39       : target_index_(-1) {
40   }
41
42   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
43 #if defined(OS_CHROMEOS)
44     command_line->AppendSwitch(chromeos::switches::kNaturalScrollDefault);
45 #endif
46     command_line->AppendSwitch(switches::kOpenAsh);
47   }
48
49   virtual void SetUpOnMainThread() OVERRIDE {
50     TabScrubber::GetInstance()->set_activation_delay(0);
51
52     // Disable external monitor scaling of coordinates.
53     ash::Shell* shell = ash::Shell::GetInstance();
54     shell->event_transformation_handler()->set_transformation_mode(
55         ash::EventTransformationHandler::TRANSFORM_NONE);
56   }
57
58   virtual void TearDownOnMainThread() OVERRIDE {
59     browser()->tab_strip_model()->RemoveObserver(this);
60   }
61
62   TabStrip* GetTabStrip(Browser* browser) {
63     aura::Window* window = browser->window()->GetNativeWindow();
64     return BrowserView::GetBrowserViewForNativeWindow(window)->tabstrip();
65   }
66
67   int GetStartX(Browser* browser,
68                 int index,
69                 TabScrubber::Direction direction) {
70     return TabScrubber::GetStartPoint(
71         GetTabStrip(browser), index, direction).x();
72   }
73
74   int GetTabCenter(Browser* browser, int index) {
75     return GetTabStrip(browser)->tab_at(index)->bounds().CenterPoint().x();
76   }
77
78   // Sends one scroll event synchronously without initial or final
79   // fling events.
80   void SendScrubEvent(Browser* browser, int index) {
81     aura::Window* window = browser->window()->GetNativeWindow();
82     aura::Window* root = window->GetRootWindow();
83     ui::test::EventGenerator event_generator(root, window);
84     int active_index = browser->tab_strip_model()->active_index();
85     TabScrubber::Direction direction = index < active_index ?
86         TabScrubber::LEFT : TabScrubber::RIGHT;
87     int offset = GetTabCenter(browser, index) -
88         GetStartX(browser, active_index, direction);
89     ui::ScrollEvent scroll_event(ui::ET_SCROLL,
90                                  gfx::Point(0, 0),
91                                  ui::EventTimeForNow(),
92                                  0,
93                                  offset, 0,
94                                  offset, 0,
95                                  3);
96     event_generator.Dispatch(&scroll_event);
97   }
98
99   enum ScrubType {
100     EACH_TAB,
101     SKIP_TABS,
102     REPEAT_TABS,
103   };
104
105   // Sends asynchronous events and waits for tab at |index| to become
106   // active.
107   void Scrub(Browser* browser, int index, ScrubType scrub_type) {
108     aura::Window* window = browser->window()->GetNativeWindow();
109     aura::Window* root = window->GetRootWindow();
110     ui::test::EventGenerator event_generator(root, window);
111     event_generator.set_async(true);
112     activation_order_.clear();
113     int active_index = browser->tab_strip_model()->active_index();
114     ASSERT_NE(index, active_index);
115     ASSERT_TRUE(scrub_type != SKIP_TABS || ((index - active_index) % 2) == 0);
116     TabScrubber::Direction direction;
117     int increment;
118     if (index < active_index) {
119       direction = TabScrubber::LEFT;
120       increment = -1;
121     } else {
122       direction = TabScrubber::RIGHT;
123       increment = 1;
124     }
125     if (scrub_type == SKIP_TABS)
126       increment *= 2;
127     int last = GetStartX(browser, active_index, direction);
128     std::vector<gfx::Point> offsets;
129     for (int i = active_index + increment; i != (index + increment);
130         i += increment) {
131       int tab_center = GetTabCenter(browser, i);
132       offsets.push_back(gfx::Point(tab_center - last, 0));
133       last = GetStartX(browser, i, direction);
134       if (scrub_type == REPEAT_TABS) {
135         offsets.push_back(gfx::Point(increment, 0));
136         last += increment;
137       }
138     }
139     event_generator.ScrollSequence(gfx::Point(0, 0),
140                                    base::TimeDelta::FromMilliseconds(100),
141                                    offsets,
142                                    3);
143     RunUntilTabActive(browser, index);
144   }
145
146   // Sends events and waits for tab at |index| to become active
147   // if it's different from the currently active tab.
148   // If the active tab is expected to stay the same, send events
149   // synchronously (as we don't have anything to wait for).
150   void SendScrubSequence(Browser* browser, int x_offset, int index) {
151     aura::Window* window = browser->window()->GetNativeWindow();
152     aura::Window* root = window->GetRootWindow();
153     ui::test::EventGenerator event_generator(root, window);
154     bool wait_for_active = false;
155     if (index != browser->tab_strip_model()->active_index()) {
156       wait_for_active = true;
157       event_generator.set_async(true);
158     }
159     event_generator.ScrollSequence(gfx::Point(0, 0),
160                                    ui::EventTimeForNow(),
161                                    x_offset,
162                                    0,
163                                    1,
164                                    3);
165     if (wait_for_active)
166       RunUntilTabActive(browser, index);
167   }
168
169   void AddTabs(Browser* browser, int num_tabs) {
170     TabStrip* tab_strip = GetTabStrip(browser);
171     for (int i = 0; i < num_tabs; ++i)
172       AddBlankTabAndShow(browser);
173     ASSERT_EQ(num_tabs + 1, browser->tab_strip_model()->count());
174     ASSERT_EQ(num_tabs, browser->tab_strip_model()->active_index());
175     tab_strip->StopAnimating(true);
176     ASSERT_FALSE(tab_strip->IsAnimating());
177   }
178
179   // TabStripModelObserver overrides.
180   virtual void TabInsertedAt(content::WebContents* contents,
181                              int index,
182                              bool foreground) OVERRIDE {}
183   virtual void TabClosingAt(TabStripModel* tab_strip_model,
184                             content::WebContents* contents,
185                             int index) OVERRIDE {}
186   virtual void TabDetachedAt(content::WebContents* contents,
187                              int index) OVERRIDE {}
188   virtual void TabDeactivated(content::WebContents* contents) OVERRIDE {}
189   virtual void ActiveTabChanged(content::WebContents* old_contents,
190                                 content::WebContents* new_contents,
191                                 int index,
192                                 int reason) OVERRIDE {
193     activation_order_.push_back(index);
194     if (index == target_index_)
195       quit_closure_.Run();
196   }
197
198   virtual void TabSelectionChanged(
199       TabStripModel* tab_strip_model,
200       const ui::ListSelectionModel& old_model) OVERRIDE {}
201   virtual void TabMoved(content::WebContents* contents,
202                         int from_index,
203                         int to_index) OVERRIDE {}
204   virtual void TabChangedAt(content::WebContents* contents,
205                             int index,
206                             TabChangeType change_type) OVERRIDE {}
207   virtual void TabReplacedAt(TabStripModel* tab_strip_model,
208                              content::WebContents* old_contents,
209                              content::WebContents* new_contents,
210                              int index) OVERRIDE {}
211   virtual void TabPinnedStateChanged(content::WebContents* contents,
212                                      int index) OVERRIDE {}
213   virtual void TabMiniStateChanged(content::WebContents* contents,
214                                    int index) OVERRIDE {
215   }
216   virtual void TabBlockedStateChanged(content::WebContents* contents,
217                                       int index) OVERRIDE {}
218   virtual void TabStripEmpty() OVERRIDE {}
219   virtual void TabStripModelDeleted() OVERRIDE {}
220
221   // History of tab activation. Scrub() resets it.
222   std::vector<int> activation_order_;
223
224  private:
225   void RunUntilTabActive(Browser* browser, int target) {
226     base::RunLoop run_loop;
227     quit_closure_ = content::GetQuitTaskForRunLoop(&run_loop);
228     browser->tab_strip_model()->AddObserver(this);
229     target_index_ = target;
230     content::RunThisRunLoop(&run_loop);
231     browser->tab_strip_model()->RemoveObserver(this);
232     target_index_ = -1;
233   }
234
235   base::Closure quit_closure_;
236   int target_index_;
237
238   DISALLOW_COPY_AND_ASSIGN(TabScrubberTest);
239 };
240
241 }  // namespace
242
243 #if defined(OS_CHROMEOS)
244 // Swipe a single tab in each direction.
245 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Single) {
246   AddTabs(browser(), 1);
247
248   Scrub(browser(), 0, EACH_TAB);
249   EXPECT_EQ(1U, activation_order_.size());
250   EXPECT_EQ(0, activation_order_[0]);
251   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
252
253   Scrub(browser(), 1, EACH_TAB);
254   EXPECT_EQ(1U, activation_order_.size());
255   EXPECT_EQ(1, activation_order_[0]);
256   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
257 }
258
259 // Swipe 4 tabs in each direction. Each of the tabs should become active.
260 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Multi) {
261   AddTabs(browser(), 4);
262
263   Scrub(browser(), 0, EACH_TAB);
264   ASSERT_EQ(4U, activation_order_.size());
265   EXPECT_EQ(3, activation_order_[0]);
266   EXPECT_EQ(2, activation_order_[1]);
267   EXPECT_EQ(1, activation_order_[2]);
268   EXPECT_EQ(0, activation_order_[3]);
269   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
270
271   Scrub(browser(), 4, EACH_TAB);
272   ASSERT_EQ(4U, activation_order_.size());
273   EXPECT_EQ(1, activation_order_[0]);
274   EXPECT_EQ(2, activation_order_[1]);
275   EXPECT_EQ(3, activation_order_[2]);
276   EXPECT_EQ(4, activation_order_[3]);
277   EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
278 }
279
280 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MultiBrowser) {
281   AddTabs(browser(), 1);
282   Scrub(browser(), 0, EACH_TAB);
283   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
284
285   Browser* browser2 = CreateBrowser(browser()->profile());
286   browser2->window()->Activate();
287   ASSERT_TRUE(browser2->window()->IsActive());
288   ASSERT_FALSE(browser()->window()->IsActive());
289   AddTabs(browser2, 1);
290
291   Scrub(browser2, 0, EACH_TAB);
292   EXPECT_EQ(0, browser2->tab_strip_model()->active_index());
293 }
294
295 // Swipe 4 tabs in each direction with an extra swipe within each. The same
296 // 4 tabs should become active.
297 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Repeated) {
298   AddTabs(browser(), 4);
299
300   Scrub(browser(), 0, REPEAT_TABS);
301   ASSERT_EQ(4U, activation_order_.size());
302   EXPECT_EQ(3, activation_order_[0]);
303   EXPECT_EQ(2, activation_order_[1]);
304   EXPECT_EQ(1, activation_order_[2]);
305   EXPECT_EQ(0, activation_order_[3]);
306   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
307
308   Scrub(browser(), 4, REPEAT_TABS);
309   ASSERT_EQ(4U, activation_order_.size());
310   EXPECT_EQ(1, activation_order_[0]);
311   EXPECT_EQ(2, activation_order_[1]);
312   EXPECT_EQ(3, activation_order_[2]);
313   EXPECT_EQ(4, activation_order_[3]);
314   EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
315 }
316
317 // Confirm that we get the last tab made active when we skip tabs.
318 // These tests have 5 total tabs. We will only received scroll events
319 // on tabs 0, 2 and 4.
320 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Skipped) {
321   AddTabs(browser(), 4);
322
323   Scrub(browser(), 0, SKIP_TABS);
324   EXPECT_EQ(2U, activation_order_.size());
325   EXPECT_EQ(2, activation_order_[0]);
326   EXPECT_EQ(0, activation_order_[1]);
327   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
328
329   Scrub(browser(), 4, SKIP_TABS);
330   EXPECT_EQ(2U, activation_order_.size());
331   EXPECT_EQ(2, activation_order_[0]);
332   EXPECT_EQ(4, activation_order_[1]);
333   EXPECT_EQ(4, browser()->tab_strip_model()->active_index());
334 }
335
336 // Confirm that nothing happens when the swipe is small.
337 IN_PROC_BROWSER_TEST_F(TabScrubberTest, NoChange) {
338   AddTabs(browser(), 1);
339
340   SendScrubSequence(browser(), -1, 1);
341   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
342
343   SendScrubSequence(browser(), 1, 1);
344   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
345 }
346
347 // Confirm that very large swipes go to the beginning and and of the tabstrip.
348 IN_PROC_BROWSER_TEST_F(TabScrubberTest, Bounds) {
349   AddTabs(browser(), 1);
350
351   SendScrubSequence(browser(), -10000, 0);
352   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
353
354   SendScrubSequence(browser(), 10000, 1);
355   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
356 }
357
358 IN_PROC_BROWSER_TEST_F(TabScrubberTest, DeleteHighlighted) {
359   AddTabs(browser(), 1);
360
361   SendScrubEvent(browser(), 0);
362   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
363   browser()->tab_strip_model()->CloseWebContentsAt(0,
364                                                    TabStripModel::CLOSE_NONE);
365   EXPECT_FALSE(TabScrubber::GetInstance()->IsActivationPending());
366 }
367
368 // Delete the currently highlighted tab. Make sure the TabScrubber is aware.
369 IN_PROC_BROWSER_TEST_F(TabScrubberTest, DeleteBeforeHighlighted) {
370   AddTabs(browser(), 2);
371
372   SendScrubEvent(browser(), 1);
373   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
374   browser()->tab_strip_model()->CloseWebContentsAt(0,
375                                                    TabStripModel::CLOSE_NONE);
376   EXPECT_EQ(0, TabScrubber::GetInstance()->highlighted_tab());
377 }
378
379 // Move the currently highlighted tab and confirm it gets tracked.
380 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveHighlighted) {
381   AddTabs(browser(), 1);
382
383   SendScrubEvent(browser(), 0);
384   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
385   browser()->tab_strip_model()->ToggleSelectionAt(0);
386   browser()->tab_strip_model()->ToggleSelectionAt(1);
387   browser()->tab_strip_model()->MoveSelectedTabsTo(1);
388   EXPECT_EQ(1, TabScrubber::GetInstance()->highlighted_tab());
389 }
390
391 // Move a tab to before  the highlighted one.
392 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveBefore) {
393   AddTabs(browser(), 2);
394
395   SendScrubEvent(browser(), 1);
396   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
397   browser()->tab_strip_model()->ToggleSelectionAt(0);
398   browser()->tab_strip_model()->ToggleSelectionAt(2);
399   browser()->tab_strip_model()->MoveSelectedTabsTo(2);
400   EXPECT_EQ(0, TabScrubber::GetInstance()->highlighted_tab());
401 }
402
403 // Move a tab to after the highlighted one.
404 IN_PROC_BROWSER_TEST_F(TabScrubberTest, MoveAfter) {
405   AddTabs(browser(), 2);
406
407   SendScrubEvent(browser(), 1);
408   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
409   browser()->tab_strip_model()->MoveSelectedTabsTo(0);
410   EXPECT_EQ(2, TabScrubber::GetInstance()->highlighted_tab());
411 }
412
413 // Close the browser while an activation is pending.
414 IN_PROC_BROWSER_TEST_F(TabScrubberTest, CloseBrowser) {
415   AddTabs(browser(), 1);
416
417   SendScrubEvent(browser(), 0);
418   EXPECT_TRUE(TabScrubber::GetInstance()->IsActivationPending());
419   browser()->window()->Close();
420   EXPECT_FALSE(TabScrubber::GetInstance()->IsActivationPending());
421 }
422
423 #endif  // defined(OS_CHROMEOS)