Home | History | Annotate | Download | only in views
      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