summaryrefslogtreecommitdiffstats
path: root/chromium/ui/message_center/views/bounded_label_unittest.cc
blob: 90452e2e1e312cb9ffff0f2e3255b8fecd31007b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Copyright 2013 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 "ui/message_center/views/bounded_label.h"

#include <limits>

#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
#include "ui/views/controls/label.h"

namespace message_center {

namespace test {

/* Test fixture ***************************************************************/

class BoundedLabelTest : public testing::Test {
 public:
  BoundedLabelTest() {
    digit_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16("0"), font_list_);
    space_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16(" "), font_list_);
    ellipsis_pixels_ = gfx::GetStringWidth(base::UTF8ToUTF16("\xE2\x80\xA6"),
                                           font_list_);
  }

  virtual ~BoundedLabelTest() {}

  // Replaces all occurences of three periods ("...") in the specified string
  // with an ellipses character (UTF8 "\xE2\x80\xA6") and returns a string16
  // with the results. This allows test strings to be specified as ASCII const
  // char* strings, making tests more readable and easier to write.
  base::string16 ToString(const char* string) {
    const base::string16 periods = base::UTF8ToUTF16("...");
    const base::string16 ellipses = base::UTF8ToUTF16("\xE2\x80\xA6");
    base::string16 result = base::UTF8ToUTF16(string);
    ReplaceSubstringsAfterOffset(&result, 0, periods, ellipses);
    return result;
  }

  // Converts the specified elision width to pixels. To make tests somewhat
  // independent of the fonts of the platform on which they're run, the elision
  // widths are specified as XYZ integers, with the corresponding width in
  // pixels being X times the width of digit characters plus Y times the width
  // of spaces plus Z times the width of ellipses in the default font of the
  // test plaform. It is assumed that all digits have the same width in that
  // font, that this width is greater than the width of spaces, and that the
  // width of 3 digits is greater than the width of ellipses.
  int ToPixels(int width) {
    return digit_pixels_ * width / 100 +
           space_pixels_ * (width % 100) / 10 +
           ellipsis_pixels_ * (width % 10);
  }

  // Exercise BounderLabel::GetWrappedText() using the fixture's test label.
  base::string16 GetWrappedText(int width) {
    return label_->GetWrappedTextForTest(width, lines_);
  }

  // Exercise BounderLabel::GetLinesForWidthAndLimit() using the test label.
  int GetLinesForWidth(int width) {
    label_->SetBounds(0, 0, width, font_list_.GetHeight() * lines_);
    return label_->GetLinesForWidthAndLimit(width, lines_);
  }

 protected:
  // Creates a label to test with. Returns this fixture, which can be used to
  // test the newly created label using the exercise methods above.
  BoundedLabelTest& Label(base::string16 text, int lines) {
    lines_ = lines;
    label_.reset(new BoundedLabel(text, font_list_));
    label_->SetLineLimit(lines_);
    return *this;
  }

 private:
  // The default font list, which will be used for tests.
  gfx::FontList font_list_;
  int digit_pixels_;
  int space_pixels_;
  int ellipsis_pixels_;
  scoped_ptr<BoundedLabel> label_;
  int lines_;
};

/* Test macro *****************************************************************/

#define TEST_WRAP(expected, text, width, lines) \
  EXPECT_EQ(ToString(expected), \
            Label(ToString(text), lines).GetWrappedText(ToPixels(width)))

#define TEST_LINES(expected, text, width, lines) \
  EXPECT_EQ(expected, \
            Label(ToString(text), lines).GetLinesForWidth(ToPixels(width)))

/* Elision tests **************************************************************/

TEST_F(BoundedLabelTest, GetWrappedTextTest) {
  // One word per line: No ellision should be made when not necessary.
  TEST_WRAP("123", "123", 301, 1);
  TEST_WRAP("123", "123", 301, 2);
  TEST_WRAP("123", "123", 301, 3);
  TEST_WRAP("123\n456", "123 456", 301, 2);
  TEST_WRAP("123\n456", "123 456", 301, 3);
  TEST_WRAP("123\n456\n789", "123 456 789", 301, 3);

  // One word per line: Ellisions should be made when necessary.
  TEST_WRAP("123...", "123 456", 301, 1);
  TEST_WRAP("123...", "123 456 789", 301, 1);
  TEST_WRAP("123\n456...", "123 456 789", 301, 2);

  // Two words per line: No ellision should be made when not necessary.
  TEST_WRAP("123 456", "123 456", 621, 1);
  TEST_WRAP("123 456", "123 456", 621, 2);
  TEST_WRAP("123 456", "123 456", 621, 3);
  TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 2);
  TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 3);
  TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678", 621, 3);

  // Two words per line: Ellisions should be made when necessary.
  TEST_WRAP("123 456...", "123 456 789 012", 621, 1);
  TEST_WRAP("123 456...", "123 456 789 012 345 678", 621, 1);
  TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 621, 2);

  // Single trailing spaces: No ellipses should be added.
  TEST_WRAP("123", "123 ", 301, 1);
  TEST_WRAP("123\n456", "123 456 ", 301, 2);
  TEST_WRAP("123\n456\n789", "123 456 789 ", 301, 3);
  TEST_WRAP("123 456", "123 456 ", 611, 1);
  TEST_WRAP("123 456\n789 012", "123 456 789 012 ", 611, 2);
  TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678 ", 611, 3);

  // Multiple trailing spaces: No ellipses should be added.
  TEST_WRAP("123", "123         ", 301, 1);
  TEST_WRAP("123\n456", "123 456         ", 301, 2);
  TEST_WRAP("123\n456\n789", "123 456 789         ", 301, 3);
  TEST_WRAP("123 456", "123 456         ", 611, 1);
  TEST_WRAP("123 456\n789 012", "123 456 789 012         ", 611, 2);
  TEST_WRAP("123 456\n789 012\n345 678",
            "123 456 789 012 345 678         ", 611, 3);

  // Multiple spaces between words on the same line: Spaces should be preserved.
  // Test cases for single spaces between such words are included in the "Two
  // words per line" sections above.
  TEST_WRAP("123  456", "123  456", 621, 1);
  TEST_WRAP("123  456...", "123  456 789   012", 631, 1);
  TEST_WRAP("123  456\n789   012", "123  456 789   012", 631, 2);
  TEST_WRAP("123  456...", "123  456 789   012  345    678", 621, 1);
  TEST_WRAP("123  456\n789   012...", "123  456 789   012 345    678", 631, 2);
  TEST_WRAP("123  456\n789   012\n345    678",
            "123  456 789   012 345    678", 641, 3);

  // Multiple spaces between words split across lines: Spaces should be removed
  // even if lines are wide enough to include those spaces. Test cases for
  // single spaces between such words are included in the "Two words  per line"
  // sections above.
  TEST_WRAP("123\n456", "123  456", 321, 2);
  TEST_WRAP("123\n456", "123         456", 391, 2);
  TEST_WRAP("123\n456...", "123  456  789", 321, 2);
  TEST_WRAP("123\n456...", "123         456         789", 391, 2);
  TEST_WRAP("123  456\n789  012", "123  456  789  012", 641, 2);
  TEST_WRAP("123  456\n789  012...", "123  456  789  012  345  678", 641, 2);

  // Long words without spaces should be wrapped when necessary.
  TEST_WRAP("123\n456", "123456", 300, 9);

  // TODO(dharcourt): Add test cases to verify that:
  // - Spaces before elisions are removed
  // - Leading spaces are preserved
  // - Words are split when they are longer than lines
  // - Words are clipped when they are longer than the last line
  // - No blank line are created before or after clipped word
  // - Spaces at the end of the text are removed

  // TODO(dharcourt): Add test cases for:
  // - Empty and very large strings
  // - Zero, very large, and negative line limit values
  // - Other input boundary conditions
  // TODO(dharcourt): Add some randomly generated fuzz test cases.

}

/* GetLinesTest ***************************************************************/

TEST_F(BoundedLabelTest, GetLinesTest) {
  // Zero and negative width values should yield zero lines.
  TEST_LINES(0, "123 456", 0, 1);
  TEST_LINES(0, "123 456", -1, 1);
  TEST_LINES(0, "123 456", -2, 1);
  TEST_LINES(0, "123 456", std::numeric_limits<int>::min(), 1);

  // Small width values should yield one word per line.
  TEST_LINES(1, "123 456", 1, 1);
  TEST_LINES(2, "123 456", 1, 2);
  TEST_LINES(1, "123 456", 2, 1);
  TEST_LINES(2, "123 456", 2, 2);
  TEST_LINES(1, "123 456", 3, 1);
  TEST_LINES(2, "123 456", 3, 2);

  // Large width values should yield all words on one line.
  TEST_LINES(1, "123 456", 610, 1);
  TEST_LINES(1, "123 456", std::numeric_limits<int>::max(), 1);
}

/* Other tests ****************************************************************/

// TODO(dharcourt): Add test cases to verify that:
// - SetMaxLines() affects the return values of some methods but not others.
// - Bound changes affects GetPreferredLines(), GetTextSize(), and
//   GetWrappedText() return values.
// - GetTextFlags are as expected.

}  // namespace test

}  // namespace message_center