blob: be9e5b3c1077428e5b83518882998201f8e9e147 [file] [log] [blame]
// Copyright 2015 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.
#import "ios/chrome/browser/ui/util/label_link_controller.h"
#include "ios/chrome/browser/ui/util/text_region_mapper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// A simple text region mapper that just returns the mapped bounds for
// any range.
@interface SimpleTextRegionMapper : NSObject<TextRegionMapper>
@end
@implementation SimpleTextRegionMapper {
CGRect _bounds;
}
- (instancetype)initWithAttributedString:(NSAttributedString*)string
bounds:(CGRect)bounds {
if ((self = [super init])) {
_bounds = bounds;
}
return self;
}
- (NSArray*)rectsForRange:(NSRange)range {
return @[ [NSValue valueWithCGRect:_bounds] ];
}
@end
#define EXPECT_UICOLOR_EQ(A, B) EXPECT_NSEQ([A description], [B description])
namespace {
class LabelLinkControllerTest : public PlatformTest {
protected:
LabelLinkControllerTest() {
label_container_ = [[UIView alloc] initWithFrame:CGRectZero];
label_ = [[UILabel alloc] initWithFrame:CGRectZero];
[label_container_ addSubview:label_];
}
void setLabelAttrString(NSString* str) {
str_ = [[NSAttributedString alloc] initWithString:str];
[label_ setAttributedText:str_];
}
void setLabelAttrStringWithAttr(NSString* str, NSString* attr, id value) {
str_ = [[NSAttributedString alloc] initWithString:str
attributes:@{attr : value}];
[label_ setAttributedText:str_];
}
UIView* label_container_;
UILabel* label_;
NSAttributedString* str_;
};
TEST_F(LabelLinkControllerTest, TapTest) {
setLabelAttrString(@"link tap test");
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(5, 3); // "tap".
GURL url = GURL("http://www.google.com");
__block NSInteger taps = 0;
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_
action:^(const GURL& tappedUrl) {
EXPECT_EQ(tappedUrl, url);
taps++;
}];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
CGRect rect = [rects[0] CGRectValue];
CGPoint tapPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
[llc tapLabelAtPoint:tapPoint];
EXPECT_EQ(1, taps);
}
TEST_F(LabelLinkControllerTest, LinkColorTest) {
setLabelAttrStringWithAttr(@"link color test", NSForegroundColorAttributeName,
[UIColor blueColor]);
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(5, 5); // "color".
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
[llc addLinkWithRange:linkRange url:GURL("http://www.google.com")];
// That shouldn't have changed the label's attributes.
NSDictionary* attrs =
[[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_UICOLOR_EQ(attrs[NSForegroundColorAttributeName], [UIColor blueColor]);
[llc setLinkColor:[UIColor redColor]];
// That should only change the attributes at the link location
attrs = [[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_UICOLOR_EQ(attrs[NSForegroundColorAttributeName], [UIColor redColor]);
attrs = [[label_ attributedText] attributesAtIndex:0 effectiveRange:nullptr];
EXPECT_UICOLOR_EQ(attrs[NSForegroundColorAttributeName], [UIColor blueColor]);
[llc setLinkColor:[UIColor yellowColor]];
// There shouldn't be a red foreground color attribute any more.
attrs = [[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_UICOLOR_EQ(attrs[NSForegroundColorAttributeName],
[UIColor yellowColor]);
}
TEST_F(LabelLinkControllerTest, LinkUnderlineTest) {
setLabelAttrStringWithAttr(@"link underline test",
NSUnderlineStyleAttributeName,
@(NSUnderlineStyleSingle));
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(5, 9); // "underline".
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
[llc addLinkWithRange:linkRange url:GURL("http://www.google.com")];
// That shouldn't have changed the label's attributes.
NSDictionary* attrs =
[[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_NSEQ(attrs[NSUnderlineStyleAttributeName], @(NSUnderlineStyleSingle));
[llc setLinkUnderlineStyle:NSUnderlineStyleDouble];
// That should only change the attributes at the link location
attrs = [[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_NSEQ(attrs[NSUnderlineStyleAttributeName], @(NSUnderlineStyleDouble));
attrs = [[label_ attributedText] attributesAtIndex:0 effectiveRange:nullptr];
EXPECT_NSEQ(attrs[NSUnderlineStyleAttributeName], @(NSUnderlineStyleSingle));
[llc setLinkUnderlineStyle:NSUnderlineStyleThick];
// There shouldn't be a red foreground color attribute any more.
attrs = [[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_NSEQ(attrs[NSUnderlineStyleAttributeName], @(NSUnderlineStyleThick));
[llc setLinkUnderlineStyle:NSUnderlineStyleNone];
// Should see the underlying underline style.
attrs = [[label_ attributedText] attributesAtIndex:linkRange.location
effectiveRange:nullptr];
EXPECT_NSEQ(attrs[NSUnderlineStyleAttributeName], @(NSUnderlineStyleSingle));
}
TEST_F(LabelLinkControllerTest, BoundsChangeTest) {
setLabelAttrString(@"bounds change test");
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(7, 6); // "change".
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
GURL url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
NSValue* rect = rects[0];
EXPECT_TRUE(CGRectContainsRect([rect CGRectValue], [label_ bounds]));
// Change the label bounds, expect the links to be recomputed.
// (SimpleTextRegionMapper just maps all ranges to the label bounds).
CGRect newFrame = CGRectMake(0, 0, 200, 200);
[label_ setFrame:newFrame];
rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
NSValue* newRect = rects[0];
EXPECT_NSNE(rect, newRect);
EXPECT_TRUE(CGRectContainsRect([newRect CGRectValue], newFrame));
}
TEST_F(LabelLinkControllerTest, AttributedTextChangeTest) {
setLabelAttrString(@"attributed text change test");
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(16, 6); // "change".
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
GURL url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
EXPECT_EQ(1UL, [rects count]);
setLabelAttrString(@"crazy new attributed text");
// Expect all links to be gone.
rects = [llc tapRectsForURL:url];
EXPECT_EQ(0UL, [rects count]);
}
TEST_F(LabelLinkControllerTest, TextChangeTest) {
[label_ setText:@"text change test"];
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(5, 6); // "change".
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
[llc setTextMapperClass:[SimpleTextRegionMapper class]];
GURL url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
EXPECT_EQ(1UL, [rects count]);
[label_ setText:@"crazy new text"];
// Expect all links to be gone.
rects = [llc tapRectsForURL:url];
EXPECT_EQ(0UL, [rects count]);
}
TEST_F(LabelLinkControllerTest, LabelStyleInitTest) {
[label_ setText:@"style init test"];
[label_ sizeToFit];
NSRange linkRange = NSMakeRange(6, 5); // "init".
// Don't use an injected text mapper for this test.
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
GURL url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
CGRect linkRect = [rects[0] CGRectValue];
// Make a new label and controller with a very large font size, and
// compute the same tap rect. It should be different from the rect computed
// above.
label_ = [[UILabel alloc] initWithFrame:CGRectZero];
[label_ setText:@"style init test"];
[label_ setFont:[UIFont systemFontOfSize:40]];
[label_ sizeToFit];
llc = [[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
CGRect newLinkRect = [rects[0] CGRectValue];
EXPECT_NSNE(NSStringFromCGRect(linkRect), NSStringFromCGRect(newLinkRect));
}
TEST_F(LabelLinkControllerTest, LabelStylePropertyChangeTest) {
[label_ setText:@"style change test"];
// Choose a size large enough so that the full text can be laid out with both
// fonts in this test.
CGSize labelSize = CGSizeMake(400, 50);
[label_ setFrame:{CGPointZero, labelSize}];
NSRange linkRange = NSMakeRange(6, 6); // "change".
// Don't use an injected text mapper for this test.
LabelLinkController* llc =
[[LabelLinkController alloc] initWithLabel:label_ action:nullptr];
GURL url = GURL("http://www.google.com");
[llc addLinkWithRange:linkRange url:url];
NSArray* rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
NSValue* smallTextRect = rects[0];
[label_ setFont:[UIFont systemFontOfSize:40]];
// Expect all links to be changed.
rects = [llc tapRectsForURL:url];
ASSERT_EQ(1UL, [rects count]);
EXPECT_NSNE(smallTextRect, rects[0]);
}
} // namespace