Index: ios/chrome/browser/ui/util/text_region_mapper_unittest.mm |
diff --git a/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm b/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ab3de525282b80a22b1aaebf8ec50071bba5642e |
--- /dev/null |
+++ b/ios/chrome/browser/ui/util/text_region_mapper_unittest.mm |
@@ -0,0 +1,144 @@ |
+// 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 <UIKit/UIKit.h> |
+ |
+#include "base/mac/foundation_util.h" |
+#include "base/mac/scoped_nsobject.h" |
+#include "ios/chrome/browser/ui/util/text_region_mapper.h" |
+#import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "testing/gtest_mac.h" |
+#include "testing/platform_test.h" |
+ |
+namespace { |
+class TextRegionMapperTest : public PlatformTest { |
+ protected: |
+ void SetUp() override { |
+ _string.reset(); |
+ _textMapper.reset(); |
+ } |
+ |
+ void InitMapper(NSAttributedString* string, CGRect bounds) { |
+ _string.reset([string copy]); |
+ _textMapper.reset([[CoreTextRegionMapper alloc] |
+ initWithAttributedString:_string |
+ bounds:bounds]); |
+ } |
+ |
+ CGRect RectAtIndex(NSArray* array, NSUInteger index) { |
+ NSValue* value = base::mac::ObjCCastStrict<NSValue>(array[index]); |
+ return [value CGRectValue]; |
+ } |
+ |
+ NSDictionary* AttributesForTextAlignment(NSTextAlignment alignment) { |
+ base::scoped_nsobject<NSMutableParagraphStyle> style; |
+ style.reset([[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy]); |
+ [style setAlignment:alignment]; |
+ return @{NSParagraphStyleAttributeName : style}; |
+ } |
+ |
+ base::scoped_nsobject<NSAttributedString> _string; |
+ base::scoped_nsobject<CoreTextRegionMapper> _textMapper; |
+}; |
+} |
+ |
+TEST_F(TextRegionMapperTest, SimpleTextTest) { |
+ CGRect bounds = CGRectMake(0, 0, 500, 100); |
+ base::scoped_nsobject<NSString> string(@"Simple Test"); |
+ InitMapper([[NSAttributedString alloc] initWithString:string], bounds); |
+ |
+ // Simple case: a single word in a string in a large bounding rect. |
+ // Rect bounding word should be inside bounding rect, and should be |
+ // wider than it is tall. |
+ NSRange range = NSMakeRange(0, 6); // "Simple". |
+ NSArray* rects = [_textMapper rectsForRange:range]; |
+ ASSERT_EQ(1UL, [rects count]); |
+ CGRect rect = RectAtIndex(rects, 0); |
+ EXPECT_TRUE(CGRectContainsRect(bounds, rect)); |
+ EXPECT_GT(CGRectGetWidth(rect), CGRectGetHeight(rect)); |
+ |
+ // Range that ends at end of string still generates a rect. |
+ range = NSMakeRange(9, 2); |
+ rects = [_textMapper rectsForRange:range]; |
+ ASSERT_EQ(1UL, [rects count]); |
+ rect = RectAtIndex(rects, 0); |
+ EXPECT_TRUE(CGRectContainsRect(bounds, rect)); |
+ |
+ // Simple null cases: range of zero length, range outside of string. |
+ range = NSMakeRange(6, 0); |
+ rects = [_textMapper rectsForRange:range]; |
+ EXPECT_EQ(0UL, [rects count]) << "Range has length 0."; |
+ |
+ range = NSMakeRange([_string length] + 1, 5); |
+ rects = [_textMapper rectsForRange:range]; |
+ EXPECT_EQ(0UL, [rects count]) << "Range starts beyond string."; |
+ |
+ range = NSMakeRange([_string length] - 2, 3); |
+ rects = [_textMapper rectsForRange:range]; |
+ EXPECT_EQ(0UL, [rects count]) << "Range ends beyond string."; |
+} |
+ |
+TEST_F(TextRegionMapperTest, TextAlignmentTest) { |
+ CGRect bounds = CGRectMake(0, 0, 500, 100); |
+ base::scoped_nsobject<NSAttributedString> string; |
+ string.reset([[NSAttributedString alloc] |
+ initWithString:@"Simple Test" |
+ attributes:AttributesForTextAlignment(NSTextAlignmentLeft)]); |
+ InitMapper(string, bounds); |
+ |
+ // First word of left-aligned string should at the left edge of the bounds. |
+ NSRange range = NSMakeRange(0, 6); // "Simple". |
+ NSArray* rects = [_textMapper rectsForRange:range]; |
+ ASSERT_EQ(1UL, [rects count]); |
+ CGRect rect = RectAtIndex(rects, 0); |
+ EXPECT_TRUE(CGRectContainsRect(bounds, rect)); |
+ EXPECT_GT(CGRectGetWidth(rect), CGRectGetHeight(rect)); |
+ EXPECT_EQ(CGRectGetMinX(rect), CGRectGetMinX(bounds)); |
+ |
+ string.reset([[NSAttributedString alloc] |
+ initWithString:@"Simple Test" |
+ attributes:AttributesForTextAlignment(NSTextAlignmentRight)]); |
+ InitMapper(string, bounds); |
+ |
+ // Last word of right-aligned string should at the right edge of the bounds. |
+ range = NSMakeRange(6, 5); // "Test". |
+ rects = [_textMapper rectsForRange:range]; |
+ ASSERT_EQ(1UL, [rects count]); |
+ rect = RectAtIndex(rects, 0); |
+ EXPECT_TRUE(CGRectContainsRect(bounds, rect)); |
+ EXPECT_GT(CGRectGetWidth(rect), CGRectGetHeight(rect)); |
+ EXPECT_EQ(CGRectGetMaxX(rect), CGRectGetMaxX(bounds)); |
+} |
+ |
+TEST_F(TextRegionMapperTest, CJKTest) { |
+ CGRect bounds = CGRectMake(0, 0, 345, 65); |
+ // clang-format off |
+ base::scoped_nsobject<NSString> CJKString( |
+ @"“触摸搜索”会将所选字词和当前页面(作为上下文)一起发送给 Google 搜索。" |
+ @"您可以在设置中停用此功能。"); |
+ // clang-format on |
+ base::scoped_nsobject<NSMutableDictionary> attributes([[NSMutableDictionary |
+ dictionaryWithDictionary:AttributesForTextAlignment(NSTextAlignmentLeft)] |
+ retain]); |
+ attributes.get()[NSFontAttributeName] = |
+ [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16]; |
+ base::scoped_nsobject<NSAttributedString> string([[NSAttributedString alloc] |
+ initWithString:CJKString |
+ attributes:attributes]); |
+ InitMapper(string, bounds); |
+ |
+ NSRange range = NSMakeRange(0, 6); // "“触摸搜索”". |
+ NSArray* rects = [_textMapper rectsForRange:range]; |
+ ASSERT_EQ(1UL, [rects count]); |
+} |
+ |
+/* |
+ Further unit tests should cover additional cases: |
+ - In several languages. |
+ - Range split across line break == two rects |
+ - Bidi text with text range across scripts gets two rects. |
+ - Various string attributions. |
+ - Isolate buggy CoreText case. |
+*/ |