Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / wrench_menu / wrench_menu_controller_unittest.mm
blob6d0c1b9459bcf4f55d9950486601b565b887e79a
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.
5 #include "base/command_line.h"
6 #include "base/mac/scoped_nsobject.h"
7 #include "base/strings/sys_string_conversions.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/app/chrome_command_ids.h"
10 #include "chrome/browser/sync/glue/session_model_associator.h"
11 #include "chrome/browser/sync/glue/device_info.h"
12 #include "chrome/browser/sync/profile_sync_service_factory.h"
13 #include "chrome/browser/sync/sessions2/sessions_sync_manager.h"
14 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
15 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
16 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
17 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
18 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h"
19 #include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h"
20 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
21 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "grit/generated_resources.h"
25 #include "grit/theme_resources.h"
26 #include "sync/api/fake_sync_change_processor.h"
27 #include "sync/api/sync_error_factory_mock.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "testing/gtest_mac.h"
31 #include "testing/platform_test.h"
32 #include "ui/base/l10n/l10n_util.h"
34 namespace {
36 class MockWrenchMenuModel : public WrenchMenuModel {
37  public:
38   MockWrenchMenuModel() : WrenchMenuModel() {}
39   ~MockWrenchMenuModel() {
40     // This dirty, ugly hack gets around a bug in the test. In
41     // ~WrenchMenuModel(), there's a call to TabstripModel::RemoveObserver(this)
42     // which mysteriously leads to this crash: http://crbug.com/49206 .  It
43     // seems that the vector of observers is getting hosed somewhere between
44     // |-[ToolbarController dealloc]| and ~MockWrenchMenuModel(). This line
45     // short-circuits the parent destructor to avoid this crash.
46     tab_strip_model_ = NULL;
47   }
48   MOCK_METHOD2(ExecuteCommand, void(int command_id, int event_flags));
51 class DummyRouter : public browser_sync::LocalSessionEventRouter {
52  public:
53   virtual ~DummyRouter() {}
54   virtual void StartRoutingTo(
55       browser_sync::LocalSessionEventHandler* handler) OVERRIDE {}
56   virtual void Stop() OVERRIDE {}
59 class WrenchMenuControllerTest
60     : public CocoaProfileTest,
61       public browser_sync::SessionsSyncManager::SyncInternalApiDelegate {
62  public:
63   virtual void SetUp() OVERRIDE {
64     CocoaProfileTest::SetUp();
65     ASSERT_TRUE(browser());
67     controller_.reset([[WrenchMenuController alloc] initWithBrowser:browser()]);
68     fake_model_.reset(new MockWrenchMenuModel);
70     if (CommandLine::ForCurrentProcess()->HasSwitch(
71             switches::kEnableSyncSessionsV2)) {
72       manager_.reset(new browser_sync::SessionsSyncManager(
73           profile(),
74           this,
75           scoped_ptr<browser_sync::LocalSessionEventRouter>(
76               new DummyRouter())));
77       manager_->MergeDataAndStartSyncing(
78           syncer::SESSIONS,
79           syncer::SyncDataList(),
80           scoped_ptr<syncer::SyncChangeProcessor>(
81               new syncer::FakeSyncChangeProcessor),
82           scoped_ptr<syncer::SyncErrorFactory>(
83               new syncer::SyncErrorFactoryMock));
84     } else {
85       ProfileSyncService* sync_service =
86           ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile());
87       associator_.reset(new browser_sync::SessionModelAssociator(
88           sync_service, true));
89       associator_->SetCurrentMachineTagForTesting(
90           GetLocalSyncCacheGUID());
91     }
92   }
94   virtual scoped_ptr<browser_sync::DeviceInfo> GetLocalDeviceInfo()
95       const OVERRIDE {
96     return scoped_ptr<browser_sync::DeviceInfo>(
97         new browser_sync::DeviceInfo(GetLocalSyncCacheGUID(),
98                        "Test Machine",
99                        "Chromium 10k",
100                        "Chrome 10k",
101                        sync_pb::SyncEnums_DeviceType_TYPE_LINUX));
102   }
104   virtual std::string GetLocalSyncCacheGUID() const OVERRIDE {
105     return "WrenchMenuControllerTest";
106   }
108   void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
109     if (CommandLine::ForCurrentProcess()->HasSwitch(
110             switches::kEnableSyncSessionsV2)) {
111       helper->ExportToSessionsSyncManager(manager_.get());
112     } else {
113       helper->ExportToSessionModelAssociator(associator_.get());
114     }
115   }
117   browser_sync::OpenTabsUIDelegate* GetOpenTabsDelegate() {
118     if (CommandLine::ForCurrentProcess()->HasSwitch(
119             switches::kEnableSyncSessionsV2)) {
120       return manager_.get();
121     } else {
122       return associator_.get();
123     }
124   }
126   virtual void TearDown() OVERRIDE {
127     fake_model_.reset();
128     controller_.reset();
129     associator_.reset();
130     manager_.reset();
131     CocoaProfileTest::TearDown();
132   }
134   WrenchMenuController* controller() {
135     return controller_.get();
136   }
138   base::scoped_nsobject<WrenchMenuController> controller_;
140   scoped_ptr<MockWrenchMenuModel> fake_model_;
142  private:
143   // TODO(tim): Bug 98892. Remove associator_ once sessions2 is the default.
144   scoped_ptr<browser_sync::SessionModelAssociator> associator_;
145   scoped_ptr<browser_sync::SessionsSyncManager> manager_;
148 TEST_F(WrenchMenuControllerTest, Initialized) {
149   EXPECT_TRUE([controller() menu]);
150   EXPECT_GE([[controller() menu] numberOfItems], 5);
153 TEST_F(WrenchMenuControllerTest, DispatchSimple) {
154   base::scoped_nsobject<NSButton> button([[NSButton alloc] init]);
155   [button setTag:IDC_ZOOM_PLUS];
157   // Set fake model to test dispatching.
158   EXPECT_CALL(*fake_model_, ExecuteCommand(IDC_ZOOM_PLUS, 0));
159   [controller() setModel:fake_model_.get()];
161   [controller() dispatchWrenchMenuCommand:button.get()];
162   chrome::testing::NSRunLoopRunAllPending();
165 TEST_F(WrenchMenuControllerTest, RecentTabsFavIcon) {
166   RecentTabsBuilderTestHelper recent_tabs_builder;
167   recent_tabs_builder.AddSession();
168   recent_tabs_builder.AddWindow(0);
169   recent_tabs_builder.AddTab(0, 0);
170   RegisterRecentTabs(&recent_tabs_builder);
172   RecentTabsSubMenuModel recent_tabs_sub_menu_model(
173       NULL, browser(), GetOpenTabsDelegate());
174   fake_model_->AddSubMenuWithStringId(
175       IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
176       &recent_tabs_sub_menu_model);
178   [controller() setModel:fake_model_.get()];
179   NSMenu* menu = [controller() menu];
180   [controller() updateRecentTabsSubmenu];
182   NSString* title = l10n_util::GetNSStringWithFixup(IDS_RECENT_TABS_MENU);
183   NSMenu* recent_tabs_menu = [[menu itemWithTitle:title] submenu];
184   EXPECT_TRUE(recent_tabs_menu);
185   EXPECT_EQ(6, [recent_tabs_menu numberOfItems]);
187   // Send a icon changed event and verify that the icon is updated.
188   gfx::Image icon(ResourceBundle::GetSharedInstance().GetNativeImageNamed(
189       IDR_BOOKMARKS_FAVICON));
190   recent_tabs_sub_menu_model.SetIcon(3, icon);
191   EXPECT_NSNE(icon.ToNSImage(), [[recent_tabs_menu itemAtIndex:3] image]);
192   recent_tabs_sub_menu_model.GetMenuModelDelegate()->OnIconChanged(3);
193   EXPECT_TRUE([[recent_tabs_menu itemAtIndex:3] image]);
194   EXPECT_NSEQ(icon.ToNSImage(), [[recent_tabs_menu itemAtIndex:3] image]);
196   controller_.reset();
197   fake_model_.reset();
200 TEST_F(WrenchMenuControllerTest, RecentTabsElideTitle) {
201   // Add 1 session with 1 window and 2 tabs.
202   RecentTabsBuilderTestHelper recent_tabs_builder;
203   recent_tabs_builder.AddSession();
204   recent_tabs_builder.AddWindow(0);
205   base::string16 tab1_short_title = base::ASCIIToUTF16("Short");
206   recent_tabs_builder.AddTabWithInfo(0, 0, base::Time::Now(), tab1_short_title);
207   base::string16 tab2_long_title = base::ASCIIToUTF16(
208       "Very very very very very very very very very very very very long");
209   recent_tabs_builder.AddTabWithInfo(0, 0,
210       base::Time::Now() - base::TimeDelta::FromMinutes(10), tab2_long_title);
211   RegisterRecentTabs(&recent_tabs_builder);
213   RecentTabsSubMenuModel recent_tabs_sub_menu_model(
214       NULL, browser(), GetOpenTabsDelegate());
215   fake_model_->AddSubMenuWithStringId(
216       IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
217       &recent_tabs_sub_menu_model);
219   [controller() setModel:fake_model_.get()];
220   NSMenu* menu = [controller() menu];
221   [controller() updateRecentTabsSubmenu];
223   NSString* title = l10n_util::GetNSStringWithFixup(IDS_RECENT_TABS_MENU);
224   NSMenu* recent_tabs_menu = [[menu itemWithTitle:title] submenu];
225   EXPECT_TRUE(recent_tabs_menu);
226   EXPECT_EQ(7, [recent_tabs_menu numberOfItems]);
228   // Index 0: restore tabs menu item.
229   NSString* restore_tab_label = l10n_util::FixUpWindowsStyleLabel(
230       recent_tabs_sub_menu_model.GetLabelAt(0));
231   EXPECT_NSEQ(restore_tab_label, [[recent_tabs_menu itemAtIndex:0] title]);
233   // Item 1: separator.
234   EXPECT_TRUE([[recent_tabs_menu itemAtIndex:1] isSeparatorItem]);
236   // Item 2: window title.
237   EXPECT_NSEQ(
238       base::SysUTF16ToNSString(recent_tabs_sub_menu_model.GetLabelAt(2)),
239       [[recent_tabs_menu itemAtIndex:2] title]);
241   // Item 3: short tab title.
242   EXPECT_NSEQ(base::SysUTF16ToNSString(tab1_short_title),
243               [[recent_tabs_menu itemAtIndex:3] title]);
245   // Item 4: long tab title.
246   NSString* tab2_actual_title = [[recent_tabs_menu itemAtIndex:4] title];
247   NSUInteger title_length = [tab2_actual_title length];
248   EXPECT_GT(tab2_long_title.size(), title_length);
249   NSString* actual_substring =
250       [tab2_actual_title substringToIndex:title_length - 1];
251   NSString* expected_substring = [base::SysUTF16ToNSString(tab2_long_title)
252       substringToIndex:title_length - 1];
253   EXPECT_NSEQ(expected_substring, actual_substring);
255   controller_.reset();
256   fake_model_.reset();
259 // Verify that |RecentTabsMenuModelDelegate| is deleted before the model
260 // it's observing.
261 TEST_F(WrenchMenuControllerTest, RecentTabDeleteOrder) {
262   [controller_ menuNeedsUpdate:[controller_ menu]];
263   // If the delete order is wrong then the test will crash on exit.
266 }  // namespace