Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / wrench_menu / wrench_menu_controller_unittest.mm
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 "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/profile_sync_service_factory.h"
11 #include "chrome/browser/sync/sessions/sessions_sync_manager.h"
12 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
13 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
14 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
15 #import "chrome/browser/ui/cocoa/view_resizer_pong.h"
16 #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h"
17 #include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h"
18 #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h"
19 #include "chrome/browser/ui/toolbar/wrench_menu_model.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "components/sync_driver/local_device_info_provider_mock.h"
24 #include "grit/theme_resources.h"
25 #include "sync/api/fake_sync_change_processor.h"
26 #include "sync/api/sync_error_factory_mock.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "testing/gtest_mac.h"
30 #include "testing/platform_test.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "ui/base/resource/resource_bundle.h"
33
34 namespace {
35
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));
49 };
50
51 class DummyRouter : public browser_sync::LocalSessionEventRouter {
52  public:
53   ~DummyRouter() override {}
54   void StartRoutingTo(
55       browser_sync::LocalSessionEventHandler* handler) override {}
56   void Stop() override {}
57 };
58
59 class WrenchMenuControllerTest
60     : public CocoaProfileTest {
61  public:
62   WrenchMenuControllerTest()
63       : local_device_(new sync_driver::LocalDeviceInfoProviderMock(
64             "WrenchMenuControllerTest",
65             "Test Machine",
66             "Chromium 10k",
67             "Chrome 10k",
68             sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
69             "device_id")) {
70   }
71
72   virtual ~WrenchMenuControllerTest() {}
73
74   virtual void SetUp() override {
75     CocoaProfileTest::SetUp();
76     ASSERT_TRUE(browser());
77
78     controller_.reset([[WrenchMenuController alloc] initWithBrowser:browser()]);
79     fake_model_.reset(new MockWrenchMenuModel);
80
81     manager_.reset(new browser_sync::SessionsSyncManager(
82         profile(),
83         local_device_.get(),
84         scoped_ptr<browser_sync::LocalSessionEventRouter>(
85             new DummyRouter())));
86     manager_->MergeDataAndStartSyncing(
87         syncer::SESSIONS,
88         syncer::SyncDataList(),
89         scoped_ptr<syncer::SyncChangeProcessor>(
90             new syncer::FakeSyncChangeProcessor),
91         scoped_ptr<syncer::SyncErrorFactory>(
92             new syncer::SyncErrorFactoryMock));
93   }
94
95   void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
96     helper->ExportToSessionsSyncManager(manager_.get());
97   }
98
99   browser_sync::OpenTabsUIDelegate* GetOpenTabsDelegate() {
100     return manager_.get();
101   }
102
103   virtual void TearDown() override {
104     fake_model_.reset();
105     controller_.reset();
106     manager_.reset();
107     CocoaProfileTest::TearDown();
108   }
109
110   WrenchMenuController* controller() {
111     return controller_.get();
112   }
113
114   base::scoped_nsobject<WrenchMenuController> controller_;
115
116   scoped_ptr<MockWrenchMenuModel> fake_model_;
117
118  private:
119   scoped_ptr<browser_sync::SessionsSyncManager> manager_;
120   scoped_ptr<sync_driver::LocalDeviceInfoProviderMock> local_device_;
121 };
122
123 TEST_F(WrenchMenuControllerTest, Initialized) {
124   EXPECT_TRUE([controller() menu]);
125   EXPECT_GE([[controller() menu] numberOfItems], 5);
126 }
127
128 TEST_F(WrenchMenuControllerTest, DispatchSimple) {
129   base::scoped_nsobject<NSButton> button([[NSButton alloc] init]);
130   [button setTag:IDC_ZOOM_PLUS];
131
132   // Set fake model to test dispatching.
133   EXPECT_CALL(*fake_model_, ExecuteCommand(IDC_ZOOM_PLUS, 0));
134   [controller() setModel:fake_model_.get()];
135
136   [controller() dispatchWrenchMenuCommand:button.get()];
137   chrome::testing::NSRunLoopRunAllPending();
138 }
139
140 TEST_F(WrenchMenuControllerTest, RecentTabsFavIcon) {
141   RecentTabsBuilderTestHelper recent_tabs_builder;
142   recent_tabs_builder.AddSession();
143   recent_tabs_builder.AddWindow(0);
144   recent_tabs_builder.AddTab(0, 0);
145   RegisterRecentTabs(&recent_tabs_builder);
146
147   RecentTabsSubMenuModel recent_tabs_sub_menu_model(
148       NULL, browser(), GetOpenTabsDelegate());
149   fake_model_->AddSubMenuWithStringId(
150       IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
151       &recent_tabs_sub_menu_model);
152
153   [controller() setModel:fake_model_.get()];
154   NSMenu* menu = [controller() menu];
155   [controller() updateRecentTabsSubmenu];
156
157   NSString* title = l10n_util::GetNSStringWithFixup(IDS_RECENT_TABS_MENU);
158   NSMenu* recent_tabs_menu = [[menu itemWithTitle:title] submenu];
159   EXPECT_TRUE(recent_tabs_menu);
160   EXPECT_EQ(6, [recent_tabs_menu numberOfItems]);
161
162   // Send a icon changed event and verify that the icon is updated.
163   gfx::Image icon(ResourceBundle::GetSharedInstance().GetNativeImageNamed(
164       IDR_BOOKMARKS_FAVICON));
165   recent_tabs_sub_menu_model.SetIcon(3, icon);
166   EXPECT_NSNE(icon.ToNSImage(), [[recent_tabs_menu itemAtIndex:3] image]);
167   recent_tabs_sub_menu_model.GetMenuModelDelegate()->OnIconChanged(3);
168   EXPECT_TRUE([[recent_tabs_menu itemAtIndex:3] image]);
169   EXPECT_NSEQ(icon.ToNSImage(), [[recent_tabs_menu itemAtIndex:3] image]);
170
171   controller_.reset();
172   fake_model_.reset();
173 }
174
175 TEST_F(WrenchMenuControllerTest, RecentTabsElideTitle) {
176   // Add 1 session with 1 window and 2 tabs.
177   RecentTabsBuilderTestHelper recent_tabs_builder;
178   recent_tabs_builder.AddSession();
179   recent_tabs_builder.AddWindow(0);
180   base::string16 tab1_short_title = base::ASCIIToUTF16("Short");
181   recent_tabs_builder.AddTabWithInfo(0, 0, base::Time::Now(), tab1_short_title);
182   base::string16 tab2_long_title = base::ASCIIToUTF16(
183       "Very very very very very very very very very very very very long");
184   recent_tabs_builder.AddTabWithInfo(0, 0,
185       base::Time::Now() - base::TimeDelta::FromMinutes(10), tab2_long_title);
186   RegisterRecentTabs(&recent_tabs_builder);
187
188   RecentTabsSubMenuModel recent_tabs_sub_menu_model(
189       NULL, browser(), GetOpenTabsDelegate());
190   fake_model_->AddSubMenuWithStringId(
191       IDC_RECENT_TABS_MENU, IDS_RECENT_TABS_MENU,
192       &recent_tabs_sub_menu_model);
193
194   [controller() setModel:fake_model_.get()];
195   NSMenu* menu = [controller() menu];
196   [controller() updateRecentTabsSubmenu];
197
198   NSString* title = l10n_util::GetNSStringWithFixup(IDS_RECENT_TABS_MENU);
199   NSMenu* recent_tabs_menu = [[menu itemWithTitle:title] submenu];
200   EXPECT_TRUE(recent_tabs_menu);
201   EXPECT_EQ(7, [recent_tabs_menu numberOfItems]);
202
203   // Index 0: restore tabs menu item.
204   NSString* restore_tab_label = l10n_util::FixUpWindowsStyleLabel(
205       recent_tabs_sub_menu_model.GetLabelAt(0));
206   EXPECT_NSEQ(restore_tab_label, [[recent_tabs_menu itemAtIndex:0] title]);
207
208   // Item 1: separator.
209   EXPECT_TRUE([[recent_tabs_menu itemAtIndex:1] isSeparatorItem]);
210
211   // Item 2: window title.
212   EXPECT_NSEQ(
213       base::SysUTF16ToNSString(recent_tabs_sub_menu_model.GetLabelAt(2)),
214       [[recent_tabs_menu itemAtIndex:2] title]);
215
216   // Item 3: short tab title.
217   EXPECT_NSEQ(base::SysUTF16ToNSString(tab1_short_title),
218               [[recent_tabs_menu itemAtIndex:3] title]);
219
220   // Item 4: long tab title.
221   NSString* tab2_actual_title = [[recent_tabs_menu itemAtIndex:4] title];
222   NSUInteger title_length = [tab2_actual_title length];
223   EXPECT_GT(tab2_long_title.size(), title_length);
224   NSString* actual_substring =
225       [tab2_actual_title substringToIndex:title_length - 1];
226   NSString* expected_substring = [base::SysUTF16ToNSString(tab2_long_title)
227       substringToIndex:title_length - 1];
228   EXPECT_NSEQ(expected_substring, actual_substring);
229
230   controller_.reset();
231   fake_model_.reset();
232 }
233
234 // Verify that |RecentTabsMenuModelDelegate| is deleted before the model
235 // it's observing.
236 TEST_F(WrenchMenuControllerTest, RecentTabDeleteOrder) {
237   [controller_ menuNeedsUpdate:[controller_ menu]];
238   // If the delete order is wrong then the test will crash on exit.
239 }
240
241 }  // namespace