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