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