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 "ui/message_center/views/bounded_label.h" 6 7 #include <limits> 8 9 #include "base/strings/string_split.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 #include "ui/gfx/font.h" 14 #include "ui/views/controls/label.h" 15 16 namespace message_center { 17 18 namespace test { 19 20 /* Test fixture ***************************************************************/ 21 22 class BoundedLabelTest : public testing::Test { 23 public: 24 BoundedLabelTest() { 25 digit_pixels_ = font_.GetStringWidth(UTF8ToUTF16("0")); 26 space_pixels_ = font_.GetStringWidth(UTF8ToUTF16(" ")); 27 ellipsis_pixels_ = font_.GetStringWidth(UTF8ToUTF16("\xE2\x80\xA6")); 28 } 29 30 virtual ~BoundedLabelTest() {} 31 32 // Replaces all occurences of three periods ("...") in the specified string 33 // with an ellipses character (UTF8 "\xE2\x80\xA6") and returns a string16 34 // with the results. This allows test strings to be specified as ASCII const 35 // char* strings, making tests more readable and easier to write. 36 string16 ToString(const char* string) { 37 const string16 periods = UTF8ToUTF16("..."); 38 const string16 ellipses = UTF8ToUTF16("\xE2\x80\xA6"); 39 string16 result = UTF8ToUTF16(string); 40 ReplaceSubstringsAfterOffset(&result, 0, periods, ellipses); 41 return result; 42 } 43 44 // Converts the specified elision width to pixels. To make tests somewhat 45 // independent of the fonts of the platform on which they're run, the elision 46 // widths are specified as XYZ integers, with the corresponding width in 47 // pixels being X times the width of digit characters plus Y times the width 48 // of spaces plus Z times the width of ellipses in the default font of the 49 // test plaform. It is assumed that all digits have the same width in that 50 // font, that this width is greater than the width of spaces, and that the 51 // width of 3 digits is greater than the width of ellipses. 52 int ToPixels(int width) { 53 return digit_pixels_ * width / 100 + 54 space_pixels_ * (width % 100) / 10 + 55 ellipsis_pixels_ * (width % 10); 56 } 57 58 // Exercise BounderLabel::GetWrappedText() using the fixture's test label. 59 string16 GetWrappedText(int width) { 60 return label_->GetWrappedTextForTest(width, lines_); 61 } 62 63 // Exercise BounderLabel::GetLinesForWidthAndLimit() using the test label. 64 int GetLinesForWidth(int width) { 65 label_->SetBounds(0, 0, width, font_.GetHeight() * lines_); 66 return label_->GetLinesForWidthAndLimit(width, lines_); 67 } 68 69 protected: 70 // Creates a label to test with. Returns this fixture, which can be used to 71 // test the newly created label using the exercise methods above. 72 BoundedLabelTest& Label(string16 text, int lines) { 73 lines_ = lines; 74 label_.reset(new BoundedLabel(text, font_)); 75 label_->SetLineLimit(lines_); 76 return *this; 77 } 78 79 private: 80 gfx::Font font_; // The default font, which will be used for tests. 81 int digit_pixels_; 82 int space_pixels_; 83 int ellipsis_pixels_; 84 scoped_ptr<BoundedLabel> label_; 85 int lines_; 86 }; 87 88 /* Test macro *****************************************************************/ 89 90 #define TEST_WRAP(expected, text, width, lines) \ 91 EXPECT_EQ(ToString(expected), \ 92 Label(ToString(text), lines).GetWrappedText(ToPixels(width))) 93 94 #define TEST_LINES(expected, text, width, lines) \ 95 EXPECT_EQ(expected, \ 96 Label(ToString(text), lines).GetLinesForWidth(ToPixels(width))) 97 98 /* Elision tests **************************************************************/ 99 100 TEST_F(BoundedLabelTest, GetWrappedTextTest) { 101 // One word per line: No ellision should be made when not necessary. 102 TEST_WRAP("123", "123", 301, 1); 103 TEST_WRAP("123", "123", 301, 2); 104 TEST_WRAP("123", "123", 301, 3); 105 TEST_WRAP("123\n456", "123 456", 301, 2); 106 TEST_WRAP("123\n456", "123 456", 301, 3); 107 TEST_WRAP("123\n456\n789", "123 456 789", 301, 3); 108 109 // One word per line: Ellisions should be made when necessary. 110 TEST_WRAP("123...", "123 456", 301, 1); 111 TEST_WRAP("123...", "123 456 789", 301, 1); 112 TEST_WRAP("123\n456...", "123 456 789", 301, 2); 113 114 // Two words per line: No ellision should be made when not necessary. 115 TEST_WRAP("123 456", "123 456", 621, 1); 116 TEST_WRAP("123 456", "123 456", 621, 2); 117 TEST_WRAP("123 456", "123 456", 621, 3); 118 TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 2); 119 TEST_WRAP("123 456\n789 012", "123 456 789 012", 621, 3); 120 TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678", 621, 3); 121 122 // Two words per line: Ellisions should be made when necessary. 123 TEST_WRAP("123 456...", "123 456 789 012", 621, 1); 124 TEST_WRAP("123 456...", "123 456 789 012 345 678", 621, 1); 125 TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 621, 2); 126 127 // Single trailing spaces: No ellipses should be added. 128 TEST_WRAP("123", "123 ", 301, 1); 129 TEST_WRAP("123\n456", "123 456 ", 301, 2); 130 TEST_WRAP("123\n456\n789", "123 456 789 ", 301, 3); 131 TEST_WRAP("123 456", "123 456 ", 611, 1); 132 TEST_WRAP("123 456\n789 012", "123 456 789 012 ", 611, 2); 133 TEST_WRAP("123 456\n789 012\n345 678", "123 456 789 012 345 678 ", 611, 3); 134 135 // Multiple trailing spaces: No ellipses should be added. 136 TEST_WRAP("123", "123 ", 301, 1); 137 TEST_WRAP("123\n456", "123 456 ", 301, 2); 138 TEST_WRAP("123\n456\n789", "123 456 789 ", 301, 3); 139 TEST_WRAP("123 456", "123 456 ", 611, 1); 140 TEST_WRAP("123 456\n789 012", "123 456 789 012 ", 611, 2); 141 TEST_WRAP("123 456\n789 012\n345 678", 142 "123 456 789 012 345 678 ", 611, 3); 143 144 // Multiple spaces between words on the same line: Spaces should be preserved. 145 // Test cases for single spaces between such words are included in the "Two 146 // words per line" sections above. 147 TEST_WRAP("123 456", "123 456", 621, 1); 148 TEST_WRAP("123 456...", "123 456 789 012", 631, 1); 149 TEST_WRAP("123 456\n789 012", "123 456 789 012", 631, 2); 150 TEST_WRAP("123 456...", "123 456 789 012 345 678", 621, 1); 151 TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 631, 2); 152 TEST_WRAP("123 456\n789 012\n345 678", 153 "123 456 789 012 345 678", 641, 3); 154 155 // Multiple spaces between words split across lines: Spaces should be removed 156 // even if lines are wide enough to include those spaces. Test cases for 157 // single spaces between such words are included in the "Two words per line" 158 // sections above. 159 TEST_WRAP("123\n456", "123 456", 321, 2); 160 TEST_WRAP("123\n456", "123 456", 391, 2); 161 TEST_WRAP("123\n456...", "123 456 789", 321, 2); 162 TEST_WRAP("123\n456...", "123 456 789", 391, 2); 163 TEST_WRAP("123 456\n789 012", "123 456 789 012", 641, 2); 164 TEST_WRAP("123 456\n789 012...", "123 456 789 012 345 678", 641, 2); 165 166 // Long words without spaces should be wrapped when necessary. 167 TEST_WRAP("123\n456", "123456", 300, 9); 168 169 // TODO(dharcourt): Add test cases to verify that: 170 // - Spaces before elisions are removed 171 // - Leading spaces are preserved 172 // - Words are split when they are longer than lines 173 // - Words are clipped when they are longer than the last line 174 // - No blank line are created before or after clipped word 175 // - Spaces at the end of the text are removed 176 177 // TODO(dharcourt): Add test cases for: 178 // - Empty and very large strings 179 // - Zero, very large, and negative line limit values 180 // - Other input boundary conditions 181 // TODO(dharcourt): Add some randomly generated fuzz test cases. 182 183 } 184 185 /* GetLinesTest ***************************************************************/ 186 187 TEST_F(BoundedLabelTest, GetLinesTest) { 188 // Zero and negative width values should yield zero lines. 189 TEST_LINES(0, "123 456", 0, 1); 190 TEST_LINES(0, "123 456", -1, 1); 191 TEST_LINES(0, "123 456", -2, 1); 192 TEST_LINES(0, "123 456", std::numeric_limits<int>::min(), 1); 193 194 // Small width values should yield one word per line. 195 TEST_LINES(1, "123 456", 1, 1); 196 TEST_LINES(2, "123 456", 1, 2); 197 TEST_LINES(1, "123 456", 2, 1); 198 TEST_LINES(2, "123 456", 2, 2); 199 TEST_LINES(1, "123 456", 3, 1); 200 TEST_LINES(2, "123 456", 3, 2); 201 202 // Large width values should yield all words on one line. 203 TEST_LINES(1, "123 456", 610, 1); 204 TEST_LINES(1, "123 456", std::numeric_limits<int>::max(), 1); 205 } 206 207 /* Other tests ****************************************************************/ 208 209 // TODO(dharcourt): Add test cases to verify that: 210 // - SetMaxLines() affects the return values of some methods but not others. 211 // - Bound changes affects GetPreferredLines(), GetTextSize(), and 212 // GetWrappedText() return values. 213 // - GetTextFlags are as expected. 214 215 } // namespace test 216 217 } // namespace message_center 218