Rename vector icon header files.
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / toolbar_actions_bar_unittest.cc
blob18fab964cf583a575acbc63d9f0b22d633f117a0
1 // Copyright 2014 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 "chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.h"
7 #include "base/command_line.h"
8 #include "base/run_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
12 #include "chrome/browser/extensions/extension_action.h"
13 #include "chrome/browser/extensions/extension_action_manager.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/test_extension_system.h"
16 #include "chrome/browser/sessions/session_tab_helper.h"
17 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
20 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
21 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h"
22 #include "chrome/common/pref_names.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/extension.h"
27 namespace {
29 // Verifies that the toolbar order matches for the given |actions_bar|. If the
30 // order matches, the return value is empty; otherwise, it contains the error.
31 std::string VerifyToolbarOrderForBar(
32 const ToolbarActionsBar* actions_bar,
33 BrowserActionTestUtil* browser_action_test_util,
34 const char* expected_names[],
35 size_t total_size,
36 size_t visible_count) {
37 const std::vector<ToolbarActionViewController*>& toolbar_actions =
38 actions_bar->toolbar_actions_unordered();
39 // If the total size is wrong, we risk segfaulting by continuing. Abort now.
40 if (total_size != toolbar_actions.size()) {
41 return base::StringPrintf("Incorrect action count: expected %d, found %d",
42 static_cast<int>(total_size),
43 static_cast<int>(toolbar_actions.size()));
46 // Check that the ToolbarActionsBar matches the expected state.
47 std::string error;
48 for (size_t i = 0; i < total_size; ++i) {
49 if (std::string(expected_names[i]) !=
50 base::UTF16ToUTF8(toolbar_actions[i]->GetActionName())) {
51 error += base::StringPrintf(
52 "Incorrect action in bar at index %d: expected '%s', found '%s'.\n",
53 static_cast<int>(i),
54 expected_names[i],
55 base::UTF16ToUTF8(toolbar_actions[i]->GetActionName()).c_str());
58 size_t icon_count = actions_bar->GetIconCount();
59 if (visible_count != icon_count)
60 error += base::StringPrintf(
61 "Incorrect visible count: expected %d, found %d.\n",
62 static_cast<int>(visible_count), static_cast<int>(icon_count));
64 // Test that the (platform-specific) toolbar view matches the expected state.
65 for (size_t i = 0; i < total_size; ++i) {
66 std::string id = browser_action_test_util->GetExtensionId(i);
67 if (id != toolbar_actions[i]->GetId()) {
68 error += base::StringPrintf(
69 "Incorrect action in view at index %d: expected '%s', found '%s'.\n",
70 static_cast<int>(i),
71 toolbar_actions[i]->GetId().c_str(),
72 id.c_str());
75 size_t view_icon_count = browser_action_test_util->VisibleBrowserActions();
76 if (visible_count != view_icon_count)
77 error += base::StringPrintf(
78 "Incorrect visible count in view: expected %d, found %d.\n",
79 static_cast<int>(visible_count), static_cast<int>(view_icon_count));
81 return error;
84 } // namespace
86 ToolbarActionsBarUnitTest::ToolbarActionsBarUnitTest()
87 : toolbar_model_(nullptr),
88 use_redesign_(false) {}
90 ToolbarActionsBarUnitTest::ToolbarActionsBarUnitTest(bool use_redesign)
91 : toolbar_model_(nullptr),
92 use_redesign_(use_redesign) {}
94 ToolbarActionsBarUnitTest::~ToolbarActionsBarUnitTest() {}
96 void ToolbarActionsBarUnitTest::SetUp() {
97 if (use_redesign_) {
98 redesign_switch_.reset(new extensions::FeatureSwitch::ScopedOverride(
99 extensions::FeatureSwitch::extension_action_redesign(), true));
102 BrowserWithTestWindowTest::SetUp();
103 // The toolbar typically displays extension icons, so create some extension
104 // test infrastructure.
105 extensions::TestExtensionSystem* extension_system =
106 static_cast<extensions::TestExtensionSystem*>(
107 extensions::ExtensionSystem::Get(profile()));
108 extension_system->CreateExtensionService(
109 base::CommandLine::ForCurrentProcess(),
110 base::FilePath(),
111 false);
112 toolbar_model_ =
113 extensions::extension_action_test_util::CreateToolbarModelForProfile(
114 profile());
116 ToolbarActionsBar::disable_animations_for_testing_ = true;
117 ToolbarActionsBar::set_send_overflowed_action_changes_for_testing(false);
118 browser_action_test_util_.reset(new BrowserActionTestUtil(browser(), false));
120 if (use_redesign_) {
121 overflow_browser_action_test_util_ =
122 browser_action_test_util_->CreateOverflowBar();
126 void ToolbarActionsBarUnitTest::TearDown() {
127 // Since the profile gets destroyed in BrowserWithTestWindowTest::TearDown(),
128 // we need to delete this now.
129 browser_action_test_util_.reset();
130 overflow_browser_action_test_util_.reset();
131 ToolbarActionsBar::disable_animations_for_testing_ = false;
132 redesign_switch_.reset();
133 BrowserWithTestWindowTest::TearDown();
136 void ToolbarActionsBarUnitTest::ActivateTab(int index) {
137 ASSERT_NE(nullptr, browser()->tab_strip_model()->GetWebContentsAt(index));
138 browser()->tab_strip_model()->ActivateTabAt(index, true);
141 scoped_refptr<const extensions::Extension>
142 ToolbarActionsBarUnitTest::CreateAndAddExtension(
143 const std::string& name,
144 extensions::extension_action_test_util::ActionType action_type) {
145 scoped_refptr<const extensions::Extension> extension =
146 extensions::extension_action_test_util::CreateActionExtension(
147 name, action_type);
148 extensions::ExtensionSystem::Get(profile())->extension_service()->
149 AddExtension(extension.get());
150 return extension;
153 void ToolbarActionsBarUnitTest::SetActionWantsToRunOnTab(
154 ExtensionAction* action,
155 content::WebContents* web_contents,
156 bool wants_to_run) {
157 action->SetIsVisible(SessionTabHelper::IdForTab(web_contents), wants_to_run);
158 extensions::ExtensionActionAPI::Get(profile())->NotifyChange(
159 action, web_contents, profile());
162 testing::AssertionResult ToolbarActionsBarUnitTest::VerifyToolbarOrder(
163 const char* expected_names[],
164 size_t total_size,
165 size_t visible_count) {
166 std::string main_bar_error =
167 VerifyToolbarOrderForBar(toolbar_actions_bar(),
168 browser_action_test_util(),
169 expected_names,
170 total_size,
171 visible_count);
172 std::string overflow_bar_error;
173 if (use_redesign_) {
174 overflow_bar_error =
175 VerifyToolbarOrderForBar(overflow_bar(),
176 overflow_browser_action_test_util(),
177 expected_names,
178 total_size,
179 total_size - visible_count);
183 return main_bar_error.empty() && overflow_bar_error.empty() ?
184 testing::AssertionSuccess() :
185 testing::AssertionFailure() << "main bar error:\n" << main_bar_error <<
186 "overflow bar error:\n" << overflow_bar_error;
189 ToolbarActionsBarRedesignUnitTest::ToolbarActionsBarRedesignUnitTest()
190 : ToolbarActionsBarUnitTest(true) {}
192 ToolbarActionsBarRedesignUnitTest::~ToolbarActionsBarRedesignUnitTest() {}
194 TEST_F(ToolbarActionsBarUnitTest, BasicToolbarActionsBarTest) {
195 // Add three extensions to the profile; this is the easiest way to have
196 // toolbar actions.
197 for (int i = 0; i < 3; ++i) {
198 CreateAndAddExtension(
199 base::StringPrintf("extension %d", i),
200 extensions::extension_action_test_util::BROWSER_ACTION);
203 const ToolbarActionsBar::PlatformSettings& platform_settings =
204 toolbar_actions_bar()->platform_settings();
206 // By default, all three actions should be visible.
207 EXPECT_EQ(3u, toolbar_actions_bar()->GetIconCount());
208 // Check the widths.
209 int expected_width = 3 * ToolbarActionsBar::IconWidth(true) -
210 platform_settings.item_spacing +
211 platform_settings.left_padding +
212 platform_settings.right_padding;
213 EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width());
214 // Since all icons are showing, the current width should be the max width.
215 int maximum_width = expected_width;
216 EXPECT_EQ(maximum_width, toolbar_actions_bar()->GetMaximumWidth());
217 // The minimum width should be just enough for the chevron to be displayed.
218 int minimum_width = platform_settings.left_padding +
219 platform_settings.right_padding +
220 toolbar_actions_bar()->delegate_for_test()->
221 GetChevronWidth();
222 EXPECT_EQ(minimum_width, toolbar_actions_bar()->GetMinimumWidth());
224 // Test the connection between the ToolbarActionsBar and the model by
225 // adjusting the visible count.
226 toolbar_model()->SetVisibleIconCount(2u);
227 EXPECT_EQ(2u, toolbar_actions_bar()->GetIconCount());
229 // The current width should now be enough for two icons, and the chevron.
230 expected_width = 2 * ToolbarActionsBar::IconWidth(true) -
231 platform_settings.item_spacing +
232 platform_settings.left_padding +
233 platform_settings.right_padding +
234 toolbar_actions_bar()->delegate_for_test()->
235 GetChevronWidth();
236 EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width());
237 // The maximum and minimum widths should have remained constant (since we have
238 // the same number of actions).
239 EXPECT_EQ(maximum_width, toolbar_actions_bar()->GetMaximumWidth());
240 EXPECT_EQ(minimum_width, toolbar_actions_bar()->GetMinimumWidth());
242 // Test drag-and-drop logic.
243 const char kExtension0[] = "extension 0";
244 const char kExtension1[] = "extension 1";
245 const char kExtension2[] = "extension 2";
248 // The order should start as 0, 1, 2.
249 const char* expected_names[] = { kExtension0, kExtension1, kExtension2 };
250 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u));
254 // Drag 0 to be in the second spot; 1, 0, 2, within the same container.
255 toolbar_actions_bar()->OnDragDrop(0, 1, ToolbarActionsBar::DRAG_TO_SAME);
256 const char* expected_names[] = { kExtension1, kExtension0, kExtension2 };
257 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u));
261 // Drag 0 to be in the third spot, in the overflow container.
262 // Order should be 1, 2, 0, and the icon count should reduce by 1.
263 toolbar_actions_bar()->OnDragDrop(
264 1, 2, ToolbarActionsBar::DRAG_TO_OVERFLOW);
265 const char* expected_names[] = { kExtension1, kExtension2, kExtension0 };
266 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u));
267 // The model should also reflect the updated icon count.
268 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
269 // Dragging 2 to the main container should work, even if its spot in the
270 // "list" remains constant.
271 // Order remains 1, 2, 0, but now we have 2 icons visible.
272 toolbar_actions_bar()->OnDragDrop(1, 1, ToolbarActionsBar::DRAG_TO_MAIN);
273 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u));
274 // Similarly, dragging 2 to overflow, with the same "list" spot, should also
275 // work. Order remains 1, 2, 0, but icon count goes back to 1.
276 toolbar_actions_bar()->OnDragDrop(
277 1, 1, ToolbarActionsBar::DRAG_TO_OVERFLOW);
278 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u));
281 // Try resizing the toolbar. Start with the current width (enough for 1 icon).
282 int width = toolbar_actions_bar()->GetPreferredSize().width();
284 // If we try to resize by increasing, without allowing enough room for a new
285 // icon, width, and icon count should stay the same.
286 toolbar_actions_bar()->OnResizeComplete(width + 1);
287 EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width());
288 EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
290 // If we resize by enough to include a new icon, width and icon count should
291 // both increase.
292 width += ToolbarActionsBar::IconWidth(true);
293 toolbar_actions_bar()->OnResizeComplete(width);
294 EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width());
295 EXPECT_EQ(2u, toolbar_actions_bar()->GetIconCount());
297 // If we shrink the bar so that a full icon can't fit, it should resize to
298 // hide that icon.
299 toolbar_actions_bar()->OnResizeComplete(width - 1);
300 width -= ToolbarActionsBar::IconWidth(true);
301 EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width());
302 EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount());
305 TEST_F(ToolbarActionsBarUnitTest, ToolbarActionsReorderOnPrefChange) {
306 for (int i = 0; i < 3; ++i) {
307 CreateAndAddExtension(
308 base::StringPrintf("extension %d", i),
309 extensions::extension_action_test_util::BROWSER_ACTION);
311 EXPECT_EQ(3u, toolbar_actions_bar()->GetIconCount());
312 // Change the value of the toolbar preference.
313 // Test drag-and-drop logic.
314 const char kExtension0[] = "extension 0";
315 const char kExtension1[] = "extension 1";
316 const char kExtension2[] = "extension 2";
318 // The order should start as 0, 1, 2.
319 const char* expected_names[] = { kExtension0, kExtension1, kExtension2 };
320 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
323 std::vector<std::string> new_order;
324 new_order.push_back(toolbar_actions_bar()->toolbar_actions_unordered()[1]->
325 GetId());
326 new_order.push_back(toolbar_actions_bar()->toolbar_actions_unordered()[2]->
327 GetId());
328 extensions::ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order);
331 // The order should now reflect the prefs, and be 1, 2, 0.
332 const char* expected_names[] = { kExtension1, kExtension2, kExtension0 };
333 EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u));
337 TEST_F(ToolbarActionsBarRedesignUnitTest, IconSurfacingBubbleAppearance) {
338 // Without showing anything new, we shouldn't show the bubble, and should
339 // auto-acknowledge it.
340 EXPECT_FALSE(
341 ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
342 profile()));
343 PrefService* prefs = profile()->GetPrefs();
344 EXPECT_TRUE(
345 prefs->GetBoolean(prefs::kToolbarIconSurfacingBubbleAcknowledged));
347 // Clear the pref for testing, and add an extension that wouldn't normally
348 // have an icon. We should now show the bubble.
349 prefs->ClearPref(prefs::kToolbarIconSurfacingBubbleAcknowledged);
350 CreateAndAddExtension("extension",
351 extensions::extension_action_test_util::NO_ACTION);
352 EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
353 profile()));
355 // If the bubble was recently shown, we shouldn't show it again...
356 scoped_ptr<ToolbarActionsBarBubbleDelegate> bubble_delegate(
357 new ExtensionToolbarIconSurfacingBubbleDelegate(profile()));
358 bubble_delegate->OnBubbleShown();
359 bubble_delegate->OnBubbleClosed(
360 ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS);
361 EXPECT_FALSE(
362 ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
363 profile()));
365 // ...But if it was only dismissed, we should show it before too long.
366 base::Time two_days_ago = base::Time::Now() - base::TimeDelta::FromDays(2);
367 prefs->SetInt64(prefs::kToolbarIconSurfacingBubbleLastShowTime,
368 two_days_ago.ToInternalValue());
369 EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
370 profile()));
372 // If it's acknowledged, then it should never show again, and should be
373 // recorded as acknowledged.
374 bubble_delegate->OnBubbleShown();
375 bubble_delegate->OnBubbleClosed(
376 ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE);
377 EXPECT_FALSE(
378 ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
379 profile()));
380 base::Time one_week_ago = base::Time::Now() - base::TimeDelta::FromDays(7);
381 prefs->SetInt64(prefs::kToolbarIconSurfacingBubbleLastShowTime,
382 one_week_ago.ToInternalValue());
383 EXPECT_TRUE(
384 prefs->GetBoolean(prefs::kToolbarIconSurfacingBubbleAcknowledged));
387 // Test the bounds calculation for different indices.
388 TEST_F(ToolbarActionsBarRedesignUnitTest, TestActionFrameBounds) {
389 const int kIconWidth = ToolbarActionsBar::IconWidth(false);
390 const int kIconHeight = ToolbarActionsBar::IconHeight();
391 const int kIconWidthWithPadding = ToolbarActionsBar::IconWidth(true);
392 const int kIconsPerOverflowRow = 3;
393 const int kNumExtensions = 7;
394 const int kSpacing =
395 toolbar_actions_bar()->platform_settings().item_spacing;
397 // Initialization: 7 total extensions, with 3 visible per row in overflow.
398 // Start with all visible on the main bar.
399 for (int i = 0; i < kNumExtensions; ++i) {
400 CreateAndAddExtension(
401 base::StringPrintf("extension %d", i),
402 extensions::extension_action_test_util::BROWSER_ACTION);
404 toolbar_model()->SetVisibleIconCount(kNumExtensions);
405 overflow_bar()->SetOverflowRowWidth(
406 kIconWidthWithPadding * kIconsPerOverflowRow + 3);
407 EXPECT_EQ(kIconsPerOverflowRow,
408 overflow_bar()->platform_settings().icons_per_overflow_menu_row);
410 // Check main bar calculations. Actions should be laid out in a line, so
411 // all on the same (0) y-axis.
412 EXPECT_EQ(gfx::Rect(kSpacing, 0, kIconWidth, kIconHeight),
413 toolbar_actions_bar()->GetFrameForIndex(0));
414 EXPECT_EQ(gfx::Rect(kSpacing + kIconWidthWithPadding, 0, kIconWidth,
415 kIconHeight),
416 toolbar_actions_bar()->GetFrameForIndex(1));
417 EXPECT_EQ(gfx::Rect(kSpacing + kIconWidthWithPadding * (kNumExtensions - 1),
418 0, kIconWidth, kIconHeight),
419 toolbar_actions_bar()->GetFrameForIndex(kNumExtensions - 1));
421 // Check overflow bar calculations.
422 toolbar_model()->SetVisibleIconCount(3);
423 // Any actions that are shown on the main bar should have an empty rect for
424 // the frame.
425 EXPECT_EQ(gfx::Rect(), overflow_bar()->GetFrameForIndex(0));
426 EXPECT_EQ(gfx::Rect(), overflow_bar()->GetFrameForIndex(2));
428 // Other actions should start from their relative index; that is, the first
429 // action shown should be in the first spot's bounds, even though it's the
430 // third action by index.
431 EXPECT_EQ(gfx::Rect(kSpacing, 0, kIconWidth, kIconHeight),
432 overflow_bar()->GetFrameForIndex(3));
433 EXPECT_EQ(gfx::Rect(kSpacing + kIconWidthWithPadding, 0, kIconWidth,
434 kIconHeight),
435 overflow_bar()->GetFrameForIndex(4));
436 EXPECT_EQ(gfx::Rect(kSpacing + kIconWidthWithPadding * 2, 0, kIconWidth,
437 kIconHeight),
438 overflow_bar()->GetFrameForIndex(5));
439 // And the actions should wrap, so that it starts back at the left on a new
440 // row.
441 EXPECT_EQ(gfx::Rect(kSpacing, kIconHeight, kIconWidth, kIconHeight),
442 overflow_bar()->GetFrameForIndex(6));
444 // Check with > 2 rows.
445 toolbar_model()->SetVisibleIconCount(0);
446 EXPECT_EQ(gfx::Rect(kSpacing, 0, kIconWidth, kIconHeight),
447 overflow_bar()->GetFrameForIndex(0));
448 EXPECT_EQ(gfx::Rect(kSpacing, kIconHeight * 2, kIconWidth, kIconHeight),
449 overflow_bar()->GetFrameForIndex(6));