Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/cocoa/history_menu_bridge.h" | 5 #include "chrome/browser/ui/cocoa/history_menu_bridge.h" |
| 6 | 6 |
| 7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <vector> | 10 #include <vector> |
|
Robert Sesek
2016/07/29 21:37:25
#include <initializer_list>
| |
| 11 | 11 |
| 12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
| 13 #include "base/memory/ref_counted_memory.h" | 13 #include "base/memory/ref_counted_memory.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "base/strings/sys_string_conversions.h" | 15 #include "base/strings/sys_string_conversions.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 17 #include "chrome/app/chrome_command_ids.h" | 17 #include "chrome/app/chrome_command_ids.h" |
| 18 #include "chrome/browser/sessions/chrome_tab_restore_service_client.h" | 18 #include "chrome/browser/sessions/chrome_tab_restore_service_client.h" |
| 19 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" | 19 #include "chrome/browser/ui/cocoa/cocoa_profile_test.h" |
| 20 #include "chrome/test/base/testing_profile.h" | 20 #include "chrome/test/base/testing_profile.h" |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 43 MockBridge(Profile* profile) | 43 MockBridge(Profile* profile) |
| 44 : HistoryMenuBridge(profile), | 44 : HistoryMenuBridge(profile), |
| 45 menu_([[NSMenu alloc] initWithTitle:@"History"]) {} | 45 menu_([[NSMenu alloc] initWithTitle:@"History"]) {} |
| 46 | 46 |
| 47 NSMenu* HistoryMenu() override { return menu_.get(); } | 47 NSMenu* HistoryMenu() override { return menu_.get(); } |
| 48 | 48 |
| 49 private: | 49 private: |
| 50 base::scoped_nsobject<NSMenu> menu_; | 50 base::scoped_nsobject<NSMenu> menu_; |
| 51 }; | 51 }; |
| 52 | 52 |
| 53 class TestEntries { | |
|
Sidney San Martín
2016/07/29 20:21:33
This class is longer/nastier than I wanted — if an
| |
| 54 public: | |
| 55 struct Entry { | |
| 56 SessionID::id_type id; | |
| 57 virtual std::unique_ptr<MockTRS::Entry> toTRS() const = 0; | |
|
Robert Sesek
2016/07/29 21:37:25
naming: always use CamelCase for method names, unl
| |
| 58 virtual void test(const MockBridge::HistoryItem&, NSMenuItem*) const = 0; | |
| 59 | |
| 60 void test(const MockBridge::HistoryItem& historyItem) const { | |
| 61 EXPECT_EQ(id, historyItem.session_id); | |
| 62 } | |
| 63 | |
| 64 Entry(SessionID::id_type id_) : id{id_} {} | |
| 65 }; | |
| 66 | |
| 67 struct Tab : public Entry { | |
| 68 std::string url, title; | |
|
Robert Sesek
2016/07/29 21:37:25
Don't declare member variables using comma notatio
| |
| 69 | |
| 70 Tab(SessionID::id_type id_, std::string url_, std::string title_) | |
|
Robert Sesek
2016/07/29 21:37:25
Take std::string arguments as const&, and the argu
Sidney San Martín
2016/07/29 22:02:33
WRT underscores, it's to avoid shadowing the membe
Robert Sesek
2016/08/02 14:39:25
I use a_var or an_var, indirect through the this p
| |
| 71 : Entry{id_}, url{url_}, title{title_} {} | |
| 72 | |
| 73 std::unique_ptr<MockTRS::Tab> toTRSTab() const { | |
| 74 auto tab = base::MakeUnique<MockTRS::Tab>(); | |
| 75 tab->id = id; | |
| 76 tab->current_navigation_index = 0; | |
| 77 tab->navigations.push_back( | |
| 78 sessions::SerializedNavigationEntryTestHelper::CreateNavigation( | |
| 79 url, title)); | |
| 80 return tab; | |
| 81 } | |
| 82 | |
| 83 std::unique_ptr<MockTRS::Entry> toTRS() const override { | |
| 84 return std::unique_ptr<MockTRS::Entry>(toTRSTab()); | |
| 85 } | |
| 86 | |
| 87 void test(const MockBridge::HistoryItem& historyItem, | |
|
Robert Sesek
2016/07/29 21:37:25
naming: unless this is an ObjC method, variables a
| |
| 88 NSMenuItem* menuItem) const override { | |
| 89 Entry::test(historyItem); | |
| 90 EXPECT_NSEQ(base::SysUTF8ToNSString(title), menuItem.title); | |
| 91 } | |
| 92 }; | |
| 93 | |
| 94 struct Window : public Entry { | |
| 95 std::vector<Tab> tabs; | |
| 96 | |
| 97 Window(SessionID::id_type id_, std::vector<Tab> tabs_) | |
| 98 : Entry{id_}, tabs{tabs_} {} | |
| 99 | |
| 100 std::unique_ptr<MockTRS::Entry> toTRS() const override { | |
| 101 auto window = new MockTRS::Window; | |
| 102 window->id = id; | |
| 103 window->tabs.reserve(tabs.size()); | |
| 104 for (const auto& tab : tabs) { | |
| 105 window->tabs.push_back(*tab.toTRSTab()); | |
| 106 } | |
| 107 return std::unique_ptr<MockTRS::Entry>(window); | |
| 108 } | |
| 109 | |
| 110 void test(const MockBridge::HistoryItem& historyItem, | |
| 111 NSMenuItem* menuItem) const override { | |
| 112 Entry::test(historyItem); | |
| 113 NSMenu* submenu = menuItem.submenu; | |
| 114 EXPECT_EQ(tabs.size() + 2, (size_t)submenu.numberOfItems); | |
|
Robert Sesek
2016/07/29 21:37:25
numberOfItems should be NSUInteger and so should b
| |
| 115 EXPECT_TRUE([submenu itemAtIndex:1].isSeparatorItem); | |
| 116 for (size_t i = 0; i < tabs.size(); i++) { | |
| 117 tabs[i].test(*historyItem.tabs[i], [submenu itemAtIndex:i + 2]); | |
| 118 } | |
| 119 } | |
| 120 }; | |
| 121 | |
| 122 private: | |
|
Robert Sesek
2016/07/29 21:37:25
Style does not mix public and private. private alw
Sidney San Martín
2016/07/29 22:02:33
I like that. When I was writing this I thought ent
| |
| 123 std::vector<std::unique_ptr<Entry>> entries_; | |
| 124 | |
| 125 public: | |
| 126 TestEntries(std::initializer_list<Entry*> l) { | |
| 127 entries_.reserve(l.size()); | |
| 128 for (const auto& entry : l) { | |
| 129 entries_.emplace_back(entry); | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void test(MockBridge* bridge) const { | |
| 134 NSMenu* menu = bridge->HistoryMenu(); | |
| 135 ASSERT_EQ(entries_.size(), (size_t)[[menu itemArray] count]); | |
| 136 for (size_t i = 0; i < entries_.size(); i++) { | |
| 137 NSMenuItem* menuItem = [menu itemAtIndex:i]; | |
| 138 MockBridge::HistoryItem* historyItem = | |
| 139 bridge->HistoryItemForMenuItem(menuItem); | |
| 140 EXPECT_TRUE(historyItem); | |
| 141 entries_[i]->test(*historyItem, [menu itemAtIndex:i]); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 MockTRS::Entries toTRS() const { | |
| 146 MockTRS::Entries ret; | |
| 147 for (const auto& entry : entries_) { | |
| 148 ret.push_back(entry->toTRS().release()); | |
| 149 } | |
| 150 return ret; | |
| 151 } | |
| 152 }; | |
| 153 | |
| 53 class HistoryMenuBridgeTest : public CocoaProfileTest { | 154 class HistoryMenuBridgeTest : public CocoaProfileTest { |
| 54 public: | 155 public: |
| 55 void SetUp() override { | 156 void SetUp() override { |
| 56 CocoaProfileTest::SetUp(); | 157 CocoaProfileTest::SetUp(); |
| 57 profile()->CreateFaviconService(); | 158 profile()->CreateFaviconService(); |
| 58 bridge_.reset(new MockBridge(profile())); | 159 bridge_.reset(new MockBridge(profile())); |
| 59 } | 160 } |
| 60 | 161 |
| 61 // We are a friend of HistoryMenuBridge (and have access to | 162 // We are a friend of HistoryMenuBridge (and have access to |
| 62 // protected methods), but none of the classes generated by TEST_F() | 163 // protected methods), but none of the classes generated by TEST_F() |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 89 } | 190 } |
| 90 | 191 |
| 91 HistoryMenuBridge::HistoryItem* CreateItem(const base::string16& title) { | 192 HistoryMenuBridge::HistoryItem* CreateItem(const base::string16& title) { |
| 92 HistoryMenuBridge::HistoryItem* item = | 193 HistoryMenuBridge::HistoryItem* item = |
| 93 new HistoryMenuBridge::HistoryItem(); | 194 new HistoryMenuBridge::HistoryItem(); |
| 94 item->title = title; | 195 item->title = title; |
| 95 item->url = GURL(title); | 196 item->url = GURL(title); |
| 96 return item; | 197 return item; |
| 97 } | 198 } |
| 98 | 199 |
| 99 MockTRS::Tab CreateSessionTab(const std::string& url, | |
| 100 const std::string& title) { | |
| 101 MockTRS::Tab tab; | |
| 102 tab.current_navigation_index = 0; | |
| 103 tab.navigations.push_back( | |
| 104 sessions::SerializedNavigationEntryTestHelper::CreateNavigation( | |
| 105 url, title)); | |
| 106 return tab; | |
| 107 } | |
| 108 | |
| 109 void GetFaviconForHistoryItem(HistoryMenuBridge::HistoryItem* item) { | 200 void GetFaviconForHistoryItem(HistoryMenuBridge::HistoryItem* item) { |
| 110 bridge_->GetFaviconForHistoryItem(item); | 201 bridge_->GetFaviconForHistoryItem(item); |
| 111 } | 202 } |
| 112 | 203 |
| 113 void GotFaviconData(HistoryMenuBridge::HistoryItem* item, | 204 void GotFaviconData(HistoryMenuBridge::HistoryItem* item, |
| 114 const favicon_base::FaviconImageResult& image_result) { | 205 const favicon_base::FaviconImageResult& image_result) { |
| 115 bridge_->GotFaviconData(item, image_result); | 206 bridge_->GotFaviconData(item, image_result); |
| 116 } | 207 } |
| 117 | 208 |
| 118 std::unique_ptr<MockBridge> bridge_; | 209 std::unique_ptr<MockBridge> bridge_; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 206 // Confirm tooltips and confirm they are not trimmed (like the item | 297 // Confirm tooltips and confirm they are not trimmed (like the item |
| 207 // name might be). Add tolerance for URL fixer-upping; | 298 // name might be). Add tolerance for URL fixer-upping; |
| 208 // e.g. http://foo becomes http://foo/) | 299 // e.g. http://foo becomes http://foo/) |
| 209 EXPECT_GE([[[menu itemAtIndex:0] toolTip] length], (2*short_url.length()-5)); | 300 EXPECT_GE([[[menu itemAtIndex:0] toolTip] length], (2*short_url.length()-5)); |
| 210 EXPECT_GE([[[menu itemAtIndex:1] toolTip] length], (2*long_url.length()-5)); | 301 EXPECT_GE([[[menu itemAtIndex:1] toolTip] length], (2*long_url.length()-5)); |
| 211 } | 302 } |
| 212 | 303 |
| 213 // Test that the menu is created for a set of simple tabs. | 304 // Test that the menu is created for a set of simple tabs. |
| 214 TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) { | 305 TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabs) { |
| 215 std::unique_ptr<MockTRS> trs(new MockTRS(profile())); | 306 std::unique_ptr<MockTRS> trs(new MockTRS(profile())); |
| 216 MockTRS::Entries entries; | |
| 217 | 307 |
| 218 MockTRS::Tab tab1 = CreateSessionTab("http://google.com", "Google"); | 308 const TestEntries testEntries{ |
| 219 tab1.id = 24; | 309 new TestEntries::Tab{24, "http://google.com", "Google"}, |
| 220 entries.push_back(&tab1); | 310 new TestEntries::Tab{42, "http://apple.com", "Apple"}, |
| 311 }; | |
| 221 | 312 |
| 222 MockTRS::Tab tab2 = CreateSessionTab("http://apple.com", "Apple"); | 313 auto entries = testEntries.toTRS(); |
| 223 tab2.id = 42; | |
| 224 entries.push_back(&tab2); | |
| 225 | |
| 226 using ::testing::ReturnRef; | 314 using ::testing::ReturnRef; |
| 227 EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries)); | 315 EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries)); |
| 228 | 316 |
| 229 bridge_->TabRestoreServiceChanged(trs.get()); | 317 bridge_->TabRestoreServiceChanged(trs.get()); |
| 230 | 318 testEntries.test(bridge_.get()); |
| 231 NSMenu* menu = bridge_->HistoryMenu(); | |
| 232 ASSERT_EQ(2U, [[menu itemArray] count]); | |
| 233 | |
| 234 NSMenuItem* item1 = [menu itemAtIndex:0]; | |
| 235 MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1); | |
| 236 EXPECT_TRUE(hist1); | |
| 237 EXPECT_EQ(24, hist1->session_id); | |
| 238 EXPECT_NSEQ(@"Google", [item1 title]); | |
| 239 | |
| 240 NSMenuItem* item2 = [menu itemAtIndex:1]; | |
| 241 MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2); | |
| 242 EXPECT_TRUE(hist2); | |
| 243 EXPECT_EQ(42, hist2->session_id); | |
| 244 EXPECT_NSEQ(@"Apple", [item2 title]); | |
| 245 } | 319 } |
| 246 | 320 |
| 247 // Test that the menu is created for a mix of windows and tabs. | 321 // Test that the menu is created for a mix of windows and tabs. |
| 248 TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) { | 322 TEST_F(HistoryMenuBridgeTest, RecentlyClosedTabsAndWindows) { |
| 249 std::unique_ptr<MockTRS> trs(new MockTRS(profile())); | 323 std::unique_ptr<MockTRS> trs(new MockTRS(profile())); |
| 250 MockTRS::Entries entries; | |
| 251 | 324 |
| 252 MockTRS::Tab tab1 = CreateSessionTab("http://google.com", "Google"); | 325 const TestEntries testEntries{ |
| 253 tab1.id = 24; | 326 new TestEntries::Window{30, { |
| 254 entries.push_back(&tab1); | 327 {31, "http://foo.com", "foo"}, |
| 328 {32, "http://bar.com", "bar"}, | |
| 329 }}, | |
| 330 new TestEntries::Tab{42, "http://apple.com", "Apple"}, | |
| 331 new TestEntries::Window{50, { | |
| 332 {51, "http://magic.com", "magic"}, | |
| 333 {52, "http://goats.com", "goats"}, | |
| 334 {53, "http://teleporter.com", "teleporter"}, | |
| 335 }}, | |
| 336 }; | |
| 255 | 337 |
| 256 // TODO(sdy): The tab ids below *must* be set after all of them have been | 338 auto entries = testEntries.toTRS(); |
| 257 // pushed onto window.tabs. Otherwise, the ids will change when push_back | |
| 258 // reallocates the vector's storage and calls each tabs' copy ctor. Ugh. | |
| 259 | |
| 260 MockTRS::Window win1; | |
| 261 win1.id = 30; | |
| 262 win1.tabs.push_back(CreateSessionTab("http://foo.com", "foo")); | |
| 263 win1.tabs.push_back(CreateSessionTab("http://bar.com", "bar")); | |
| 264 win1.tabs[0].id = 31; | |
| 265 win1.tabs[1].id = 32; | |
| 266 entries.push_back(&win1); | |
| 267 | |
| 268 MockTRS::Tab tab2 = CreateSessionTab("http://apple.com", "Apple"); | |
| 269 tab2.id = 42; | |
| 270 entries.push_back(&tab2); | |
| 271 | |
| 272 MockTRS::Window win2; | |
| 273 win2.id = 50; | |
| 274 win2.tabs.push_back(CreateSessionTab("http://magic.com", "magic")); | |
| 275 win2.tabs.push_back(CreateSessionTab("http://goats.com", "goats")); | |
| 276 win2.tabs.push_back(CreateSessionTab("http://teleporter.com", "teleporter")); | |
| 277 win2.tabs[0].id = 51; | |
| 278 win2.tabs[1].id = 52; | |
| 279 win2.tabs[2].id = 53; | |
| 280 entries.push_back(&win2); | |
| 281 | |
| 282 using ::testing::ReturnRef; | 339 using ::testing::ReturnRef; |
| 283 EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries)); | 340 EXPECT_CALL(*trs.get(), entries()).WillOnce(ReturnRef(entries)); |
| 284 | 341 |
| 285 bridge_->TabRestoreServiceChanged(trs.get()); | 342 bridge_->TabRestoreServiceChanged(trs.get()); |
| 286 | 343 testEntries.test(bridge_.get()); |
| 287 NSMenu* menu = bridge_->HistoryMenu(); | |
| 288 ASSERT_EQ(4U, [[menu itemArray] count]); | |
| 289 | |
| 290 NSMenuItem* item1 = [menu itemAtIndex:0]; | |
| 291 MockBridge::HistoryItem* hist1 = bridge_->HistoryItemForMenuItem(item1); | |
| 292 EXPECT_TRUE(hist1); | |
| 293 EXPECT_EQ(24, hist1->session_id); | |
| 294 EXPECT_NSEQ(@"Google", [item1 title]); | |
| 295 | |
| 296 NSMenuItem* item2 = [menu itemAtIndex:1]; | |
| 297 MockBridge::HistoryItem* hist2 = bridge_->HistoryItemForMenuItem(item2); | |
| 298 EXPECT_TRUE(hist2); | |
| 299 EXPECT_EQ(30, hist2->session_id); | |
| 300 EXPECT_EQ(2U, hist2->tabs.size()); | |
| 301 // Do not test menu item title because it is localized. | |
| 302 NSMenu* submenu1 = [item2 submenu]; | |
| 303 EXPECT_EQ(4U, [[submenu1 itemArray] count]); | |
| 304 // Do not test Restore All Tabs because it is localiced. | |
| 305 EXPECT_TRUE([[submenu1 itemAtIndex:1] isSeparatorItem]); | |
| 306 EXPECT_NSEQ(@"foo", [[submenu1 itemAtIndex:2] title]); | |
| 307 EXPECT_NSEQ(@"bar", [[submenu1 itemAtIndex:3] title]); | |
| 308 EXPECT_EQ(31, hist2->tabs[0]->session_id); | |
| 309 EXPECT_EQ(32, hist2->tabs[1]->session_id); | |
| 310 | |
| 311 NSMenuItem* item3 = [menu itemAtIndex:2]; | |
| 312 MockBridge::HistoryItem* hist3 = bridge_->HistoryItemForMenuItem(item3); | |
| 313 EXPECT_TRUE(hist3); | |
| 314 EXPECT_EQ(42, hist3->session_id); | |
| 315 EXPECT_NSEQ(@"Apple", [item3 title]); | |
| 316 | |
| 317 NSMenuItem* item4 = [menu itemAtIndex:3]; | |
| 318 MockBridge::HistoryItem* hist4 = bridge_->HistoryItemForMenuItem(item4); | |
| 319 EXPECT_TRUE(hist4); | |
| 320 EXPECT_EQ(50, hist4->session_id); | |
| 321 EXPECT_EQ(3U, hist4->tabs.size()); | |
| 322 // Do not test menu item title because it is localized. | |
| 323 NSMenu* submenu2 = [item4 submenu]; | |
| 324 EXPECT_EQ(5U, [[submenu2 itemArray] count]); | |
| 325 // Do not test Restore All Tabs because it is localiced. | |
| 326 EXPECT_TRUE([[submenu2 itemAtIndex:1] isSeparatorItem]); | |
| 327 EXPECT_NSEQ(@"magic", [[submenu2 itemAtIndex:2] title]); | |
| 328 EXPECT_NSEQ(@"goats", [[submenu2 itemAtIndex:3] title]); | |
| 329 EXPECT_NSEQ(@"teleporter", [[submenu2 itemAtIndex:4] title]); | |
| 330 EXPECT_EQ(51, hist4->tabs[0]->session_id); | |
| 331 EXPECT_EQ(52, hist4->tabs[1]->session_id); | |
| 332 EXPECT_EQ(53, hist4->tabs[2]->session_id); | |
| 333 } | 344 } |
| 334 | 345 |
| 335 // Tests that we properly request an icon from the FaviconService. | 346 // Tests that we properly request an icon from the FaviconService. |
| 336 TEST_F(HistoryMenuBridgeTest, GetFaviconForHistoryItem) { | 347 TEST_F(HistoryMenuBridgeTest, GetFaviconForHistoryItem) { |
| 337 // Create a fake item. | 348 // Create a fake item. |
| 338 HistoryMenuBridge::HistoryItem item; | 349 HistoryMenuBridge::HistoryItem item; |
| 339 item.title = base::ASCIIToUTF16("Title"); | 350 item.title = base::ASCIIToUTF16("Title"); |
| 340 item.url = GURL("http://google.com"); | 351 item.url = GURL("http://google.com"); |
| 341 | 352 |
| 342 // Request the icon. | 353 // Request the icon. |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 363 image_result.image = gfx::Image::CreateFrom1xBitmap(bitmap); | 374 image_result.image = gfx::Image::CreateFrom1xBitmap(bitmap); |
| 364 GotFaviconData(&item, image_result); | 375 GotFaviconData(&item, image_result); |
| 365 | 376 |
| 366 // Make sure the callback works. | 377 // Make sure the callback works. |
| 367 EXPECT_FALSE(item.icon_requested); | 378 EXPECT_FALSE(item.icon_requested); |
| 368 EXPECT_TRUE(item.icon.get()); | 379 EXPECT_TRUE(item.icon.get()); |
| 369 EXPECT_TRUE([item.menu_item image]); | 380 EXPECT_TRUE([item.menu_item image]); |
| 370 } | 381 } |
| 371 | 382 |
| 372 } // namespace | 383 } // namespace |
| OLD | NEW |