From 5c42bb4e2f2424f09097a461ffbaa53cc3e21695 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Fri, 2 Sep 2016 15:10:15 -0700 Subject: [PATCH] Add tests to confirm CALayer behaviors (#2184) --- AsyncDisplayKit.xcodeproj/project.pbxproj | 4 + .../xcschemes/AsyncDisplayKit.xcscheme | 3 + AsyncDisplayKitTests/ASCALayerTests.m | 107 ++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 AsyncDisplayKitTests/ASCALayerTests.m diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 8789f8b46..2e29d8a42 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -410,6 +410,7 @@ B350625E1B0111780018CF92 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051943121A1575630030A7D0 /* AssetsLibrary.framework */; }; B350625F1B0111800018CF92 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 058D09AF195D04C000B7D73C /* Foundation.framework */; }; C78F7E2B1BF7809800CDEAFC /* ASTableNode.h in Headers */ = {isa = PBXBuildFile; fileRef = B0F880581BEAEC7500D17647 /* ASTableNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CC051F1F1D7A286A006434CB /* ASCALayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC051F1E1D7A286A006434CB /* ASCALayerTests.m */; }; CC0AEEA41D66316E005D1C78 /* ASUICollectionViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.m */; }; CC3B20841C3F76D600798563 /* ASPendingStateController.h in Headers */ = {isa = PBXBuildFile; fileRef = CC3B20811C3F76D600798563 /* ASPendingStateController.h */; }; CC3B20851C3F76D600798563 /* ASPendingStateController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B20821C3F76D600798563 /* ASPendingStateController.mm */; }; @@ -1089,6 +1090,7 @@ B35061DA1B010EDF0018CF92 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B35061DD1B010EDF0018CF92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = "../AsyncDisplayKit-iOS/Info.plist"; sourceTree = ""; }; BDC2D162BD55A807C1475DA5 /* Pods-AsyncDisplayKitTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.profile.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.profile.xcconfig"; sourceTree = ""; }; + CC051F1E1D7A286A006434CB /* ASCALayerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCALayerTests.m; sourceTree = ""; }; CC0AEEA31D66316E005D1C78 /* ASUICollectionViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASUICollectionViewTests.m; sourceTree = ""; }; CC3B20811C3F76D600798563 /* ASPendingStateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASPendingStateController.h; sourceTree = ""; }; CC3B20821C3F76D600798563 /* ASPendingStateController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPendingStateController.mm; sourceTree = ""; }; @@ -1343,6 +1345,7 @@ 058D09C5195D04C000B7D73C /* AsyncDisplayKitTests */ = { isa = PBXGroup; children = ( + CC051F1E1D7A286A006434CB /* ASCALayerTests.m */, CC8B05D71D73979700F54286 /* ASTextNodePerformanceTests.m */, CC8B05D41D73836400F54286 /* ASPerformanceTestContext.h */, CC8B05D51D73836400F54286 /* ASPerformanceTestContext.m */, @@ -2203,6 +2206,7 @@ buildActionMask = 2147483647; files = ( 29CDC2E21AAE70D000833CA4 /* ASBasicImageDownloaderContextTests.m in Sources */, + CC051F1F1D7A286A006434CB /* ASCALayerTests.m in Sources */, 242995D31B29743C00090100 /* ASBasicImageDownloaderTests.m in Sources */, 296A0A351A951ABF005ACEAA /* ASBatchFetchingTests.m in Sources */, ACF6ED5C1B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm in Sources */, diff --git a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme index a9347f2fa..3b750e491 100644 --- a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme +++ b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme @@ -56,6 +56,9 @@ + + diff --git a/AsyncDisplayKitTests/ASCALayerTests.m b/AsyncDisplayKitTests/ASCALayerTests.m new file mode 100644 index 000000000..d52d6ec30 --- /dev/null +++ b/AsyncDisplayKitTests/ASCALayerTests.m @@ -0,0 +1,107 @@ +// +// ASCALayerTests.m +// AsyncDisplayKit +// +// Created by Adlai Holler on 9/2/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +#import +#import + +/** + * Tests that confirm what we know about Core Animation behavior. + * + * These tests are not run during the normal test action. You can run them yourself + * to investigate and confirm CA behavior. + */ +@interface ASCALayerTests : XCTestCase + +@end + +#define DeclareLayerAndSublayer() \ + CALayer *realSublayer = [CALayer layer]; \ + id layer = [OCMockObject partialMockForObject:[CALayer layer]]; \ + id sublayer = [OCMockObject partialMockForObject:realSublayer]; \ + [layer addSublayer:realSublayer]; + +@implementation ASCALayerTests + +- (void)testThatLayerBeginsWithCleanLayout +{ + XCTAssertFalse([CALayer layer].needsLayout); +} + +- (void)testThatAddingSublayersDirtysLayout +{ + CALayer *layer = [CALayer layer]; + [layer addSublayer:[CALayer layer]]; + XCTAssertTrue([layer needsLayout]); +} + +- (void)testThatRemovingSublayersDirtysLayout +{ + DeclareLayerAndSublayer(); + [layer layoutIfNeeded]; + XCTAssertFalse([layer needsLayout]); + [sublayer removeFromSuperlayer]; + XCTAssertTrue([layer needsLayout]); +} + +- (void)testDirtySublayerLayoutDoesntDirtySuperlayer +{ + DeclareLayerAndSublayer(); + [layer layoutIfNeeded]; + + // Dirtying sublayer doesn't dirty superlayer. + [sublayer setNeedsLayout]; + XCTAssertTrue([sublayer needsLayout]); + XCTAssertFalse([layer needsLayout]); + [[[sublayer expect] andForwardToRealObject] layoutSublayers]; + // NOTE: We specifically don't expect layer to get -layoutSublayers + [sublayer layoutIfNeeded]; + [sublayer verify]; + [layer verify]; +} + +- (void)testDirtySuperlayerLayoutDoesntDirtySublayerLayout +{ + DeclareLayerAndSublayer(); + [layer layoutIfNeeded]; + + // Dirtying superlayer doesn't dirty sublayer. + [layer setNeedsLayout]; + XCTAssertTrue([layer needsLayout]); + XCTAssertFalse([sublayer needsLayout]); + [[[layer expect] andForwardToRealObject] layoutSublayers]; + // NOTE: We specifically don't expect sublayer to get -layoutSublayers + [layer layoutIfNeeded]; + [sublayer verify]; + [layer verify]; +} + +- (void)testDirtyHierarchyIsLaidOutTopDown +{ + DeclareLayerAndSublayer(); + [sublayer setNeedsLayout]; + + XCTAssertTrue([layer needsLayout]); + XCTAssertTrue([sublayer needsLayout]); + + __block BOOL superlayerLaidOut = NO; + [[[[layer expect] andDo:^(NSInvocation *i) { + superlayerLaidOut = YES; + }] andForwardToRealObject] layoutSublayers]; + + [[[[sublayer expect] andDo:^(NSInvocation *i) { + XCTAssertTrue(superlayerLaidOut); + }] andForwardToRealObject] layoutSublayers]; + + [layer layoutIfNeeded]; + [sublayer verify]; + [layer verify]; +} + +@end