Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / cocoa / bookmarks / bookmark_menu_bridge_unittest.mm
1 // Copyright (c) 2011 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 #import <AppKit/AppKit.h>
6
7 #include "base/strings/string16.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
12 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/bookmarks/browser/bookmark_model.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #import "testing/gtest_mac.h"
18 #include "testing/platform_test.h"
19 #include "ui/base/l10n/l10n_util.h"
20
21 using base::ASCIIToUTF16;
22
23 class TestBookmarkMenuBridge : public BookmarkMenuBridge {
24  public:
25   TestBookmarkMenuBridge(Profile* profile, NSMenu *menu)
26       : BookmarkMenuBridge(profile, menu),
27         menu_(menu) {
28   }
29   virtual ~TestBookmarkMenuBridge() {
30     [menu_ autorelease];
31   }
32
33   NSMenu* menu_;
34
35  protected:
36   // Overridden from BookmarkMenuBridge.
37   virtual NSMenu* BookmarkMenu() OVERRIDE {
38     return menu_;
39   }
40 };
41
42 // TODO(jrg): see refactor comment in bookmark_bar_state_controller_unittest.mm
43 class BookmarkMenuBridgeTest : public CocoaProfileTest {
44  public:
45
46    virtual void SetUp() {
47      CocoaProfileTest::SetUp();
48      ASSERT_TRUE(profile());
49
50      NSMenu* menu = [[NSMenu alloc] initWithTitle:@"test"];
51      bridge_.reset(new TestBookmarkMenuBridge(profile(), menu));
52      EXPECT_TRUE(bridge_.get());
53    }
54
55   // We are a friend of BookmarkMenuBridge (and have access to
56   // protected methods), but none of the classes generated by TEST_F()
57   // are.  This (and AddNodeToMenu()) are simple wrappers to let
58   // derived test classes have access to protected methods.
59   void ClearBookmarkMenu(BookmarkMenuBridge* bridge, NSMenu* menu) {
60     bridge->ClearBookmarkMenu(menu);
61   }
62
63   void InvalidateMenu()  { bridge_->InvalidateMenu(); }
64   bool menu_is_valid()  { return bridge_->menuIsValid_; }
65
66   void AddNodeToMenu(BookmarkMenuBridge* bridge,
67                      const BookmarkNode* root,
68                      NSMenu* menu) {
69     bridge->AddNodeToMenu(root, menu, true);
70   }
71
72   void AddItemToMenu(BookmarkMenuBridge* bridge,
73                      int command_id,
74                      int message_id,
75                      const BookmarkNode* node,
76                      NSMenu* menu,
77                      bool enable) {
78     bridge->AddItemToMenu(command_id, message_id, node, menu, enable);
79   }
80
81   NSMenuItem* MenuItemForNode(BookmarkMenuBridge* bridge,
82                               const BookmarkNode* node) {
83     return bridge->MenuItemForNode(node);
84   }
85
86   NSMenuItem* AddTestMenuItem(NSMenu *menu, NSString *title, SEL selector) {
87     NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:title action:NULL
88                                             keyEquivalent:@""] autorelease];
89     if (selector)
90       [item setAction:selector];
91     [menu addItem:item];
92     return item;
93   }
94   scoped_ptr<TestBookmarkMenuBridge> bridge_;
95 };
96
97 TEST_F(BookmarkMenuBridgeTest, TestBookmarkMenuAutoSeparator) {
98   BookmarkModel* model = bridge_->GetBookmarkModel();
99   bridge_->BookmarkModelLoaded(model, false);
100   NSMenu* menu = bridge_->menu_;
101   bridge_->UpdateMenu(menu);
102   // The bare menu after loading used to have a separator and an
103   // "Other Bookmarks" submenu, but we no longer show those items if the
104   // "Other Bookmarks" submenu would be empty.
105   EXPECT_EQ(0, [menu numberOfItems]);
106   // Add a bookmark and reload and there should be 8 items: the previous
107   // menu contents plus two new separator, the new bookmark and three
108   // versions of 'Open All Bookmarks' menu items.
109   const BookmarkNode* parent = model->bookmark_bar_node();
110   const char* url = "http://www.zim-bop-a-dee.com/";
111   model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
112   bridge_->UpdateMenu(menu);
113   EXPECT_EQ(6, [menu numberOfItems]);
114   // Remove the new bookmark and reload and we should have 2 items again
115   // because the separator should have been removed as well.
116   model->Remove(parent, 0);
117   bridge_->UpdateMenu(menu);
118   EXPECT_EQ(0, [menu numberOfItems]);
119 }
120
121 // Test that ClearBookmarkMenu() removes all bookmark menus.
122 TEST_F(BookmarkMenuBridgeTest, TestClearBookmarkMenu) {
123   NSMenu* menu = bridge_->menu_;
124
125   AddTestMenuItem(menu, @"hi mom", nil);
126   AddTestMenuItem(menu, @"not", @selector(openBookmarkMenuItem:));
127   NSMenuItem* item = AddTestMenuItem(menu, @"hi mom", nil);
128   [item setSubmenu:[[[NSMenu alloc] initWithTitle:@"bar"] autorelease]];
129   AddTestMenuItem(menu, @"not", @selector(openBookmarkMenuItem:));
130   AddTestMenuItem(menu, @"zippy", @selector(length));
131   [menu addItem:[NSMenuItem separatorItem]];
132
133   ClearBookmarkMenu(bridge_.get(), menu);
134
135   // Make sure all bookmark items are removed, all items with
136   // submenus removed, and all separator items are gone.
137   EXPECT_EQ(2, [menu numberOfItems]);
138   for (NSMenuItem *item in [menu itemArray]) {
139     EXPECT_NSNE(@"not", [item title]);
140   }
141 }
142
143 // Test invalidation
144 TEST_F(BookmarkMenuBridgeTest, TestInvalidation) {
145   BookmarkModel* model = bridge_->GetBookmarkModel();
146   bridge_->BookmarkModelLoaded(model, false);
147
148   EXPECT_FALSE(menu_is_valid());
149   bridge_->UpdateMenu(bridge_->menu_);
150   EXPECT_TRUE(menu_is_valid());
151
152   InvalidateMenu();
153   EXPECT_FALSE(menu_is_valid());
154   InvalidateMenu();
155   EXPECT_FALSE(menu_is_valid());
156   bridge_->UpdateMenu(bridge_->menu_);
157   EXPECT_TRUE(menu_is_valid());
158   bridge_->UpdateMenu(bridge_->menu_);
159   EXPECT_TRUE(menu_is_valid());
160
161   const BookmarkNode* parent = model->bookmark_bar_node();
162   const char* url = "http://www.zim-bop-a-dee.com/";
163   model->AddURL(parent, 0, ASCIIToUTF16("Bookmark"), GURL(url));
164
165   EXPECT_FALSE(menu_is_valid());
166   bridge_->UpdateMenu(bridge_->menu_);
167   EXPECT_TRUE(menu_is_valid());
168 }
169
170 // Test that AddNodeToMenu() properly adds bookmark nodes as menus,
171 // including the recursive case.
172 TEST_F(BookmarkMenuBridgeTest, TestAddNodeToMenu) {
173   base::string16 empty;
174   NSMenu* menu = bridge_->menu_;
175
176   BookmarkModel* model = bridge_->GetBookmarkModel();
177   const BookmarkNode* root = model->bookmark_bar_node();
178   EXPECT_TRUE(model && root);
179
180   const char* short_url = "http://foo/";
181   const char* long_url = "http://super-duper-long-url--."
182     "that.cannot.possibly.fit.even-in-80-columns"
183     "or.be.reasonably-displayed-in-a-menu"
184     "without.looking-ridiculous.com/"; // 140 chars total
185
186   // 3 nodes; middle one has a child, last one has a HUGE URL
187   // Set their titles to be the same as the URLs
188   const BookmarkNode* node = NULL;
189   model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
190   bridge_->UpdateMenu(menu);
191   int prev_count = [menu numberOfItems] - 1; // "extras" added at this point
192   node = model->AddFolder(root, 1, empty);
193   model->AddURL(root, 2, ASCIIToUTF16(long_url), GURL(long_url));
194
195   // And the submenu fo the middle one
196   model->AddURL(node, 0, empty, GURL("http://sub"));
197   bridge_->UpdateMenu(menu);
198
199   EXPECT_EQ((NSInteger)(prev_count+3), [menu numberOfItems]);
200
201   // Verify the 1st one is there with the right action.
202   NSMenuItem* item = [menu itemWithTitle:[NSString
203                                            stringWithUTF8String:short_url]];
204   EXPECT_TRUE(item);
205   EXPECT_EQ(@selector(openBookmarkMenuItem:), [item action]);
206   EXPECT_EQ(NO, [item hasSubmenu]);
207   NSMenuItem* short_item = item;
208   NSMenuItem* long_item = nil;
209
210   // Now confirm we have 1 submenu (the one we added, and not "other")
211   int subs = 0;
212   for (item in [menu itemArray]) {
213     if ([item hasSubmenu])
214       subs++;
215   }
216   EXPECT_EQ(1, subs);
217
218   for (item in [menu itemArray]) {
219     if ([[item title] hasPrefix:@"http://super-duper"]) {
220       long_item = item;
221       break;
222     }
223   }
224   EXPECT_TRUE(long_item);
225
226   // Make sure a short title looks fine
227   NSString* s = [short_item title];
228   EXPECT_NSEQ([NSString stringWithUTF8String:short_url], s);
229
230   // Make sure a super-long title gets trimmed
231   s = [long_item title];
232   EXPECT_TRUE([s length] < strlen(long_url));
233
234   // Confirm tooltips and confirm they are not trimmed (like the item
235   // name might be).  Add tolerance for URL fixer-upping;
236   // e.g. http://foo becomes http://foo/)
237   EXPECT_GE([[short_item toolTip] length], strlen(short_url) - 3);
238   EXPECT_GE([[long_item toolTip] length], strlen(long_url) - 3);
239
240   // Make sure the favicon is non-nil (should be either the default site
241   // icon or a favicon, if present).
242   EXPECT_TRUE([short_item image]);
243   EXPECT_TRUE([long_item image]);
244 }
245
246 // Test that AddItemToMenu() properly added versions of
247 // 'Open All Bookmarks' as menu items.
248 TEST_F(BookmarkMenuBridgeTest, TestAddItemToMenu) {
249   NSString* title;
250   NSMenuItem* item;
251   NSMenu* menu = bridge_->menu_;
252
253   BookmarkModel* model = bridge_->GetBookmarkModel();
254   const BookmarkNode* root = model->bookmark_bar_node();
255   EXPECT_TRUE(model && root);
256   EXPECT_EQ(0, [menu numberOfItems]);
257
258   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL,
259                 IDS_BOOKMARK_BAR_OPEN_ALL, root, menu, true);
260   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
261                 IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW, root, menu, true);
262   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
263                 IDS_BOOKMARK_BAR_OPEN_INCOGNITO, root, menu, true);
264   EXPECT_EQ(3, [menu numberOfItems]);
265
266   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_ALL);
267   item = [menu itemWithTitle:title];
268   EXPECT_TRUE(item);
269   EXPECT_EQ(@selector(openAllBookmarks:), [item action]);
270   EXPECT_TRUE([item isEnabled]);
271
272   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW);
273   item = [menu itemWithTitle:title];
274   EXPECT_TRUE(item);
275   EXPECT_EQ(@selector(openAllBookmarksNewWindow:), [item action]);
276   EXPECT_TRUE([item isEnabled]);
277
278   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_INCOGNITO);
279   item = [menu itemWithTitle:title];
280   EXPECT_TRUE(item);
281   EXPECT_EQ(@selector(openAllBookmarksIncognitoWindow:), [item action]);
282   EXPECT_TRUE([item isEnabled]);
283
284   ClearBookmarkMenu(bridge_.get(), menu);
285   EXPECT_EQ(0, [menu numberOfItems]);
286
287   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL,
288                 IDS_BOOKMARK_BAR_OPEN_ALL, root, menu, false);
289   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW,
290                 IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW, root, menu, false);
291   AddItemToMenu(bridge_.get(), IDC_BOOKMARK_BAR_OPEN_ALL_INCOGNITO,
292                 IDS_BOOKMARK_BAR_OPEN_INCOGNITO, root, menu, false);
293   EXPECT_EQ(3, [menu numberOfItems]);
294
295   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_ALL);
296   item = [menu itemWithTitle:title];
297   EXPECT_TRUE(item);
298   EXPECT_EQ(nil, [item action]);
299   EXPECT_FALSE([item isEnabled]);
300
301   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_ALL_NEW_WINDOW);
302   item = [menu itemWithTitle:title];
303   EXPECT_TRUE(item);
304   EXPECT_EQ(nil, [item action]);
305   EXPECT_FALSE([item isEnabled]);
306
307   title = l10n_util::GetNSStringWithFixup(IDS_BOOKMARK_BAR_OPEN_INCOGNITO);
308   item = [menu itemWithTitle:title];
309   EXPECT_TRUE(item);
310   EXPECT_EQ(nil, [item action]);
311   EXPECT_FALSE([item isEnabled]);
312 }
313
314 // Makes sure our internal map of BookmarkNode to NSMenuItem works.
315 TEST_F(BookmarkMenuBridgeTest, TestGetMenuItemForNode) {
316   base::string16 empty;
317   NSMenu* menu = bridge_->menu_;
318
319   BookmarkModel* model = bridge_->GetBookmarkModel();
320   const BookmarkNode* bookmark_bar = model->bookmark_bar_node();
321   const BookmarkNode* root = model->AddFolder(bookmark_bar, 0, empty);
322   EXPECT_TRUE(model && root);
323
324   model->AddURL(root, 0, ASCIIToUTF16("Test Item"), GURL("http://test"));
325   AddNodeToMenu(bridge_.get(), root, menu);
326   EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
327
328   model->AddURL(root, 1, ASCIIToUTF16("Test 2"), GURL("http://second-test"));
329   AddNodeToMenu(bridge_.get(), root, menu);
330   EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
331   EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(1)));
332
333   const BookmarkNode* removed_node = root->GetChild(0);
334   EXPECT_EQ(2, root->child_count());
335   model->Remove(root, 0);
336   EXPECT_EQ(1, root->child_count());
337   bridge_->UpdateMenu(menu);
338   EXPECT_FALSE(MenuItemForNode(bridge_.get(), removed_node));
339   EXPECT_TRUE(MenuItemForNode(bridge_.get(), root->GetChild(0)));
340
341   const BookmarkNode empty_node(GURL("http://no-where/"));
342   EXPECT_FALSE(MenuItemForNode(bridge_.get(), &empty_node));
343   EXPECT_FALSE(MenuItemForNode(bridge_.get(), NULL));
344 }
345
346 // Test that Loaded() adds both the bookmark bar nodes and the "other" nodes.
347 TEST_F(BookmarkMenuBridgeTest, TestAddNodeToOther) {
348   NSMenu* menu = bridge_->menu_;
349
350   BookmarkModel* model = bridge_->GetBookmarkModel();
351   const BookmarkNode* root = model->other_node();
352   EXPECT_TRUE(model && root);
353
354   const char* short_url = "http://foo/";
355   model->AddURL(root, 0, ASCIIToUTF16(short_url), GURL(short_url));
356
357   bridge_->UpdateMenu(menu);
358   ASSERT_GT([menu numberOfItems], 0);
359   NSMenuItem* other = [menu itemAtIndex:([menu numberOfItems]-1)];
360   EXPECT_TRUE(other);
361   EXPECT_TRUE([other hasSubmenu]);
362   ASSERT_GT([[other submenu] numberOfItems], 0);
363   EXPECT_NSEQ(@"http://foo/", [[[other submenu] itemAtIndex:0] title]);
364 }
365
366 TEST_F(BookmarkMenuBridgeTest, TestFaviconLoading) {
367   NSMenu* menu = bridge_->menu_;
368
369   BookmarkModel* model = bridge_->GetBookmarkModel();
370   const BookmarkNode* root = model->bookmark_bar_node();
371   EXPECT_TRUE(model && root);
372
373   const BookmarkNode* node =
374       model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
375                     GURL("http://favicon-test"));
376   bridge_->UpdateMenu(menu);
377   NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
378   EXPECT_TRUE([item image]);
379   [item setImage:nil];
380   bridge_->BookmarkNodeFaviconChanged(model, node);
381   EXPECT_TRUE([item image]);
382 }
383
384 TEST_F(BookmarkMenuBridgeTest, TestChangeTitle) {
385   NSMenu* menu = bridge_->menu_;
386   BookmarkModel* model = bridge_->GetBookmarkModel();
387   const BookmarkNode* root = model->bookmark_bar_node();
388   EXPECT_TRUE(model && root);
389
390   const BookmarkNode* node =
391       model->AddURL(root, 0, ASCIIToUTF16("Test Item"),
392                     GURL("http://title-test"));
393   bridge_->UpdateMenu(menu);
394   NSMenuItem* item = [menu itemWithTitle:@"Test Item"];
395   EXPECT_TRUE([item image]);
396
397   model->SetTitle(node, ASCIIToUTF16("New Title"));
398
399   item = [menu itemWithTitle:@"Test Item"];
400   EXPECT_FALSE(item);
401   item = [menu itemWithTitle:@"New Title"];
402   EXPECT_TRUE(item);
403 }
404