Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / toolbar / recent_tabs_sub_menu_model_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 "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/command_line.h"
11 #include "base/run_loop.h"
12 #include "chrome/app/chrome_command_ids.h"
13 #include "chrome/browser/sessions/persistent_tab_restore_service.h"
14 #include "chrome/browser/sessions/session_service.h"
15 #include "chrome/browser/sessions/session_service_factory.h"
16 #include "chrome/browser/sessions/session_types.h"
17 #include "chrome/browser/sessions/tab_restore_service_factory.h"
18 #include "chrome/browser/sync/glue/local_device_info_provider_mock.h"
19 #include "chrome/browser/sync/glue/synced_session.h"
20 #include "chrome/browser/sync/profile_sync_service_mock.h"
21 #include "chrome/browser/sync/sessions/sessions_sync_manager.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_tabstrip.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/test/base/browser_with_test_window_test.h"
28 #include "chrome/test/base/menu_model_test.h"
29 #include "chrome/test/base/testing_profile.h"
30 #include "components/sessions/serialized_navigation_entry_test_helper.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/test/test_utils.h"
33 #include "grit/generated_resources.h"
34 #include "sync/api/fake_sync_change_processor.h"
35 #include "sync/api/sync_error_factory_mock.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38
39 namespace {
40
41 // This copies parts of MenuModelTest::Delegate and combines them with the
42 // RecentTabsSubMenuModel since RecentTabsSubMenuModel is a
43 // SimpleMenuModel::Delegate and not just derived from SimpleMenuModel.
44 class TestRecentTabsSubMenuModel : public RecentTabsSubMenuModel {
45  public:
46   TestRecentTabsSubMenuModel(ui::AcceleratorProvider* provider,
47                              Browser* browser,
48                              browser_sync::OpenTabsUIDelegate* delegate)
49       : RecentTabsSubMenuModel(provider, browser, delegate),
50         execute_count_(0),
51         enable_count_(0) {
52   }
53
54   // Testing overrides to ui::SimpleMenuModel::Delegate:
55   virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE {
56     bool val = RecentTabsSubMenuModel::IsCommandIdEnabled(command_id);
57     if (val)
58       ++enable_count_;
59     return val;
60   }
61
62   virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE {
63     ++execute_count_;
64   }
65
66   int execute_count() const { return execute_count_; }
67   int enable_count() const { return enable_count_; }
68
69  private:
70   int execute_count_;
71   int mutable enable_count_;  // Mutable because IsCommandIdEnabledAt is const.
72
73   DISALLOW_COPY_AND_ASSIGN(TestRecentTabsSubMenuModel);
74 };
75
76 class TestRecentTabsMenuModelDelegate : public ui::MenuModelDelegate {
77  public:
78   explicit TestRecentTabsMenuModelDelegate(ui::MenuModel* model)
79       : model_(model),
80         got_changes_(false) {
81     model_->SetMenuModelDelegate(this);
82   }
83
84   virtual ~TestRecentTabsMenuModelDelegate() {
85     model_->SetMenuModelDelegate(NULL);
86   }
87
88   // ui::MenuModelDelegate implementation:
89
90   virtual void OnIconChanged(int index) OVERRIDE {
91   }
92
93   virtual void OnMenuStructureChanged() OVERRIDE {
94     got_changes_ = true;
95   }
96
97   bool got_changes() const { return got_changes_; }
98
99  private:
100   ui::MenuModel* model_;
101   bool got_changes_;
102
103   DISALLOW_COPY_AND_ASSIGN(TestRecentTabsMenuModelDelegate);
104 };
105
106 class DummyRouter : public browser_sync::LocalSessionEventRouter {
107  public:
108   virtual ~DummyRouter() {}
109   virtual void StartRoutingTo(
110       browser_sync::LocalSessionEventHandler* handler) OVERRIDE {}
111   virtual void Stop() OVERRIDE {}
112 };
113
114 }  // namespace
115
116 class RecentTabsSubMenuModelTest
117     : public BrowserWithTestWindowTest {
118  public:
119   RecentTabsSubMenuModelTest()
120       : sync_service_(&testing_profile_),
121         local_device_(new browser_sync::LocalDeviceInfoProviderMock(
122                       "RecentTabsSubMenuModelTest",
123                       "Test Machine",
124                       "Chromium 10k",
125                       "Chrome 10k",
126                       sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
127                       "device_id")) {
128     manager_.reset(new browser_sync::SessionsSyncManager(
129         &testing_profile_,
130         local_device_.get(),
131         scoped_ptr<browser_sync::LocalSessionEventRouter>(
132             new DummyRouter())));
133     manager_->MergeDataAndStartSyncing(
134         syncer::SESSIONS,
135         syncer::SyncDataList(),
136         scoped_ptr<syncer::SyncChangeProcessor>(
137           new syncer::FakeSyncChangeProcessor),
138         scoped_ptr<syncer::SyncErrorFactory>(
139             new syncer::SyncErrorFactoryMock));
140   }
141
142   void WaitForLoadFromLastSession() {
143     content::RunAllBlockingPoolTasksUntilIdle();
144   }
145
146   static KeyedService* GetTabRestoreService(
147       content::BrowserContext* browser_context) {
148     // Ownership is tranfered to the profile.
149     return new PersistentTabRestoreService(
150         Profile::FromBrowserContext(browser_context), NULL);
151   }
152
153   browser_sync::OpenTabsUIDelegate* GetOpenTabsDelegate() {
154     return manager_.get();
155   }
156
157   void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
158     helper->ExportToSessionsSyncManager(manager_.get());
159   }
160
161  private:
162   TestingProfile testing_profile_;
163   testing::NiceMock<ProfileSyncServiceMock> sync_service_;
164
165   scoped_ptr<browser_sync::SessionsSyncManager> manager_;
166   scoped_ptr<browser_sync::LocalDeviceInfoProviderMock> local_device_;
167 };
168
169 // Test disabled "Recently closed" header with no foreign tabs.
170 TEST_F(RecentTabsSubMenuModelTest, NoTabs) {
171   TestRecentTabsSubMenuModel model(NULL, browser(), NULL);
172
173   // Expected menu:
174   // Menu index  Menu items
175   // ---------------------------------------------
176   // 0           Recently closed header (disabled)
177   // 1           <separator>
178   // 2           No tabs from other Devices
179
180   int num_items = model.GetItemCount();
181   EXPECT_EQ(3, num_items);
182   EXPECT_FALSE(model.IsEnabledAt(0));
183   EXPECT_FALSE(model.IsEnabledAt(2));
184   EXPECT_EQ(0, model.enable_count());
185
186   EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
187   EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
188   EXPECT_EQ(NULL, model.GetLabelFontListAt(2));
189
190   std::string url;
191   base::string16 title;
192   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
193   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
194   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
195 }
196
197 // Test enabled "Recently closed" header with no foreign tabs.
198 TEST_F(RecentTabsSubMenuModelTest, RecentlyClosedTabsFromCurrentSession) {
199   TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
200       profile(), RecentTabsSubMenuModelTest::GetTabRestoreService);
201
202   // Add 2 tabs and close them.
203   AddTab(browser(), GURL("http://foo/1"));
204   AddTab(browser(), GURL("http://foo/2"));
205   browser()->tab_strip_model()->CloseAllTabs();
206
207   TestRecentTabsSubMenuModel model(NULL, browser(), NULL);
208   // Expected menu:
209   // Menu index  Menu items
210   // --------------------------------------
211   // 0           Recently closed header
212   // 1           <tab for http://foo/2>
213   // 2           <tab for http://foo/1>
214   // 3           <separator>
215   // 4           No tabs from other Devices
216   int num_items = model.GetItemCount();
217   EXPECT_EQ(5, num_items);
218   EXPECT_FALSE(model.IsEnabledAt(0));
219   EXPECT_TRUE(model.IsEnabledAt(1));
220   EXPECT_TRUE(model.IsEnabledAt(2));
221   model.ActivatedAt(1);
222   model.ActivatedAt(2);
223   EXPECT_FALSE(model.IsEnabledAt(4));
224   EXPECT_EQ(2, model.enable_count());
225   EXPECT_EQ(2, model.execute_count());
226
227   EXPECT_TRUE(model.GetLabelFontListAt(0) != NULL);
228   EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
229   EXPECT_EQ(NULL, model.GetLabelFontListAt(2));
230   EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
231   EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
232
233   std::string url;
234   base::string16 title;
235   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
236   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
237   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
238   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
239   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
240 }
241
242 // TODO(sail): enable this test when dynamic model is enabled in
243 // RecentTabsSubMenuModel.
244 #if defined(OS_MACOSX)
245 #define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \
246     DISABLED_RecentlyClosedTabsAndWindowsFromLastSession
247 #else
248 #define MAYBE_RecentlyClosedTabsAndWindowsFromLastSession \
249     RecentlyClosedTabsAndWindowsFromLastSession
250 #endif
251 TEST_F(RecentTabsSubMenuModelTest,
252        MAYBE_RecentlyClosedTabsAndWindowsFromLastSession) {
253   TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
254       profile(), RecentTabsSubMenuModelTest::GetTabRestoreService);
255
256   // Add 2 tabs and close them.
257   AddTab(browser(), GURL("http://wnd/tab0"));
258   AddTab(browser(), GURL("http://wnd/tab1"));
259   browser()->tab_strip_model()->CloseAllTabs();
260
261   // Create a SessionService for the profile (profile owns the service) and add
262   // a window with a tab to this session.
263   SessionService* session_service = new SessionService(profile());
264   SessionServiceFactory::SetForTestProfile(profile(), session_service);
265   SessionID tab_id;
266   SessionID window_id;
267   session_service->SetWindowType(
268       window_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
269   session_service->SetTabWindow(window_id, tab_id);
270   session_service->SetTabIndexInWindow(window_id, tab_id, 0);
271   session_service->SetSelectedTabInWindow(window_id, 0);
272   session_service->UpdateTabNavigation(
273       window_id, tab_id,
274       sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
275           "http://wnd1/tab0", "title"));
276   // Set this, otherwise previous session won't be loaded.
277   profile()->set_last_session_exited_cleanly(false);
278   // Move this session to the last so that TabRestoreService will load it as the
279   // last session.
280   SessionServiceFactory::GetForProfile(profile())->
281       MoveCurrentSessionToLastSession();
282
283   // Create a new TabRestoreService so that it'll load the recently closed tabs
284   // and windows afresh.
285   TabRestoreServiceFactory::GetInstance()->SetTestingFactory(
286       profile(), RecentTabsSubMenuModelTest::GetTabRestoreService);
287   // Let the shutdown of previous TabRestoreService run.
288   content::RunAllBlockingPoolTasksUntilIdle();
289
290   TestRecentTabsSubMenuModel model(NULL, browser(), NULL);
291   TestRecentTabsMenuModelDelegate delegate(&model);
292   EXPECT_FALSE(delegate.got_changes());
293
294   // Expected menu before tabs/windows from last session are loaded:
295   // Menu index  Menu items
296   // ----------------------------------------------------------------
297   // 0           Recently closed header
298   // 1           <separator>
299   // 2           No tabs from other Devices
300
301   int num_items = model.GetItemCount();
302   EXPECT_EQ(3, num_items);
303   EXPECT_FALSE(model.IsEnabledAt(0));
304   EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(1));
305   EXPECT_FALSE(model.IsEnabledAt(2));
306   EXPECT_EQ(0, model.enable_count());
307
308   // Wait for tabs from last session to be loaded.
309   WaitForLoadFromLastSession();
310
311   // Expected menu after tabs/windows from last session are loaded:
312   // Menu index  Menu items
313   // --------------------------------------------------------------
314   // 0           Recently closed header
315   // 1           <window for the tab http://wnd1/tab0>
316   // 2           <tab for http://wnd0/tab1>
317   // 3           <tab for http://wnd0/tab0>
318   // 4           <separator>
319   // 5           No tabs from other Devices
320
321   EXPECT_TRUE(delegate.got_changes());
322
323   num_items = model.GetItemCount();
324   EXPECT_EQ(6, num_items);
325   EXPECT_FALSE(model.IsEnabledAt(0));
326   EXPECT_TRUE(model.IsEnabledAt(1));
327   EXPECT_TRUE(model.IsEnabledAt(2));
328   EXPECT_TRUE(model.IsEnabledAt(3));
329   model.ActivatedAt(1);
330   model.ActivatedAt(2);
331   model.ActivatedAt(3);
332   EXPECT_EQ(ui::MenuModel::TYPE_SEPARATOR, model.GetTypeAt(4));
333   EXPECT_FALSE(model.IsEnabledAt(5));
334   EXPECT_EQ(3, model.enable_count());
335   EXPECT_EQ(3, model.execute_count());
336
337   EXPECT_TRUE(model.GetLabelFontListAt(0) != NULL);
338   EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
339   EXPECT_EQ(NULL, model.GetLabelFontListAt(2));
340   EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
341   EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
342   EXPECT_EQ(NULL, model.GetLabelFontListAt(5));
343
344   std::string url;
345   base::string16 title;
346   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
347   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
348   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
349   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
350   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
351   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
352 }
353
354 // Test disabled "Recently closed" header with multiple sessions, multiple
355 // windows, and multiple enabled tabs from other devices.
356 TEST_F(RecentTabsSubMenuModelTest, OtherDevices) {
357   // Tabs are populated in decreasing timestamp.
358   base::Time timestamp = base::Time::Now();
359   const base::TimeDelta time_delta = base::TimeDelta::FromMinutes(10);
360
361   RecentTabsBuilderTestHelper recent_tabs_builder;
362
363   // Create 1st session : 1 window, 3 tabs
364   recent_tabs_builder.AddSession();
365   recent_tabs_builder.AddWindow(0);
366   for (int i = 0; i < 3; ++i) {
367     timestamp -= time_delta;
368     recent_tabs_builder.AddTabWithInfo(0, 0, timestamp, base::string16());
369   }
370
371   // Create 2nd session : 2 windows, 1 tab in 1st window, 2 tabs in 2nd window
372   recent_tabs_builder.AddSession();
373   recent_tabs_builder.AddWindow(1);
374   recent_tabs_builder.AddWindow(1);
375   timestamp -= time_delta;
376   recent_tabs_builder.AddTabWithInfo(1, 0, timestamp, base::string16());
377   timestamp -= time_delta;
378   recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16());
379   timestamp -= time_delta;
380   recent_tabs_builder.AddTabWithInfo(1, 1, timestamp, base::string16());
381
382   RegisterRecentTabs(&recent_tabs_builder);
383
384   // Verify that data is populated correctly in RecentTabsSubMenuModel.
385   // Expected menu:
386   // - first inserted tab is most recent and hence is top
387   // Menu index  Menu items
388   // -----------------------------------------------------
389   // 0           Recently closed header (disabled)
390   // 1           <separator>
391   // 2           <section header for 1st session>
392   // 3-5         <3 tabs of the only window of session 0>
393   // 6           <separator>
394   // 7           <section header for 2nd session>
395   // 8           <the only tab of window 0 of session 1>
396   // 9-10        <2 tabs of window 1 of session 2>
397   // 11          <separator>
398   // 12          More...
399
400   TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate());
401   int num_items = model.GetItemCount();
402   EXPECT_EQ(13, num_items);
403   model.ActivatedAt(0);
404   EXPECT_FALSE(model.IsEnabledAt(0));
405   model.ActivatedAt(3);
406   EXPECT_TRUE(model.IsEnabledAt(3));
407   model.ActivatedAt(4);
408   EXPECT_TRUE(model.IsEnabledAt(4));
409   model.ActivatedAt(5);
410   EXPECT_TRUE(model.IsEnabledAt(5));
411   model.ActivatedAt(8);
412   EXPECT_TRUE(model.IsEnabledAt(8));
413   model.ActivatedAt(9);
414   EXPECT_TRUE(model.IsEnabledAt(9));
415   model.ActivatedAt(10);
416   EXPECT_TRUE(model.IsEnabledAt(10));
417   EXPECT_TRUE(model.IsEnabledAt(12));
418   EXPECT_EQ(7, model.enable_count());
419   EXPECT_EQ(7, model.execute_count());
420
421   EXPECT_EQ(NULL, model.GetLabelFontListAt(0));
422   EXPECT_EQ(NULL, model.GetLabelFontListAt(1));
423   EXPECT_TRUE(model.GetLabelFontListAt(2) != NULL);
424   EXPECT_EQ(NULL, model.GetLabelFontListAt(3));
425   EXPECT_EQ(NULL, model.GetLabelFontListAt(4));
426   EXPECT_EQ(NULL, model.GetLabelFontListAt(5));
427   EXPECT_EQ(NULL, model.GetLabelFontListAt(6));
428   EXPECT_TRUE(model.GetLabelFontListAt(7) != NULL);
429   EXPECT_EQ(NULL, model.GetLabelFontListAt(8));
430   EXPECT_EQ(NULL, model.GetLabelFontListAt(9));
431   EXPECT_EQ(NULL, model.GetLabelFontListAt(10));
432   EXPECT_EQ(NULL, model.GetLabelFontListAt(11));
433   EXPECT_EQ(NULL, model.GetLabelFontListAt(12));
434
435   std::string url;
436   base::string16 title;
437   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(0, &url, &title));
438   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(1, &url, &title));
439   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(2, &url, &title));
440   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(3, &url, &title));
441   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(4, &url, &title));
442   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(5, &url, &title));
443   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(6, &url, &title));
444   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(7, &url, &title));
445   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(8, &url, &title));
446   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(9, &url, &title));
447   EXPECT_TRUE(model.GetURLAndTitleForItemAtIndex(10, &url, &title));
448   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(11, &url, &title));
449   EXPECT_FALSE(model.GetURLAndTitleForItemAtIndex(12, &url, &title));
450 }
451
452 TEST_F(RecentTabsSubMenuModelTest, MaxSessionsAndRecency) {
453   // Create 4 sessions : each session has 1 window with 1 tab each.
454   RecentTabsBuilderTestHelper recent_tabs_builder;
455   for (int s = 0; s < 4; ++s) {
456     recent_tabs_builder.AddSession();
457     recent_tabs_builder.AddWindow(s);
458     recent_tabs_builder.AddTab(s, 0);
459   }
460   RegisterRecentTabs(&recent_tabs_builder);
461
462   // Verify that data is populated correctly in RecentTabsSubMenuModel.
463   // Expected menu:
464   // - max sessions is 3, so only 3 most-recent sessions will show.
465   // Menu index  Menu items
466   // ----------------------------------------------------------
467   // 0           Recently closed header (disabled)
468   // 1           <separator>
469   // 2           <section header for 1st session>
470   // 3           <the only tab of the only window of session 3>
471   // 4           <separator>
472   // 5           <section header for 2nd session>
473   // 6           <the only tab of the only window of session 2>
474   // 7           <separator>
475   // 8           <section header for 3rd session>
476   // 9           <the only tab of the only window of session 1>
477   // 10          <separator>
478   // 11          More...
479
480   TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate());
481   int num_items = model.GetItemCount();
482   EXPECT_EQ(12, num_items);
483
484   std::vector<base::string16> tab_titles =
485       recent_tabs_builder.GetTabTitlesSortedByRecency();
486   EXPECT_EQ(tab_titles[0], model.GetLabelAt(3));
487   EXPECT_EQ(tab_titles[1], model.GetLabelAt(6));
488   EXPECT_EQ(tab_titles[2], model.GetLabelAt(9));
489 }
490
491 TEST_F(RecentTabsSubMenuModelTest, MaxTabsPerSessionAndRecency) {
492   // Create a session: 2 windows with 5 tabs each.
493   RecentTabsBuilderTestHelper recent_tabs_builder;
494   recent_tabs_builder.AddSession();
495   for (int w = 0; w < 2; ++w) {
496     recent_tabs_builder.AddWindow(0);
497     for (int t = 0; t < 5; ++t)
498       recent_tabs_builder.AddTab(0, w);
499   }
500   RegisterRecentTabs(&recent_tabs_builder);
501
502   // Verify that data is populated correctly in RecentTabsSubMenuModel.
503   // Expected menu:
504   // - max tabs per session is 4, so only 4 most-recent tabs will show,
505   //   independent of which window they came from.
506   // Menu index  Menu items
507   // ---------------------------------------------
508   // 0           Recently closed header (disabled)
509   // 1           <separator>
510   // 2           <section header for session>
511   // 3-6         <4 most-recent tabs of session>
512   // 7           <separator>
513   // 8           More...
514
515   TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate());
516   int num_items = model.GetItemCount();
517   EXPECT_EQ(9, num_items);
518
519   std::vector<base::string16> tab_titles =
520       recent_tabs_builder.GetTabTitlesSortedByRecency();
521   for (int i = 0; i < 4; ++i)
522     EXPECT_EQ(tab_titles[i], model.GetLabelAt(i + 3));
523 }
524
525 TEST_F(RecentTabsSubMenuModelTest, MaxWidth) {
526   // Create 1 session with 1 window and 1 tab.
527   RecentTabsBuilderTestHelper recent_tabs_builder;
528   recent_tabs_builder.AddSession();
529   recent_tabs_builder.AddWindow(0);
530   recent_tabs_builder.AddTab(0, 0);
531   RegisterRecentTabs(&recent_tabs_builder);
532
533   // Menu index  Menu items
534   // ----------------------------------------------------------
535   // 0           Recently closed header (disabled)
536   // 1           <separator>
537   // 2           <section header for 1st session>
538   // 3           <the only tab of the only window of session 1>
539   // 4           <separator>
540   // 5           More...
541
542   TestRecentTabsSubMenuModel model(NULL, browser(), GetOpenTabsDelegate());
543   EXPECT_EQ(6, model.GetItemCount());
544   EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0));
545   EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1));
546   EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(2));
547   EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(3));
548 }
549
550 TEST_F(RecentTabsSubMenuModelTest, MaxWidthNoDevices) {
551   // Expected menu:
552   // Menu index  Menu items
553   // --------------------------------------------
554   // 0           Recently closed heaer (disabled)
555   // 1           <separator>
556   // 2           No tabs from other Devices
557
558   TestRecentTabsSubMenuModel model(NULL, browser(), NULL);
559   EXPECT_EQ(3, model.GetItemCount());
560   EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(0));
561   EXPECT_NE(-1, model.GetMaxWidthForItemAtIndex(1));
562   EXPECT_EQ(-1, model.GetMaxWidthForItemAtIndex(2));
563 }