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