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