styled_label_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright 2013 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 <string> 6 7#include "base/basictypes.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/utf_string_conversions.h" 10#include "testing/gtest/include/gtest/gtest.h" 11#include "ui/views/controls/link.h" 12#include "ui/views/controls/styled_label.h" 13#include "ui/views/controls/styled_label_listener.h" 14 15namespace views { 16 17class StyledLabelTest : public testing::Test, public StyledLabelListener { 18 public: 19 StyledLabelTest() {} 20 virtual ~StyledLabelTest() {} 21 22 // StyledLabelListener implementation. 23 virtual void StyledLabelLinkClicked(const ui::Range& range, 24 int event_flags) OVERRIDE {} 25 26 protected: 27 StyledLabel* styled() { return styled_.get(); } 28 29 void InitStyledLabel(const std::string& ascii_text) { 30 styled_.reset(new StyledLabel(ASCIIToUTF16(ascii_text), this)); 31 } 32 33 int StyledLabelContentHeightForWidth(int w) { 34 return styled_->GetHeightForWidth(w) - styled_->GetInsets().height(); 35 } 36 37 private: 38 scoped_ptr<StyledLabel> styled_; 39 40 DISALLOW_COPY_AND_ASSIGN(StyledLabelTest); 41}; 42 43TEST_F(StyledLabelTest, NoWrapping) { 44 const std::string text("This is a test block of text"); 45 InitStyledLabel(text); 46 Label label(ASCIIToUTF16(text)); 47 const gfx::Size label_preferred_size = label.GetPreferredSize(); 48 EXPECT_EQ(label_preferred_size.height(), 49 StyledLabelContentHeightForWidth(label_preferred_size.width() * 2)); 50} 51 52TEST_F(StyledLabelTest, TrailingWhitespaceiIgnored) { 53 const std::string text("This is a test block of text "); 54 InitStyledLabel(text); 55 56 styled()->SetBounds(0, 0, 1000, 1000); 57 styled()->Layout(); 58 59 ASSERT_EQ(1, styled()->child_count()); 60 ASSERT_EQ(std::string(Label::kViewClassName), 61 styled()->child_at(0)->GetClassName()); 62 EXPECT_EQ(ASCIIToUTF16("This is a test block of text"), 63 static_cast<Label*>(styled()->child_at(0))->text()); 64} 65 66TEST_F(StyledLabelTest, RespectLeadingWhitespace) { 67 const std::string text(" This is a test block of text"); 68 InitStyledLabel(text); 69 70 styled()->SetBounds(0, 0, 1000, 1000); 71 styled()->Layout(); 72 73 ASSERT_EQ(1, styled()->child_count()); 74 ASSERT_EQ(std::string(Label::kViewClassName), 75 styled()->child_at(0)->GetClassName()); 76 EXPECT_EQ(ASCIIToUTF16(" This is a test block of text"), 77 static_cast<Label*>(styled()->child_at(0))->text()); 78} 79 80TEST_F(StyledLabelTest, FirstLineNotEmptyWhenLeadingWhitespaceTooLong) { 81 const std::string text(" a"); 82 InitStyledLabel(text); 83 84 Label label(ASCIIToUTF16(text)); 85 gfx::Size label_preferred_size = label.GetPreferredSize(); 86 87 styled()->SetBounds(0, 0, label_preferred_size.width() / 2, 1000); 88 styled()->Layout(); 89 90 ASSERT_EQ(1, styled()->child_count()); 91 ASSERT_EQ(std::string(Label::kViewClassName), 92 styled()->child_at(0)->GetClassName()); 93 EXPECT_EQ(ASCIIToUTF16("a"), 94 static_cast<Label*>(styled()->child_at(0))->text()); 95} 96 97TEST_F(StyledLabelTest, BasicWrapping) { 98 const std::string text("This is a test block of text"); 99 InitStyledLabel(text); 100 Label label(ASCIIToUTF16(text.substr(0, text.size() * 2 / 3))); 101 gfx::Size label_preferred_size = label.GetPreferredSize(); 102 EXPECT_EQ(label_preferred_size.height() * 2, 103 StyledLabelContentHeightForWidth(label_preferred_size.width())); 104 105 // Also respect the border. 106 styled()->set_border(Border::CreateEmptyBorder(3, 3, 3, 3)); 107 styled()->SetBounds( 108 0, 109 0, 110 styled()->GetInsets().width() + label_preferred_size.width(), 111 styled()->GetInsets().height() + 2 * label_preferred_size.height()); 112 styled()->Layout(); 113 ASSERT_EQ(2, styled()->child_count()); 114 EXPECT_EQ(3, styled()->child_at(0)->bounds().x()); 115 EXPECT_EQ(3, styled()->child_at(0)->bounds().y()); 116 EXPECT_EQ(styled()->bounds().height() - 3, 117 styled()->child_at(1)->bounds().bottom()); 118} 119 120TEST_F(StyledLabelTest, CreateLinks) { 121 const std::string text("This is a test block of text."); 122 InitStyledLabel(text); 123 styled()->AddStyleRange(ui::Range(0, 1), 124 StyledLabel::RangeStyleInfo::CreateForLink()); 125 styled()->AddStyleRange(ui::Range(1, 2), 126 StyledLabel::RangeStyleInfo::CreateForLink()); 127 styled()->AddStyleRange(ui::Range(10, 11), 128 StyledLabel::RangeStyleInfo::CreateForLink()); 129 styled()->AddStyleRange(ui::Range(12, 13), 130 StyledLabel::RangeStyleInfo::CreateForLink()); 131 132 styled()->SetBounds(0, 0, 1000, 1000); 133 styled()->Layout(); 134 ASSERT_EQ(7, styled()->child_count()); 135} 136 137TEST_F(StyledLabelTest, DontBreakLinks) { 138 const std::string text("This is a test block of text, "); 139 const std::string link_text("and this should be a link"); 140 InitStyledLabel(text + link_text); 141 styled()->AddStyleRange( 142 ui::Range(text.size(), text.size() + link_text.size()), 143 StyledLabel::RangeStyleInfo::CreateForLink()); 144 145 Label label(ASCIIToUTF16(text + link_text.substr(0, link_text.size() / 2))); 146 gfx::Size label_preferred_size = label.GetPreferredSize(); 147 int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); 148 EXPECT_EQ(label_preferred_size.height() * 2, 149 pref_height - styled()->GetInsets().height()); 150 151 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); 152 styled()->Layout(); 153 ASSERT_EQ(2, styled()->child_count()); 154 EXPECT_EQ(0, styled()->child_at(0)->bounds().x()); 155 EXPECT_EQ(0, styled()->child_at(1)->bounds().x()); 156} 157 158TEST_F(StyledLabelTest, StyledRangeWithDisabledLineWrapping) { 159 const std::string text("This is a test block of text, "); 160 const std::string unbreakable_text("and this should not be breaked"); 161 InitStyledLabel(text + unbreakable_text); 162 StyledLabel::RangeStyleInfo style_info; 163 style_info.disable_line_wrapping = true; 164 styled()->AddStyleRange( 165 ui::Range(text.size(), text.size() + unbreakable_text.size()), 166 style_info); 167 168 Label label(ASCIIToUTF16( 169 text + unbreakable_text.substr(0, unbreakable_text.size() / 2))); 170 gfx::Size label_preferred_size = label.GetPreferredSize(); 171 int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); 172 EXPECT_EQ(label_preferred_size.height() * 2, 173 pref_height - styled()->GetInsets().height()); 174 175 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); 176 styled()->Layout(); 177 ASSERT_EQ(2, styled()->child_count()); 178 EXPECT_EQ(0, styled()->child_at(0)->bounds().x()); 179 EXPECT_EQ(0, styled()->child_at(1)->bounds().x()); 180} 181 182TEST_F(StyledLabelTest, StyledRangeUnderlined) { 183 const std::string text("This is a test block of text, "); 184 const std::string underlined_text("and this should be undelined"); 185 InitStyledLabel(text + underlined_text); 186 StyledLabel::RangeStyleInfo style_info; 187 style_info.font_style = gfx::Font::UNDERLINE; 188 styled()->AddStyleRange( 189 ui::Range(text.size(), text.size() + underlined_text.size()), 190 style_info); 191 192 styled()->SetBounds(0, 0, 1000, 1000); 193 styled()->Layout(); 194 195 ASSERT_EQ(2, styled()->child_count()); 196 ASSERT_EQ(std::string(Label::kViewClassName), 197 styled()->child_at(1)->GetClassName()); 198 EXPECT_EQ(gfx::Font::UNDERLINE, 199 static_cast<Label*>(styled()->child_at(1))->font().GetStyle()); 200} 201 202TEST_F(StyledLabelTest, StyledRangeBold) { 203 const std::string bold_text( 204 "This is a block of text whose style will be set to BOLD in the test"); 205 const std::string text(" normal text"); 206 InitStyledLabel(bold_text + text); 207 208 StyledLabel::RangeStyleInfo style_info; 209 style_info.font_style = gfx::Font::BOLD; 210 styled()->AddStyleRange(ui::Range(0, bold_text.size()), style_info); 211 212 // Calculate the bold text width if it were a pure label view, both with bold 213 // and normal style. 214 Label label(ASCIIToUTF16(bold_text)); 215 const gfx::Size normal_label_size = label.GetPreferredSize(); 216 label.SetFont(label.font().DeriveFont(0, gfx::Font::BOLD)); 217 const gfx::Size bold_label_size = label.GetPreferredSize(); 218 219 ASSERT_GE(bold_label_size.width(), normal_label_size.width()); 220 221 // Set the width so |bold_text| doesn't fit on a single line with bold style, 222 // but does with normal font style. 223 int styled_width = (normal_label_size.width() + bold_label_size.width()) / 2; 224 int pref_height = styled()->GetHeightForWidth(styled_width); 225 226 // Sanity check that |bold_text| with normal font style would fit on a single 227 // line in a styled label with width |styled_width|. 228 StyledLabel unstyled(ASCIIToUTF16(bold_text), this); 229 unstyled.SetBounds(0, 0, styled_width, pref_height); 230 unstyled.Layout(); 231 ASSERT_EQ(1, unstyled.child_count()); 232 233 styled()->SetBounds(0, 0, styled_width, pref_height); 234 styled()->Layout(); 235 236 ASSERT_EQ(3, styled()->child_count()); 237 238 // The bold text should be broken up into two parts. 239 ASSERT_EQ(std::string(Label::kViewClassName), 240 styled()->child_at(0)->GetClassName()); 241 EXPECT_EQ(gfx::Font::BOLD, 242 static_cast<Label*>(styled()->child_at(0))->font().GetStyle()); 243 ASSERT_EQ(std::string(Label::kViewClassName), 244 styled()->child_at(1)->GetClassName()); 245 EXPECT_EQ(gfx::Font::BOLD, 246 static_cast<Label*>(styled()->child_at(1))->font().GetStyle()); 247 ASSERT_EQ(std::string(Label::kViewClassName), 248 styled()->child_at(2)->GetClassName()); 249 EXPECT_EQ(gfx::Font::NORMAL, 250 static_cast<Label*>(styled()->child_at(2))->font().GetStyle()); 251 252 // The second bold part should start on a new line. 253 EXPECT_EQ(0, styled()->child_at(0)->bounds().x()); 254 EXPECT_EQ(0, styled()->child_at(1)->bounds().x()); 255 EXPECT_EQ(styled()->child_at(1)->bounds().right() - 2, 256 styled()->child_at(2)->bounds().x()); 257} 258 259TEST_F(StyledLabelTest, StyledRangeWithTooltip) { 260 const std::string text("This is a test block of text, "); 261 const std::string tooltip_text("this should have a tooltip,"); 262 const std::string normal_text(" this should not have a tooltip, "); 263 const std::string link_text("and this should be a link"); 264 265 const size_t tooltip_start = text.size(); 266 const size_t link_start = 267 text.size() + tooltip_text.size() + normal_text.size(); 268 269 InitStyledLabel(text + tooltip_text + normal_text + link_text); 270 StyledLabel::RangeStyleInfo tooltip_style; 271 tooltip_style.tooltip = ASCIIToUTF16("tooltip"); 272 styled()->AddStyleRange( 273 ui::Range(tooltip_start, tooltip_start + tooltip_text.size()), 274 tooltip_style); 275 styled()->AddStyleRange(ui::Range(link_start, link_start + link_text.size()), 276 StyledLabel::RangeStyleInfo::CreateForLink()); 277 278 // Break line inside the range with the tooltip. 279 Label label(ASCIIToUTF16( 280 text + tooltip_text.substr(0, tooltip_text.size() - 3))); 281 gfx::Size label_preferred_size = label.GetPreferredSize(); 282 int pref_height = styled()->GetHeightForWidth(label_preferred_size.width()); 283 EXPECT_EQ(label_preferred_size.height() * 3, 284 pref_height - styled()->GetInsets().height()); 285 286 styled()->SetBounds(0, 0, label_preferred_size.width(), pref_height); 287 styled()->Layout(); 288 289 EXPECT_EQ(label_preferred_size.width(), styled()->width()); 290 291 ASSERT_EQ(5, styled()->child_count()); 292 EXPECT_EQ(0, styled()->child_at(0)->bounds().x()); 293 EXPECT_EQ(styled()->child_at(0)->bounds().right() - 2, 294 styled()->child_at(1)->bounds().x()); 295 EXPECT_EQ(0, styled()->child_at(2)->bounds().x()); 296 EXPECT_EQ(styled()->child_at(2)->bounds().right() - 2, 297 styled()->child_at(3)->bounds().x()); 298 EXPECT_EQ(0, styled()->child_at(4)->bounds().x()); 299 300 string16 tooltip; 301 EXPECT_TRUE( 302 styled()->child_at(1)->GetTooltipText(gfx::Point(1, 1), &tooltip)); 303 EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip); 304 EXPECT_TRUE( 305 styled()->child_at(2)->GetTooltipText(gfx::Point(1, 1), &tooltip)); 306 EXPECT_EQ(ASCIIToUTF16("tooltip"), tooltip); 307} 308 309TEST_F(StyledLabelTest, HandleEmptyLayout) { 310 const std::string text("This is a test block of text, "); 311 InitStyledLabel(text); 312 styled()->Layout(); 313 ASSERT_EQ(0, styled()->child_count()); 314} 315 316} // namespace 317