ComponentTextKitApplicationTests/CKTextKitTests.mm (119 lines of code) (raw):

/* * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #import <XCTest/XCTest.h> #import <FBSnapshotTestCase/FBSnapshotTestController.h> #import <ComponentTextKit/CKTextKitEntityAttribute.h> #import <ComponentTextKit/CKTextKitAttributes.h> #import <ComponentTextKit/CKTextKitRenderer.h> #import <ComponentTextKit/CKTextKitRenderer+Positioning.h> @interface CKTextKitTests : XCTestCase @end static UITextView *UITextViewWithAttributes(const CKTextKitAttributes &attributes, const CGSize constrainedSize) { UITextView *textView = [[UITextView alloc] initWithFrame:{ .size = constrainedSize }]; textView.backgroundColor = [UIColor clearColor]; textView.textContainer.lineBreakMode = attributes.lineBreakMode; textView.textContainer.lineFragmentPadding = 0.f; textView.textContainer.maximumNumberOfLines = attributes.maximumNumberOfLines; textView.textContainerInset = UIEdgeInsetsZero; textView.layoutManager.usesFontLeading = NO; textView.attributedText = attributes.attributedString; return textView; } static UIImage *UITextViewImageWithAttributes(const CKTextKitAttributes &attributes, const CGSize constrainedSize) { UITextView *textView = UITextViewWithAttributes(attributes, constrainedSize); UIGraphicsBeginImageContextWithOptions(constrainedSize, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); { [textView.layer renderInContext:context]; } CGContextRestoreGState(context); UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return snapshot; } static UIImage *CKTextKitImageWithAttributes(const CKTextKitAttributes &attributes, const CGSize constrainedSize) { CKTextKitRenderer *renderer = [[CKTextKitRenderer alloc] initWithTextKitAttributes:attributes constrainedSize:constrainedSize]; UIGraphicsBeginImageContextWithOptions(constrainedSize, NO, 0); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); { [renderer drawInContext:context bounds:{.size = constrainedSize}]; } CGContextRestoreGState(context); UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return snapshot; } static BOOL checkAttributes(const CKTextKitAttributes &attributes, const CGSize constrainedSize) { FBSnapshotTestController *controller = [[FBSnapshotTestController alloc] init]; UIImage *labelImage = UITextViewImageWithAttributes(attributes, constrainedSize); UIImage *textKitImage = CKTextKitImageWithAttributes(attributes, constrainedSize); return [controller compareReferenceImage:labelImage toImage:textKitImage tolerance:0 error:nil]; } @implementation CKTextKitTests - (void)testSimpleStrings { CKTextKitAttributes attributes { .attributedString = [[NSAttributedString alloc] initWithString:@"hello" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}] }; XCTAssert(checkAttributes(attributes, { 100, 100 })); } - (void)testChangingAPropertyChangesHash { NSAttributedString *as = [[NSAttributedString alloc] initWithString:@"hello" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}]; CKTextKitAttributes attrib1 { .attributedString = as, .lineBreakMode = NSLineBreakByClipping, }; CKTextKitAttributes attrib2 { .attributedString = as, }; XCTAssertNotEqual(attrib1.hash(), attrib2.hash(), @"Hashes should differ when NSLineBreakByClipping changes."); } - (void)testSameStringHashesSame { CKTextKitAttributes attrib1 { .attributedString = [[NSAttributedString alloc] initWithString:@"hello" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}], }; CKTextKitAttributes attrib2 { .attributedString = [[NSAttributedString alloc] initWithString:@"hello" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}], }; XCTAssertEqual(attrib1.hash(), attrib2.hash(), @"Hashes should be the same!"); } - (void)testStringsWithVariableAttributes { NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:@"hello" attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:12]}]; for (int i = 0; i < attrStr.length; i++) { // Color each character something different CGFloat factor = ((CGFloat)i) / ((CGFloat)attrStr.length); [attrStr addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithRed:factor green:1.0 - factor blue:0.0 alpha:1.0] range:NSMakeRange(i, 1)]; } CKTextKitAttributes attributes { .attributedString = attrStr }; XCTAssert(checkAttributes(attributes, { 100, 100 })); } - (void)testRectsForRangeBeyondTruncationSizeReturnsNonZeroNumberOfRects { NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:@"90's cray photo booth tote bag bespoke Carles. Plaid wayfarers Odd Future master cleanse tattooed four dollar toast small batch kale chips leggings meh photo booth occupy irony. " attributes:@{CKTextKitEntityAttributeName : [[CKTextKitEntityAttribute alloc] initWithEntity:@"entity"]}]; CKTextKitRenderer *renderer = [[CKTextKitRenderer alloc] initWithTextKitAttributes:{ .attributedString = attributedString, .maximumNumberOfLines = 1, .truncationAttributedString = [[NSAttributedString alloc] initWithString:@"... Continue Reading"] } constrainedSize:{ 100, 100 }]; XCTAssert([renderer rectsForTextRange:NSMakeRange(0, attributedString.length) measureOption:CKTextKitRendererMeasureOptionBlock].count > 0); } @end