| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/hover_button.h" |
| |
| #include <memory> |
| |
| #include "base/stl_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "chrome/test/views/chrome_views_test_base.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/accessibility/ax_node_data.h" |
| #include "ui/gfx/text_utils.h" |
| #include "ui/views/controls/button/button.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/test/views_test_base.h" |
| #include "ui/views/view.h" |
| |
| namespace { |
| |
| constexpr int kButtonWidth = 150; |
| |
| struct TitleSubtitlePair { |
| const char* const title; |
| const char* const subtitle; |
| // Whether the HoverButton is expected to have a tooltip for this text. |
| bool tooltip; |
| }; |
| |
| constexpr TitleSubtitlePair kTitleSubtitlePairs[] = { |
| // Two short strings that will fit in the space given. |
| {"Clap!", "Clap!", false}, |
| // First string fits, second string doesn't. |
| {"If you're happy and you know it, clap your hands!", "Clap clap!", true}, |
| // Second string fits, first string doesn't. |
| {"Clap clap!", |
| "If you're happy and you know it, and you really want to show it,", true}, |
| // Both strings don't fit. |
| {"If you're happy and you know it, and you really want to show it,", |
| "If you're happy and you know it, clap your hands!", true}, |
| }; |
| |
| class HoverButtonTest : public ChromeViewsTestBase { |
| public: |
| HoverButtonTest() {} |
| |
| std::unique_ptr<views::View> CreateIcon() { |
| auto icon = std::make_unique<views::View>(); |
| icon->SetPreferredSize(gfx::Size(16, 16)); |
| return icon; |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(HoverButtonTest); |
| }; |
| |
| } // namespace |
| |
| // Double check the length of the strings used for testing are either over or |
| // under the width used for the following tests. |
| TEST_F(HoverButtonTest, ValidateTestData) { |
| auto get_width = [](const char* text) { |
| return views::Label(base::ASCIIToUTF16(text)).GetPreferredSize().width(); |
| }; |
| EXPECT_GT(kButtonWidth, get_width(kTitleSubtitlePairs[0].title)); |
| EXPECT_GT(kButtonWidth, get_width(kTitleSubtitlePairs[0].subtitle)); |
| |
| EXPECT_LT(kButtonWidth, get_width(kTitleSubtitlePairs[1].title)); |
| EXPECT_GT(kButtonWidth, get_width(kTitleSubtitlePairs[1].subtitle)); |
| |
| EXPECT_GT(kButtonWidth, get_width(kTitleSubtitlePairs[2].title)); |
| EXPECT_LT(kButtonWidth, get_width(kTitleSubtitlePairs[2].subtitle)); |
| |
| EXPECT_LT(kButtonWidth, get_width(kTitleSubtitlePairs[3].title)); |
| EXPECT_LT(kButtonWidth, get_width(kTitleSubtitlePairs[3].subtitle)); |
| } |
| |
| // Tests whether the HoverButton has the correct tooltip and accessible name. |
| TEST_F(HoverButtonTest, TooltipAndAccessibleName) { |
| for (size_t i = 0; i < base::size(kTitleSubtitlePairs); ++i) { |
| TitleSubtitlePair pair = kTitleSubtitlePairs[i]; |
| SCOPED_TRACE(testing::Message() << "Index: " << i << ", expected_tooltip=" |
| << (pair.tooltip ? "true" : "false")); |
| auto button = std::make_unique<HoverButton>( |
| nullptr, CreateIcon(), base::ASCIIToUTF16(pair.title), |
| base::ASCIIToUTF16(pair.subtitle)); |
| button->SetSize(gfx::Size(kButtonWidth, 40)); |
| |
| ui::AXNodeData data; |
| button->GetAccessibleNodeData(&data); |
| std::string accessible_name; |
| data.GetStringAttribute(ax::mojom::StringAttribute::kName, |
| &accessible_name); |
| |
| // The accessible name should always be the title and subtitle concatenated |
| // by \n. |
| base::string16 expected = base::JoinString( |
| {base::ASCIIToUTF16(pair.title), base::ASCIIToUTF16(pair.subtitle)}, |
| base::ASCIIToUTF16("\n")); |
| EXPECT_EQ(expected, base::UTF8ToUTF16(accessible_name)); |
| |
| base::string16 tooltip_text; |
| button->GetTooltipText(gfx::Point(), &tooltip_text); |
| if (pair.tooltip) { |
| EXPECT_EQ(expected, tooltip_text); |
| } else { |
| EXPECT_EQ(base::string16(), tooltip_text); |
| } |
| } |
| } |
| |
| // Tests that setting a custom tooltip on a HoverButton will not be overwritten |
| // by HoverButton's own tooltips. |
| TEST_F(HoverButtonTest, CustomTooltip) { |
| const base::string16 custom_tooltip = base::ASCIIToUTF16("custom"); |
| |
| for (size_t i = 0; i < base::size(kTitleSubtitlePairs); ++i) { |
| SCOPED_TRACE(testing::Message() << "Index: " << i); |
| TitleSubtitlePair pair = kTitleSubtitlePairs[i]; |
| auto button = std::make_unique<HoverButton>( |
| nullptr, CreateIcon(), base::ASCIIToUTF16(pair.title), |
| base::ASCIIToUTF16(pair.subtitle)); |
| button->set_auto_compute_tooltip(false); |
| button->SetTooltipText(custom_tooltip); |
| button->SetSize(gfx::Size(kButtonWidth, 40)); |
| |
| base::string16 tooltip_text; |
| button->GetTooltipText(gfx::Point(), &tooltip_text); |
| EXPECT_EQ(custom_tooltip, tooltip_text); |
| |
| // Make sure the accessible name is still set. |
| ui::AXNodeData data; |
| button->GetAccessibleNodeData(&data); |
| std::string accessible_name; |
| data.GetStringAttribute(ax::mojom::StringAttribute::kName, |
| &accessible_name); |
| |
| // The accessible name should always be the title and subtitle concatenated |
| // by \n. |
| base::string16 expected = base::JoinString( |
| {base::ASCIIToUTF16(pair.title), base::ASCIIToUTF16(pair.subtitle)}, |
| base::ASCIIToUTF16("\n")); |
| EXPECT_EQ(expected, base::UTF8ToUTF16(accessible_name)); |
| } |
| } |
| |
| // Tests that setting the style and the subtitle elide behavior don't lead to a |
| // crash for a HoverButton with an empty subtitle. |
| TEST_F(HoverButtonTest, SetStyleAndSubtitleElideBehavior) { |
| HoverButton button(nullptr, CreateIcon(), base::ASCIIToUTF16("Test title"), |
| base::string16()); |
| button.SetStyle(HoverButton::STYLE_PROMINENT); |
| button.SetSubtitleElideBehavior(gfx::ELIDE_EMAIL); |
| } |
| |
| // Tests that a button with a subtitle and icons can be instantiated without a |
| // crash. |
| TEST_F(HoverButtonTest, CreateButtonWithSubtitleAndIcons) { |
| std::unique_ptr<views::View> primary_icon = CreateIcon(); |
| views::View* primary_icon_raw = primary_icon.get(); |
| std::unique_ptr<views::View> secondary_icon = CreateIcon(); |
| views::View* secondary_icon_raw = secondary_icon.get(); |
| |
| HoverButton button(nullptr, std::move(primary_icon), |
| base::ASCIIToUTF16("Title"), |
| base::ASCIIToUTF16("Subtitle"), std::move(secondary_icon)); |
| EXPECT_TRUE(button.Contains(primary_icon_raw)); |
| EXPECT_TRUE(button.Contains(secondary_icon_raw)); |
| } |