ComponentKitTests/CKAnimationTests.mm (539 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 <array> #import <ComponentKit/CKCasting.h> #import <ComponentKit/CKAnimation.h> #import <ComponentKit/ComponentUtilities.h> using namespace CK; using namespace CK::Animation; template <size_t N> static auto checkKeyPathsForAnimations(XCTestCase *self, const std::array<CAPropertyAnimation *, N> &animations, const std::array<const char *, N> &expectedKeyPaths) { for (auto i = 0; i < N; ++i) { XCTAssertEqualObjects(animations[i].keyPath, @(expectedKeyPaths[i])); } } @interface CKAnimationTests_KeyPaths : XCTestCase @end @implementation CKAnimationTests_KeyPaths - (void)testInitialAnimationsKeyPaths { auto const animations = std::array<CAPropertyAnimation *, 4>{ objCForceCast<CAPropertyAnimation>(alphaFrom(0).toCA()), objCForceCast<CAPropertyAnimation>(translationYFrom(0).toCA()), objCForceCast<CAPropertyAnimation>(backgroundColorFrom(UIColor.blackColor).toCA()), objCForceCast<CAPropertyAnimation>(borderColorFrom(UIColor.blackColor).toCA()), }; auto const expectedKeyPaths = std::array<const char *, 4>{ "opacity", "transform.translation.y", "backgroundColor", "borderColor" }; checkKeyPathsForAnimations(self, animations, expectedKeyPaths); } - (void)testFinalAnimationsKeyPaths { auto const animations = std::array<CAPropertyAnimation *, 4>{ objCForceCast<CAPropertyAnimation>(alphaTo(0).toCA()), objCForceCast<CAPropertyAnimation>(translationYTo(0).toCA()), objCForceCast<CAPropertyAnimation>(backgroundColorTo(UIColor.blackColor).toCA()), objCForceCast<CAPropertyAnimation>(borderColorTo(UIColor.blackColor).toCA()), }; auto const expectedKeyPaths = std::array<const char *, 4>{ "opacity", "transform.translation.y", "backgroundColor", "borderColor" }; checkKeyPathsForAnimations(self, animations, expectedKeyPaths); } - (void)testChangeAnimationsKeyPaths { auto const animations = std::array<CAPropertyAnimation *, 4>{ objCForceCast<CAPropertyAnimation>(alpha().toCA()), objCForceCast<CAPropertyAnimation>(backgroundColor().toCA()), objCForceCast<CAPropertyAnimation>(borderColor().toCA()), objCForceCast<CAPropertyAnimation>(position().toCA()), }; auto const expectedKeyPaths = std::array<const char *, 4>{ "opacity", "backgroundColor", "borderColor", "position" }; checkKeyPathsForAnimations(self, animations, expectedKeyPaths); } @end @interface CKAnimationTests_Initial: XCTestCase @end @implementation CKAnimationTests_Initial - (void)testSettingScalarFromValue { auto a = objCForceCast<CABasicAnimation>(alphaFrom(0).toCA()); XCTAssertEqualObjects(a.fromValue, @(0)); } - (void)testSettingUIColorFromValueForInitialAnimation { auto a = objCForceCast<CABasicAnimation>(backgroundColorFrom(UIColor.blueColor).toCA()); XCTAssertEqualObjects(a.fromValue, (id)UIColor.blueColor.CGColor); } - (void)test_WhenDurationIsNotSet_ItIsZero { XCTAssertEqual(alphaFrom(0).toCA().duration, 0); XCTAssertEqual(backgroundColorFrom(UIColor.blackColor).toCA().duration, 0); } - (void)testSettingDuration { XCTAssertEqual(alphaFrom(0).withDuration(0.25).toCA().duration, 0.25); XCTAssertEqual(backgroundColorFrom(UIColor.blackColor).withDuration(0.25).toCA().duration, 0.25); } - (void)testSettingDelay { XCTAssertEqual(alphaFrom(0).withDelay(0.25).toCA().beginTime, 0.25); XCTAssertEqual(backgroundColorFrom(UIColor.blackColor).withDelay(0.25).toCA().beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(alphaFrom(0).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); XCTAssertEqualObjects(backgroundColorFrom(UIColor.blackColor).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(alphaFrom(0).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(backgroundColorFrom(UIColor.blackColor).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(alphaFrom(0).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); XCTAssertEqualObjects(backgroundColorFrom(UIColor.blackColor).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testSettingTimingFunctionWithDuration { auto a1 = alphaFrom(0).easeIn(0.25).toCA(); XCTAssertEqual(a1.duration, 0.25); XCTAssertEqualObjects(a1.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); auto a2 = backgroundColorFrom(UIColor.blackColor).easeIn(0.25).toCA(); XCTAssertEqual(a2.duration, 0.25); XCTAssertEqualObjects(a2.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); } - (void)testAlwaysUsesBackwardsFillMode { XCTAssertEqualObjects(alphaFrom(0).toCA().fillMode, kCAFillModeBackwards); XCTAssertEqualObjects(backgroundColorFrom(UIColor.blackColor).toCA().fillMode, kCAFillModeBackwards); } @end @interface CKAnimationTests_Final: XCTestCase @end @implementation CKAnimationTests_Final - (void)testSettingScalarToValueForFinalAnimation { auto a = objCForceCast<CABasicAnimation>(alphaTo(0).toCA()); XCTAssertEqualObjects(a.toValue, @(0)); } - (void)testSettingUIColorToValueForFinalAnimation { auto a = objCForceCast<CABasicAnimation>(backgroundColorTo(UIColor.blueColor).toCA()); XCTAssertEqualObjects(a.toValue, (id)UIColor.blueColor.CGColor); } - (void)test_WhenDurationIsNotSet_ItIsZero { XCTAssertEqual(alphaTo(0).toCA().duration, 0); XCTAssertEqual(backgroundColorTo(UIColor.blackColor).toCA().duration, 0); } - (void)testSettingDuration { XCTAssertEqual(alphaTo(0).withDuration(0.25).toCA().duration, 0.25); XCTAssertEqual(backgroundColorTo(UIColor.blackColor).withDuration(0.25).toCA().duration, 0.25); } - (void)testSettingDelay { XCTAssertEqual(alphaTo(0).withDelay(0.25).toCA().beginTime, 0.25); XCTAssertEqual(backgroundColorTo(UIColor.blackColor).withDelay(0.25).toCA().beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(alphaTo(0).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); XCTAssertEqualObjects(backgroundColorTo(UIColor.blackColor).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(alphaTo(0).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(backgroundColorTo(UIColor.blackColor).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(alphaTo(0).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); XCTAssertEqualObjects(backgroundColorTo(UIColor.blackColor).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testSettingTimingFunctionWithDuration { auto a1 = alphaTo(0).easeIn(0.25).toCA(); XCTAssertEqual(a1.duration, 0.25); XCTAssertEqualObjects(a1.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); auto a2 = backgroundColorTo(UIColor.blackColor).easeIn(0.25).toCA(); XCTAssertEqual(a2.duration, 0.25); XCTAssertEqualObjects(a2.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); } - (void)testAlwaysUsesForwardsFillMode { XCTAssertEqualObjects(alphaTo(0).toCA().fillMode, kCAFillModeForwards); XCTAssertEqualObjects(backgroundColorTo(UIColor.blackColor).toCA().fillMode, kCAFillModeForwards); } - (void)testIsNotRemovedOnCompletion { XCTAssertFalse(alphaTo(0).toCA().removedOnCompletion); } @end @interface CKAnimationTests_Change: XCTestCase @end @implementation CKAnimationTests_Change - (void)test_WhenDurationIsNotSet_ItIsZero { auto a = alpha().toCA(); XCTAssertEqual(a.duration, 0); } - (void)testSettingDuration { auto a = alpha().withDuration(0.25).toCA(); XCTAssertEqual(a.duration, 0.25); } - (void)testSettingDelay { auto a = alpha().withDelay(0.25).toCA(); XCTAssertEqual(a.beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(alpha().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(alpha().easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(alpha().easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testSettingTimingFunctionWithDuration { auto a = alpha().easeIn(0.25).toCA(); XCTAssertEqual(a.duration, 0.25); XCTAssertEqualObjects(a.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); } - (void)test_WhenDelayIsNotSet_UsesDefaultFillMode { XCTAssertEqualObjects(alpha().toCA().fillMode, kCAFillModeRemoved); } - (void)test_WhenDelayIsSet_UsesBackwardsFillMode { XCTAssertEqualObjects(alpha().withDelay(0.25).toCA().fillMode, kCAFillModeBackwards); } @end @interface CKAnimationTests_Parallel : XCTestCase @end @implementation CKAnimationTests_Parallel - (void)testComposingAnimations { auto group = objCForceCast<CAAnimationGroup>(parallel(alphaFrom(0), translationYFrom(0)).toCA()); XCTAssertEqual(group.animations.count, 2); auto a1 = objCForceCast<CAPropertyAnimation>(group.animations[0]); XCTAssertEqualObjects(a1.keyPath, @"opacity"); auto a2 = objCForceCast<CAPropertyAnimation>(group.animations[1]); XCTAssertEqualObjects(a2.keyPath, @"transform.translation.y"); } - (void)test_WhenDurationIsNotSet_ItIsZero { auto a = parallel(alphaFrom(0), translationYFrom(0)).toCA(); XCTAssertEqual(a.duration, 0); } - (void)testSettingDuration { auto a = parallel(alphaFrom(0), translationYFrom(0)).withDuration(0.25).toCA(); XCTAssertEqual(a.duration, 0.25); } - (void)testSettingDelay { auto a = parallel(alphaFrom(0), translationYFrom(0)).withDelay(0.25).toCA(); XCTAssertEqual(a.beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(parallel(alphaFrom(0), translationYFrom(0)).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(parallel(alphaFrom(0), translationYFrom(0)).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(parallel(alphaFrom(0), translationYFrom(0)).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testSettingCustomTimingFunction { auto const expectedFunc = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; auto const c = TimingCurve::fromCA(expectedFunc); auto const func = parallel(alphaFrom(0), translationYFrom(0)).timingCurve(c).toCA().timingFunction; XCTAssertEqualObjects(func, expectedFunc); } - (void)testSettingCustomTimingFunctionUsingControlPoints { auto const expectedPoint1 = TimingCurve::ControlPoint{0.14, 1.0}; auto const expectedPoint2 = TimingCurve::ControlPoint{0.34, 1.0}; auto const f = parallel(alphaFrom(0), translationYFrom(0)) .timingCurveWithControlPoints(expectedPoint1, expectedPoint2) .toCA() .timingFunction; TimingCurve::ControlPoint point1, point2; [f getControlPointAtIndex:1 values:point1.data()]; [f getControlPointAtIndex:2 values:point2.data()]; XCTAssert(point1 == expectedPoint1); XCTAssert(point2 == expectedPoint2); } - (void)testSettingTimingFunctionWithDuration { auto a = parallel(alphaFrom(0), translationYFrom(0)).easeIn(0.25).toCA(); XCTAssertEqual(a.duration, 0.25); XCTAssertEqualObjects(a.timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); } - (void)test_WhenComposingInitialAnimations_UsesBackwardsFillMode { auto a = parallel(alphaFrom(0), translationYFrom(0)).toCA(); XCTAssertEqualObjects(a.fillMode, kCAFillModeBackwards); } - (void)test_WhenComposingChangeAnimations_UsesBackwardsFillMode { auto a = parallel(alpha(), position()).toCA(); XCTAssertEqualObjects(a.fillMode, kCAFillModeBackwards); } - (void)test_WhenComposingFinalAnimations_UsesForwardsFillMode { auto a = parallel(alphaTo(0), translationYTo(0)).toCA(); XCTAssertEqualObjects(a.fillMode, kCAFillModeForwards); } - (void)test_WhenComposingFinalAnimations_NotRemovedOnCompletion { auto a = parallel(alphaTo(0), translationYTo(0)).toCA(); XCTAssertFalse(a.removedOnCompletion); } - (void)test_WhenDurationCannotBeSetExternally_DurationIsMaxDurationOfComposedAnimations { auto a = parallel(alpha().withDuration(0.5), sequence(position().withDuration(0.3), backgroundColor())).toCA(); auto const expected = 0.3 + 0.25; // Explicit for position + implicit for background color > 0.5 for alpha XCTAssertEqual(a.duration, expected); } @end @interface CKAnimationTests_Sequence : XCTestCase @end @implementation CKAnimationTests_Sequence - (void)testComposingAnimations { auto group = objCForceCast<CAAnimationGroup>(sequence(alphaFrom(0), translationYFrom(0)).toCA()); XCTAssertEqual(group.animations.count, 2); auto a1 = objCForceCast<CAPropertyAnimation>(group.animations[0]); XCTAssertEqualObjects(a1.keyPath, @"opacity"); auto a2 = objCForceCast<CAPropertyAnimation>(group.animations[1]); XCTAssertEqualObjects(a2.keyPath, @"transform.translation.y"); } - (void)testSecondAnimationStartsAfterFirst { auto group = objCForceCast<CAAnimationGroup>(sequence(alphaFrom(0), translationYFrom(0)).toCA()); XCTAssertEqual(group.animations.count, 2); auto a1 = objCForceCast<CAPropertyAnimation>(group.animations[0]); XCTAssertEqual(a1.beginTime, 0); auto a2 = objCForceCast<CAPropertyAnimation>(group.animations[1]); XCTAssertEqual(a2.beginTime, 0.25); } - (void)test_DurationIsEqualToSumOfComposedAnimationDurations { XCTAssertEqual(sequence(alphaFrom(0), translationYFrom(0)).toCA().duration, 0.5); XCTAssertEqual(sequence(alphaFrom(0).withDuration(0.5), translationYFrom(0)).toCA().duration, 0.75); XCTAssertEqual(sequence(alphaFrom(0), translationYFrom(0).withDuration(0.5)).toCA().duration, 0.75); } - (void)testSettingDelay { auto a = sequence(alphaFrom(0), translationYFrom(0)).withDelay(0.25).toCA(); XCTAssertEqual(a.beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(sequence(alphaFrom(0), translationYFrom(0)).toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(sequence(alphaFrom(0), translationYFrom(0)).easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(sequence(alphaFrom(0), translationYFrom(0)).easeOut().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testSettingCustomTimingFunction { auto const expectedFunc = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; auto const c = TimingCurve::fromCA(expectedFunc); auto const func = sequence(alphaFrom(0), translationYFrom(0)).timingCurve(c).toCA().timingFunction; XCTAssertEqualObjects(func, expectedFunc); } - (void)testSettingCustomTimingFunctionUsingControlPoints { auto const expectedPoint1 = TimingCurve::ControlPoint{0.14, 1.0}; auto const expectedPoint2 = TimingCurve::ControlPoint{0.34, 1.0}; auto const f = sequence(alphaFrom(0), translationYFrom(0)) .timingCurveWithControlPoints(expectedPoint1, expectedPoint2) .toCA() .timingFunction; TimingCurve::ControlPoint point1, point2; [f getControlPointAtIndex:1 values:point1.data()]; [f getControlPointAtIndex:2 values:point2.data()]; XCTAssert(point1 == expectedPoint1); XCTAssert(point2 == expectedPoint2); } - (void)test_WhenComposingInitialAnimations_UsesBackwardsFillMode { auto a = sequence(alphaFrom(0), translationYFrom(0)).toCA(); XCTAssertEqualObjects(a.fillMode, kCAFillModeBackwards); } @end @interface CKAnimationTests_SpringChange : XCTestCase @end @implementation CKAnimationTests_SpringChange - (void)testSpringBuilderBuildsSpringAnimation { XCTAssertEqualObjects(alpha().usingSpring().withDelay(0.25).toCA().class, [CASpringAnimation class]); } - (void)testChangeAnimationsKeyPaths { auto const animations = std::array<CAPropertyAnimation *, 4>{ objCForceCast<CAPropertyAnimation>(alpha().usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(backgroundColor().usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(borderColor().usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(position().usingSpring().toCA()), }; auto const expectedKeyPaths = std::array<const char *, 4>{ "opacity", "backgroundColor", "borderColor", "position" }; checkKeyPathsForAnimations(self, animations, expectedKeyPaths); } - (void)testSettingDelay { XCTAssertEqual(alpha().usingSpring().withDelay(0.25).toCA().beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(alpha().usingSpring().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(alpha().easeIn().usingSpring().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(alpha().easeOut().usingSpring().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)test_WhenDelayIsNotSet_UsesDefaultFillMode { XCTAssertEqualObjects(alpha().usingSpring().toCA().fillMode, kCAFillModeRemoved); } - (void)test_WhenDelayIsSet_UsesBackwardsFillMode { XCTAssertEqualObjects(alpha().usingSpring().withDelay(0.25).toCA().fillMode, kCAFillModeBackwards); } - (void)testDurationIsEqualToSettlingDuration { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().toCA()); XCTAssertEqual(a.duration, a.settlingDuration); } - (void)testSettingDamping { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().withDamping(20).toCA()); XCTAssertEqual(a.damping, 20); } - (void)testSettingInitialVelocity { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().withInitialVelocity(1).toCA()); XCTAssertEqual(a.initialVelocity, 1); } - (void)testSettingMass { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().withMass(2).toCA()); XCTAssertEqual(a.mass, 2); } - (void)testSettingStiffness { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().withStiffness(200).toCA()); XCTAssertEqual(a.stiffness, 200); } - (void)testDurationIsSetAfterSettingSpringParams { auto spring = alpha().usingSpring(); auto const defaultSpringCA = objCForceCast<CASpringAnimation>(spring.toCA()); spring.withDamping(20); auto const customSpringCA = objCForceCast<CASpringAnimation>(spring.toCA()); XCTAssertNotEqual(customSpringCA.duration, defaultSpringCA.duration); } @end @interface CKAnimationTests_SpringInitial : XCTestCase @end @implementation CKAnimationTests_SpringInitial - (void)testSpringBuilderBuildsSpringAnimation { XCTAssertEqualObjects(alphaFrom(0).usingSpring().withDelay(0.25).toCA().class, [CASpringAnimation class]); } - (void)testInitialAnimationKeyPaths { auto const animations = std::array<CAPropertyAnimation *, 4>{ objCForceCast<CAPropertyAnimation>(alphaFrom(0).usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(translationYFrom(0).usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(backgroundColorFrom(UIColor.blackColor).usingSpring().toCA()), objCForceCast<CAPropertyAnimation>(borderColorFrom(UIColor.blackColor).usingSpring().toCA()), }; auto const expectedKeyPaths = std::array<const char *, 4>{ "opacity", "transform.translation.y", "backgroundColor", "borderColor" }; checkKeyPathsForAnimations(self, animations, expectedKeyPaths); } - (void)testSettingFromValue { auto a = objCForceCast<CABasicAnimation>(alphaFrom(0).usingSpring().toCA()); XCTAssertEqualObjects(a.fromValue, @(0)); } - (void)testSettingDelay { XCTAssertEqual(alphaFrom(0).withDelay(0.25).usingSpring().toCA().beginTime, 0.25); } - (void)test_WhenTimingFunctionIsNotSet_UsesLinear { XCTAssertEqualObjects(alphaFrom(0).usingSpring().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]); } - (void)testSettingTimingFunction { XCTAssertEqualObjects(alphaFrom(0).usingSpring().easeIn().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]); XCTAssertEqualObjects(alphaFrom(0).easeOut().usingSpring().toCA().timingFunction, [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]); } - (void)testAlwaysUsesBackwardsFillMode { XCTAssertEqualObjects(alphaFrom(0).usingSpring().toCA().fillMode, kCAFillModeBackwards); } - (void)testDurationIsEqualToSettlingDuration { auto const a = objCForceCast<CASpringAnimation>(alphaFrom(0).usingSpring().toCA()); XCTAssertEqual(a.duration, a.settlingDuration); } - (void)testSettingDamping { auto const a = objCForceCast<CASpringAnimation>(alphaFrom(0).usingSpring().withDamping(20).toCA()); XCTAssertEqual(a.damping, 20); } - (void)testSettingInitialVelocity { auto const a = objCForceCast<CASpringAnimation>(alphaFrom(0).usingSpring().withInitialVelocity(1).toCA()); XCTAssertEqual(a.initialVelocity, 1); } - (void)testSettingMass { auto const a = objCForceCast<CASpringAnimation>(alphaFrom(0).usingSpring().withMass(2).toCA()); XCTAssertEqual(a.mass, 2); } - (void)testSettingStiffness { auto const a = objCForceCast<CASpringAnimation>(alpha().usingSpring().withStiffness(200).toCA()); XCTAssertEqual(a.stiffness, 200); } - (void)testDurationIsSetAfterSettingSpringParams { auto spring = alphaFrom(0).usingSpring(); auto const defaultSpringCA = objCForceCast<CASpringAnimation>(spring.toCA()); spring.withDamping(20); auto const customSpringCA = objCForceCast<CASpringAnimation>(spring.toCA()); XCTAssertNotEqual(customSpringCA.duration, defaultSpringCA.duration); } @end