Home | History | Annotate | Download | only in autocomplete
      1 // Copyright (c) 2011 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 #import "chrome/browser/autocomplete/autocomplete_popup_view_mac.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/sys_string_conversions.h"
      9 #include "base/utf_string_conversions.h"
     10 #include "chrome/browser/autocomplete/autocomplete.h"
     11 #include "testing/platform_test.h"
     12 #include "ui/base/text/text_elider.h"
     13 
     14 namespace {
     15 
     16 const float kLargeWidth = 10000;
     17 
     18 class AutocompletePopupViewMacTest : public PlatformTest {
     19  public:
     20   AutocompletePopupViewMacTest() {}
     21 
     22   virtual void SetUp() {
     23     PlatformTest::SetUp();
     24 
     25     // These are here because there is no autorelease pool for the
     26     // constructor.
     27     color_ = [NSColor blackColor];
     28     dimColor_ = [NSColor darkGrayColor];
     29     font_ = gfx::Font(
     30         base::SysNSStringToUTF16([[NSFont userFontOfSize:12] fontName]), 12);
     31   }
     32 
     33   // Returns the length of the run starting at |location| for which
     34   // |attributeName| remains the same.
     35   static NSUInteger RunLengthForAttribute(NSAttributedString* string,
     36                                           NSUInteger location,
     37                                           NSString* attributeName) {
     38     const NSRange fullRange = NSMakeRange(0, [string length]);
     39     NSRange range;
     40     [string attribute:attributeName
     41               atIndex:location longestEffectiveRange:&range inRange:fullRange];
     42 
     43     // In order to signal when the run doesn't start exactly at
     44     // location, return a weirdo length.  This causes the incorrect
     45     // expectation to manifest at the calling location, which is more
     46     // useful than an EXPECT_EQ() would be here.
     47     if (range.location != location) {
     48       return -1;
     49     }
     50 
     51     return range.length;
     52   }
     53 
     54   // Return true if the run starting at |location| has |color| for
     55   // attribute NSForegroundColorAttributeName.
     56   static bool RunHasColor(NSAttributedString* string,
     57                           NSUInteger location, NSColor* color) {
     58     const NSRange fullRange = NSMakeRange(0, [string length]);
     59     NSRange range;
     60     NSColor* runColor = [string attribute:NSForegroundColorAttributeName
     61                                   atIndex:location
     62                     longestEffectiveRange:&range inRange:fullRange];
     63 
     64     // According to one "Ali Ozer", you can compare objects within the
     65     // same color space using -isEqual:.  Converting color spaces
     66     // seems too heavyweight for these tests.
     67     // http://lists.apple.com/archives/cocoa-dev/2005/May/msg00186.html
     68     return [runColor isEqual:color] ? true : false;
     69   }
     70 
     71   // Return true if the run starting at |location| has the font
     72   // trait(s) in |mask| font in NSFontAttributeName.
     73   static bool RunHasFontTrait(NSAttributedString* string, NSUInteger location,
     74                               NSFontTraitMask mask) {
     75     const NSRange fullRange = NSMakeRange(0, [string length]);
     76     NSRange range;
     77     NSFont* runFont = [string attribute:NSFontAttributeName
     78                                 atIndex:location
     79                   longestEffectiveRange:&range inRange:fullRange];
     80     NSFontManager* fontManager = [NSFontManager sharedFontManager];
     81     if (runFont && (mask == ([fontManager traitsOfFont:runFont]&mask))) {
     82       return true;
     83     }
     84     return false;
     85   }
     86 
     87   // AutocompleteMatch doesn't really have the right constructor for our
     88   // needs.  Fake one for us to use.
     89   static AutocompleteMatch MakeMatch(const string16 &contents,
     90                                      const string16 &description) {
     91     AutocompleteMatch m(NULL, 1, true, AutocompleteMatch::URL_WHAT_YOU_TYPED);
     92     m.contents = contents;
     93     m.description = description;
     94     return m;
     95   }
     96 
     97   NSColor* color_;  // weak
     98   NSColor* dimColor_;  // weak
     99   gfx::Font font_;
    100 };
    101 
    102 // Simple inputs with no matches should result in styled output who's
    103 // text matches the input string, with the passed-in color, and
    104 // nothing bolded.
    105 TEST_F(AutocompletePopupViewMacTest, DecorateMatchedStringNoMatch) {
    106   NSString* const string = @"This is a test";
    107   AutocompleteMatch::ACMatchClassifications classifications;
    108 
    109   NSAttributedString* decorated =
    110       AutocompletePopupViewMac::DecorateMatchedString(
    111           base::SysNSStringToUTF16(string), classifications,
    112           color_, dimColor_, font_);
    113 
    114   // Result has same characters as the input.
    115   EXPECT_EQ([decorated length], [string length]);
    116   EXPECT_TRUE([[decorated string] isEqualToString:string]);
    117 
    118   // Our passed-in color for the entire string.
    119   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    120                                   NSForegroundColorAttributeName),
    121             [string length]);
    122   EXPECT_TRUE(RunHasColor(decorated, 0U, color_));
    123 
    124   // An unbolded font for the entire string.
    125   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    126                                   NSFontAttributeName), [string length]);
    127   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    128 }
    129 
    130 // Identical to DecorateMatchedStringNoMatch, except test that URL
    131 // style gets a different color than we passed in.
    132 TEST_F(AutocompletePopupViewMacTest, DecorateMatchedStringURLNoMatch) {
    133   NSString* const string = @"This is a test";
    134   AutocompleteMatch::ACMatchClassifications classifications;
    135 
    136   classifications.push_back(
    137       ACMatchClassification(0, ACMatchClassification::URL));
    138 
    139   NSAttributedString* decorated =
    140       AutocompletePopupViewMac::DecorateMatchedString(
    141           base::SysNSStringToUTF16(string), classifications,
    142           color_, dimColor_, font_);
    143 
    144   // Result has same characters as the input.
    145   EXPECT_EQ([decorated length], [string length]);
    146   EXPECT_TRUE([[decorated string] isEqualToString:string]);
    147 
    148   // One color for the entire string, and it's not the one we passed in.
    149   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    150                                   NSForegroundColorAttributeName),
    151             [string length]);
    152   EXPECT_FALSE(RunHasColor(decorated, 0U, color_));
    153 
    154   // An unbolded font for the entire string.
    155   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    156                                   NSFontAttributeName), [string length]);
    157   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    158 }
    159 
    160 // Test that DIM works as expected.
    161 TEST_F(AutocompletePopupViewMacTest, DecorateMatchedStringDimNoMatch) {
    162   NSString* const string = @"This is a test";
    163   // Dim "is".
    164   const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
    165   // Make sure nobody messed up the inputs.
    166   EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
    167 
    168   // Push each run onto classifications.
    169   AutocompleteMatch::ACMatchClassifications classifications;
    170   classifications.push_back(
    171       ACMatchClassification(0, ACMatchClassification::NONE));
    172   classifications.push_back(
    173       ACMatchClassification(runLength1, ACMatchClassification::DIM));
    174   classifications.push_back(
    175       ACMatchClassification(runLength1 + runLength2,
    176                             ACMatchClassification::NONE));
    177 
    178   NSAttributedString* decorated =
    179       AutocompletePopupViewMac::DecorateMatchedString(
    180           base::SysNSStringToUTF16(string), classifications,
    181           color_, dimColor_, font_);
    182 
    183   // Result has same characters as the input.
    184   EXPECT_EQ([decorated length], [string length]);
    185   EXPECT_TRUE([[decorated string] isEqualToString:string]);
    186 
    187   // Should have three font runs, normal, dim, normal.
    188   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    189                                   NSForegroundColorAttributeName),
    190             runLength1);
    191   EXPECT_TRUE(RunHasColor(decorated, 0U, color_));
    192 
    193   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
    194                                   NSForegroundColorAttributeName),
    195             runLength2);
    196   EXPECT_TRUE(RunHasColor(decorated, runLength1, dimColor_));
    197 
    198   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
    199                                   NSForegroundColorAttributeName),
    200             runLength3);
    201   EXPECT_TRUE(RunHasColor(decorated, runLength1 + runLength2, color_));
    202 
    203   // An unbolded font for the entire string.
    204   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    205                                   NSFontAttributeName), [string length]);
    206   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    207 }
    208 
    209 // Test that the matched run gets bold-faced, but keeps the same
    210 // color.
    211 TEST_F(AutocompletePopupViewMacTest, DecorateMatchedStringMatch) {
    212   NSString* const string = @"This is a test";
    213   // Match "is".
    214   const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
    215   // Make sure nobody messed up the inputs.
    216   EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
    217 
    218   // Push each run onto classifications.
    219   AutocompleteMatch::ACMatchClassifications classifications;
    220   classifications.push_back(
    221       ACMatchClassification(0, ACMatchClassification::NONE));
    222   classifications.push_back(
    223       ACMatchClassification(runLength1, ACMatchClassification::MATCH));
    224   classifications.push_back(
    225       ACMatchClassification(runLength1 + runLength2,
    226                             ACMatchClassification::NONE));
    227 
    228   NSAttributedString* decorated =
    229       AutocompletePopupViewMac::DecorateMatchedString(
    230           base::SysNSStringToUTF16(string), classifications,
    231           color_, dimColor_, font_);
    232 
    233   // Result has same characters as the input.
    234   EXPECT_EQ([decorated length], [string length]);
    235   EXPECT_TRUE([[decorated string] isEqualToString:string]);
    236 
    237   // Our passed-in color for the entire string.
    238   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    239                                   NSForegroundColorAttributeName),
    240             [string length]);
    241   EXPECT_TRUE(RunHasColor(decorated, 0U, color_));
    242 
    243   // Should have three font runs, not bold, bold, then not bold again.
    244   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    245                                   NSFontAttributeName), runLength1);
    246   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    247 
    248   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
    249                                   NSFontAttributeName), runLength2);
    250   EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
    251 
    252   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
    253                                   NSFontAttributeName), runLength3);
    254   EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
    255                                NSBoldFontMask));
    256 }
    257 
    258 // Just like DecorateMatchedStringURLMatch, this time with URL style.
    259 TEST_F(AutocompletePopupViewMacTest, DecorateMatchedStringURLMatch) {
    260   NSString* const string = @"http://hello.world/";
    261   // Match "hello".
    262   const NSUInteger runLength1 = 7, runLength2 = 5, runLength3 = 7;
    263   // Make sure nobody messed up the inputs.
    264   EXPECT_EQ(runLength1 + runLength2 + runLength3, [string length]);
    265 
    266   // Push each run onto classifications.
    267   AutocompleteMatch::ACMatchClassifications classifications;
    268   classifications.push_back(
    269       ACMatchClassification(0, ACMatchClassification::URL));
    270   const int kURLMatch = ACMatchClassification::URL|ACMatchClassification::MATCH;
    271   classifications.push_back(ACMatchClassification(runLength1, kURLMatch));
    272   classifications.push_back(
    273       ACMatchClassification(runLength1 + runLength2,
    274                             ACMatchClassification::URL));
    275 
    276   NSAttributedString* decorated =
    277       AutocompletePopupViewMac::DecorateMatchedString(
    278           base::SysNSStringToUTF16(string), classifications,
    279           color_, dimColor_, font_);
    280 
    281   // Result has same characters as the input.
    282   EXPECT_EQ([decorated length], [string length]);
    283   EXPECT_TRUE([[decorated string] isEqualToString:string]);
    284 
    285   // One color for the entire string, and it's not the one we passed in.
    286   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    287                                   NSForegroundColorAttributeName),
    288             [string length]);
    289   EXPECT_FALSE(RunHasColor(decorated, 0U, color_));
    290 
    291   // Should have three font runs, not bold, bold, then not bold again.
    292   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    293                                   NSFontAttributeName), runLength1);
    294   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    295 
    296   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
    297                                   NSFontAttributeName), runLength2);
    298   EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
    299 
    300   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
    301                                   NSFontAttributeName), runLength3);
    302   EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
    303                                NSBoldFontMask));
    304 }
    305 
    306 // Check that matches with both contents and description come back
    307 // with contents at the beginning, description at the end, and
    308 // something separating them.  Not being specific about the separator
    309 // on purpose, in case it changes.
    310 TEST_F(AutocompletePopupViewMacTest, MatchText) {
    311   NSString* const contents = @"contents";
    312   NSString* const description = @"description";
    313   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
    314                                   base::SysNSStringToUTF16(description));
    315 
    316   NSAttributedString* decorated =
    317       AutocompletePopupViewMac::MatchText(m, font_, kLargeWidth);
    318 
    319   // Result contains the characters of the input in the right places.
    320   EXPECT_GT([decorated length], [contents length] + [description length]);
    321   EXPECT_TRUE([[decorated string] hasPrefix:contents]);
    322   EXPECT_TRUE([[decorated string] hasSuffix:description]);
    323 
    324   // Check that the description is a different color from the
    325   // contents.
    326   const NSUInteger descriptionLocation =
    327       [decorated length] - [description length];
    328   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    329                                   NSForegroundColorAttributeName),
    330             descriptionLocation);
    331   EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation,
    332                                   NSForegroundColorAttributeName),
    333             [description length]);
    334 
    335   // Same font all the way through, nothing bold.
    336   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    337                                   NSFontAttributeName), [decorated length]);
    338   EXPECT_FALSE(RunHasFontTrait(decorated, 0, NSBoldFontMask));
    339 }
    340 
    341 // Check that MatchText() styles content matches as expected.
    342 TEST_F(AutocompletePopupViewMacTest, MatchTextContentsMatch) {
    343   NSString* const contents = @"This is a test";
    344   // Match "is".
    345   const NSUInteger runLength1 = 5, runLength2 = 2, runLength3 = 7;
    346   // Make sure nobody messed up the inputs.
    347   EXPECT_EQ(runLength1 + runLength2 + runLength3, [contents length]);
    348 
    349   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
    350                                   string16());
    351 
    352   // Push each run onto contents classifications.
    353   m.contents_class.push_back(
    354       ACMatchClassification(0, ACMatchClassification::NONE));
    355   m.contents_class.push_back(
    356       ACMatchClassification(runLength1, ACMatchClassification::MATCH));
    357   m.contents_class.push_back(
    358       ACMatchClassification(runLength1 + runLength2,
    359                             ACMatchClassification::NONE));
    360 
    361   NSAttributedString* decorated =
    362       AutocompletePopupViewMac::MatchText(m, font_, kLargeWidth);
    363 
    364   // Result has same characters as the input.
    365   EXPECT_EQ([decorated length], [contents length]);
    366   EXPECT_TRUE([[decorated string] isEqualToString:contents]);
    367 
    368   // Result is all one color.
    369   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    370                                   NSForegroundColorAttributeName),
    371             [contents length]);
    372 
    373   // Should have three font runs, not bold, bold, then not bold again.
    374   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    375                                   NSFontAttributeName), runLength1);
    376   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    377 
    378   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1,
    379                                   NSFontAttributeName), runLength2);
    380   EXPECT_TRUE(RunHasFontTrait(decorated, runLength1, NSBoldFontMask));
    381 
    382   EXPECT_EQ(RunLengthForAttribute(decorated, runLength1 + runLength2,
    383                                   NSFontAttributeName), runLength3);
    384   EXPECT_FALSE(RunHasFontTrait(decorated, runLength1 + runLength2,
    385                                NSBoldFontMask));
    386 }
    387 
    388 // Check that MatchText() styles description matches as expected.
    389 TEST_F(AutocompletePopupViewMacTest, MatchTextDescriptionMatch) {
    390   NSString* const contents = @"This is a test";
    391   NSString* const description = @"That was a test";
    392   // Match "That was".
    393   const NSUInteger runLength1 = 8, runLength2 = 7;
    394   // Make sure nobody messed up the inputs.
    395   EXPECT_EQ(runLength1 + runLength2, [description length]);
    396 
    397   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
    398                                   base::SysNSStringToUTF16(description));
    399 
    400   // Push each run onto contents classifications.
    401   m.description_class.push_back(
    402       ACMatchClassification(0, ACMatchClassification::MATCH));
    403   m.description_class.push_back(
    404       ACMatchClassification(runLength1, ACMatchClassification::NONE));
    405 
    406   NSAttributedString* decorated =
    407       AutocompletePopupViewMac::MatchText(m, font_, kLargeWidth);
    408 
    409   // Result contains the characters of the input.
    410   EXPECT_GT([decorated length], [contents length] + [description length]);
    411   EXPECT_TRUE([[decorated string] hasPrefix:contents]);
    412   EXPECT_TRUE([[decorated string] hasSuffix:description]);
    413 
    414   // Check that the description is a different color from the
    415   // contents.
    416   const NSUInteger descriptionLocation =
    417       [decorated length] - [description length];
    418   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    419                                   NSForegroundColorAttributeName),
    420             descriptionLocation);
    421   EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation,
    422                                   NSForegroundColorAttributeName),
    423             [description length]);
    424 
    425   // Should have three font runs, not bold, bold, then not bold again.
    426   // The first run is the contents and the separator, the second run
    427   // is the first run of the description.
    428   EXPECT_EQ(RunLengthForAttribute(decorated, 0U,
    429                                   NSFontAttributeName), descriptionLocation);
    430   EXPECT_FALSE(RunHasFontTrait(decorated, 0U, NSBoldFontMask));
    431 
    432   EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation,
    433                                   NSFontAttributeName), runLength1);
    434   EXPECT_TRUE(RunHasFontTrait(decorated, descriptionLocation, NSBoldFontMask));
    435 
    436   EXPECT_EQ(RunLengthForAttribute(decorated, descriptionLocation + runLength1,
    437                                   NSFontAttributeName), runLength2);
    438   EXPECT_FALSE(RunHasFontTrait(decorated, descriptionLocation + runLength1,
    439                                NSBoldFontMask));
    440 }
    441 
    442 TEST_F(AutocompletePopupViewMacTest, ElideString) {
    443   NSString* const contents = @"This is a test with long contents";
    444   const string16 contents16(base::SysNSStringToUTF16(contents));
    445 
    446   const float kWide = 1000.0;
    447   const float kNarrow = 20.0;
    448 
    449   NSDictionary* attributes =
    450       [NSDictionary dictionaryWithObject:font_.GetNativeFont()
    451                                   forKey:NSFontAttributeName];
    452   scoped_nsobject<NSMutableAttributedString> as(
    453       [[NSMutableAttributedString alloc] initWithString:contents
    454                                              attributes:attributes]);
    455 
    456   // Nothing happens if the space is really wide.
    457   NSMutableAttributedString* ret =
    458       AutocompletePopupViewMac::ElideString(as, contents16, font_, kWide);
    459   EXPECT_TRUE(ret == as);
    460   EXPECT_TRUE([[as string] isEqualToString:contents]);
    461 
    462   // When elided, result is the same as ElideText().
    463   ret = AutocompletePopupViewMac::ElideString(as, contents16, font_, kNarrow);
    464   string16 elided = ui::ElideText(contents16, font_, kNarrow, false);
    465   EXPECT_TRUE(ret == as);
    466   EXPECT_FALSE([[as string] isEqualToString:contents]);
    467   EXPECT_TRUE([[as string] isEqualToString:base::SysUTF16ToNSString(elided)]);
    468 
    469   // When elided, result is the same as ElideText().
    470   ret = AutocompletePopupViewMac::ElideString(as, contents16, font_, 0.0);
    471   elided = ui::ElideText(contents16, font_, 0.0, false);
    472   EXPECT_TRUE(ret == as);
    473   EXPECT_FALSE([[as string] isEqualToString:contents]);
    474   EXPECT_TRUE([[as string] isEqualToString:base::SysUTF16ToNSString(elided)]);
    475 }
    476 
    477 TEST_F(AutocompletePopupViewMacTest, MatchTextElide) {
    478   NSString* const contents = @"This is a test with long contents";
    479   NSString* const description = @"That was a test";
    480   // Match "long".
    481   const NSUInteger runLength1 = 20, runLength2 = 4, runLength3 = 9;
    482   // Make sure nobody messed up the inputs.
    483   EXPECT_EQ(runLength1 + runLength2 + runLength3, [contents length]);
    484 
    485   AutocompleteMatch m = MakeMatch(base::SysNSStringToUTF16(contents),
    486                                   base::SysNSStringToUTF16(description));
    487 
    488   // Push each run onto contents classifications.
    489   m.contents_class.push_back(
    490       ACMatchClassification(0, ACMatchClassification::NONE));
    491   m.contents_class.push_back(
    492       ACMatchClassification(runLength1, ACMatchClassification::MATCH));
    493   m.contents_class.push_back(
    494       ACMatchClassification(runLength1 + runLength2,
    495                             ACMatchClassification::URL));
    496 
    497   // Figure out the width of the contents.
    498   NSDictionary* attributes =
    499       [NSDictionary dictionaryWithObject:font_.GetNativeFont()
    500                                   forKey:NSFontAttributeName];
    501   const float contentsWidth = [contents sizeWithAttributes:attributes].width;
    502 
    503   // After accounting for the width of the image, this will force us
    504   // to elide the contents.
    505   float cellWidth = ceil(contentsWidth / 0.7);
    506 
    507   NSAttributedString* decorated =
    508       AutocompletePopupViewMac::MatchText(m, font_, cellWidth);
    509 
    510   // Results contain a prefix of the contents and all of description.
    511   NSString* commonPrefix =
    512       [[decorated string] commonPrefixWithString:contents options:0];
    513   EXPECT_GT([commonPrefix length], 0U);
    514   EXPECT_LT([commonPrefix length], [contents length]);
    515   EXPECT_TRUE([[decorated string] hasSuffix:description]);
    516 
    517   // At one point the code had a bug where elided text was being
    518   // marked up using pre-elided offsets, resulting in out-of-range
    519   // values being passed to NSAttributedString.  Push the ellipsis
    520   // through part of each run to verify that we don't continue to see
    521   // such things.
    522   while([commonPrefix length] > runLength1 - 3) {
    523     EXPECT_GT(cellWidth, 0.0);
    524     cellWidth -= 1.0;
    525     decorated = AutocompletePopupViewMac::MatchText(m, font_, cellWidth);
    526     commonPrefix =
    527         [[decorated string] commonPrefixWithString:contents options:0];
    528     ASSERT_GT([commonPrefix length], 0U);
    529   }
    530 }
    531 
    532 // TODO(shess): Test that
    533 // AutocompletePopupViewMac::UpdatePopupAppearance() creates/destroys
    534 // the popup according to result contents.  Test that the matrix gets
    535 // the right number of results.  Test the contents of the cells for
    536 // the right strings.  Icons?  Maybe, that seems harder to test.
    537 // Styling seems almost impossible.
    538 
    539 // TODO(shess): Test that AutocompletePopupViewMac::PaintUpdatesNow()
    540 // updates the matrix selection.
    541 
    542 // TODO(shess): Test that AutocompletePopupViewMac::AcceptInput()
    543 // updates the model's selection from the matrix before returning.
    544 // Could possibly test that via -select:.
    545 
    546 // TODO(shess): Test that AutocompleteButtonCell returns the right
    547 // background colors for on, highlighted, and neither.
    548 
    549 // TODO(shess): Test that AutocompleteMatrixTarget can be initialized
    550 // and then sends -select: to the view.
    551 
    552 }  // namespace
    553