You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
545 lines
20 KiB
545 lines
20 KiB
9 years ago
|
/**
|
||
|
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 <QuartzCore/QuartzCore.h>
|
||
|
|
||
|
#import <OCMock/OCMock.h>
|
||
|
|
||
|
#import <XCTest/XCTest.h>
|
||
|
|
||
|
#import <pop/POP.h>
|
||
|
#import <pop/POPAnimatorPrivate.h>
|
||
|
|
||
|
#import "POPAnimatable.h"
|
||
|
#import "POPAnimationTestsExtras.h"
|
||
|
#import "POPBaseAnimationTests.h"
|
||
|
|
||
|
@interface POPDecayAnimationTests : POPBaseAnimationTests
|
||
|
@end
|
||
|
|
||
|
@implementation POPDecayAnimationTests
|
||
|
|
||
|
static NSString *animationKey = @"key";
|
||
|
static const CGFloat epsilon = 0.0001f;
|
||
|
|
||
|
- (POPDecayAnimation *)_positionAnimation
|
||
|
{
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPosition];
|
||
|
anim.fromValue = [NSValue valueWithCGPoint:CGPointZero];
|
||
|
anim.velocity = [NSValue valueWithCGPoint:CGPointMake(7223.021, 7223.021)];
|
||
|
anim.deceleration = 0.998000;
|
||
|
return anim;
|
||
|
}
|
||
|
|
||
|
- (POPDecayAnimation *)_positionXAnimation
|
||
|
{
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPositionX];
|
||
|
anim.fromValue = @0.;
|
||
|
anim.velocity = @7223.021;
|
||
|
anim.deceleration = 0.998000;
|
||
|
return anim;
|
||
|
}
|
||
|
|
||
|
- (POPDecayAnimation *)_positionYAnimation
|
||
|
{
|
||
|
POPDecayAnimation *anim = self._positionXAnimation;
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPositionY];
|
||
|
return anim;
|
||
|
}
|
||
|
|
||
|
- (void)testConvergence
|
||
|
{
|
||
|
POPAnimatable *circle = [POPAnimatable new];
|
||
|
POPDecayAnimation *anim = self._positionXAnimation;
|
||
|
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
[circle pop_addAnimation:anim forKey:@"key"];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 10.0, 1.0/60.0);
|
||
|
[tracer stop];
|
||
|
|
||
|
// did reach to value
|
||
|
POPAnimationValueEvent *didReachToEvent = [[tracer eventsWithType:kPOPAnimationEventDidReachToValue] lastObject];
|
||
|
XCTAssertEqualObjects(didReachToEvent.value, anim.toValue, @"unexpected did reach to event: %@ anim:%@", didReachToEvent, anim);
|
||
|
|
||
|
// finished
|
||
|
POPAnimationValueEvent *stopEvent = [[tracer eventsWithType:kPOPAnimationEventDidStop] lastObject];
|
||
|
XCTAssertEqualObjects(stopEvent.value, @YES, @"unexpected stop event %@", stopEvent);
|
||
|
|
||
|
// all write values monotonically increasing
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
POPAnimationValueEvent *lastWriteEvent = nil;
|
||
|
for (POPAnimationValueEvent *writeEvent in writeEvents) {
|
||
|
if (lastWriteEvent) {
|
||
|
NSComparisonResult result = [lastWriteEvent.value compare:writeEvent.value];
|
||
|
XCTAssertTrue(NSOrderedAscending == result || NSOrderedSame == result, @"write event values not monotonically increasing current:%@ last:%@ all:%@", writeEvent, lastWriteEvent, writeEvents);
|
||
|
}
|
||
|
lastWriteEvent = writeEvent;
|
||
|
}
|
||
|
|
||
|
// convergence threshold
|
||
|
NSUInteger toValueFrameCount = POPAnimationCountLastEventValues(writeEvents, anim.toValue, anim.property.threshold);
|
||
|
XCTAssertTrue(toValueFrameCount <= kPOPAnimationConvergenceMaxFrameCount, @"unexpected convergence; toValueFrameCount: %lu", (unsigned long)toValueFrameCount);
|
||
|
}
|
||
|
|
||
|
- (void)testConvergenceNegativeVelocity
|
||
|
{
|
||
|
POPAnimatable *circle = [POPAnimatable new];
|
||
|
POPDecayAnimation *anim = self._positionXAnimation;
|
||
|
anim.velocity = @-7223.021;
|
||
|
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
[circle pop_addAnimation:anim forKey:@"key"];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 10.0, 1.0/60.0);
|
||
|
[tracer stop];
|
||
|
|
||
|
// did reach to value
|
||
|
POPAnimationValueEvent *didReachToEvent = [[tracer eventsWithType:kPOPAnimationEventDidReachToValue] lastObject];
|
||
|
XCTAssertEqualObjects(didReachToEvent.value, anim.toValue, @"unexpected did reach to event: %@ anim:%@", didReachToEvent, anim);
|
||
|
|
||
|
// finished
|
||
|
POPAnimationValueEvent *stopEvent = [[tracer eventsWithType:kPOPAnimationEventDidStop] lastObject];
|
||
|
XCTAssertEqualObjects(stopEvent.value, @YES, @"unexpected stop event %@", stopEvent);
|
||
|
|
||
|
// all write values monotonically increasing
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
POPAnimationValueEvent *lastWriteEvent = nil;
|
||
|
for (POPAnimationValueEvent *writeEvent in writeEvents) {
|
||
|
if (lastWriteEvent) {
|
||
|
NSComparisonResult result = [lastWriteEvent.value compare:writeEvent.value];
|
||
|
XCTAssertTrue(NSOrderedDescending == result || NSOrderedSame == result, @"write event values not monotonically decreasing current:%@ last:%@ all:%@", writeEvent, lastWriteEvent, writeEvents);
|
||
|
}
|
||
|
lastWriteEvent = writeEvent;
|
||
|
}
|
||
|
|
||
|
// convergence threshold
|
||
|
NSUInteger toValueFrameCount = POPAnimationCountLastEventValues(writeEvents, anim.toValue, anim.property.threshold);
|
||
|
XCTAssertTrue(toValueFrameCount <= kPOPAnimationConvergenceMaxFrameCount, @"unexpected convergence; toValueFrameCount: %lu", (unsigned long)toValueFrameCount);
|
||
|
}
|
||
|
|
||
|
- (void)test2DConvergence
|
||
|
{
|
||
|
POPDecayAnimation *animX = self._positionXAnimation;
|
||
|
POPDecayAnimation *animY = self._positionYAnimation;
|
||
|
XCTAssertEqual(animX.duration, animY.duration, @"unexpected durations animX:%@ animY:%@", animX, animY);
|
||
|
XCTAssertEqualObjects(animX.toValue, animY.toValue, @"unexpected toValue animX:%@ animY:%@", animX, animY);
|
||
|
|
||
|
POPDecayAnimation *anim = self._positionAnimation;
|
||
|
CFTimeInterval duration = anim.duration;
|
||
|
XCTAssertEqualWithAccuracy(animX.duration, duration, epsilon, @"unexpected durations animX:%@ anim:%@", animX, anim);
|
||
|
XCTAssertEqualObjects(animX.toValue, @([anim.toValue CGPointValue].x), @"unexpected toValue animX:%@ anim:%@", animX, anim);
|
||
|
|
||
|
POPAnimatable *circle = [POPAnimatable new];
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
[circle pop_addAnimation:anim forKey:@"key"];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 10.0, 1.0/60.0);
|
||
|
[tracer stop];
|
||
|
|
||
|
// did reach to value
|
||
|
POPAnimationValueEvent *didReachToEvent = [[tracer eventsWithType:kPOPAnimationEventDidReachToValue] lastObject];
|
||
|
XCTAssertEqualObjects(didReachToEvent.value, anim.toValue, @"unexpected did reach to event: %@ anim:%@", didReachToEvent, anim);
|
||
|
|
||
|
// finished
|
||
|
POPAnimationValueEvent *stopEvent = [[tracer eventsWithType:kPOPAnimationEventDidStop] lastObject];
|
||
|
XCTAssertEqualObjects(stopEvent.value, @YES, @"unexpected stop event %@", stopEvent);
|
||
|
|
||
|
// increase X velocity
|
||
|
anim.velocity = [NSValue valueWithCGPoint:CGPointMake(7223.021 + 1000, 7223.021)];
|
||
|
XCTAssertTrue(anim.duration > duration, @"unexpected duration expected:%f anim:%@", duration, anim);
|
||
|
|
||
|
// increase Y velocity
|
||
|
anim.velocity = [NSValue valueWithCGPoint:CGPointMake(7223.021, 7223.021 + 1000)];
|
||
|
XCTAssertTrue(anim.duration > duration, @"unexpected duration expected:%f anim:%@", duration, anim);
|
||
|
}
|
||
|
|
||
|
- (void)testRemovedOnCompletionNoStartStopBasics
|
||
|
{
|
||
|
static NSString *animationKey = @"key";
|
||
|
|
||
|
CALayer *layer = self.layer1;
|
||
|
POPAnimation *anim = self._positionXAnimation;
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
|
||
|
// cleanup
|
||
|
[layer pop_removeAllAnimations];
|
||
|
|
||
|
// configure animation
|
||
|
anim.removedOnCompletion = NO;
|
||
|
anim.delegate = delegate;
|
||
|
|
||
|
__block BOOL completionBlock = NO;
|
||
|
__block BOOL completionBlockFinished = NO;
|
||
|
anim.completionBlock = ^(POPAnimation *a, BOOL finished) {
|
||
|
completionBlock = YES;
|
||
|
completionBlockFinished = finished;
|
||
|
};
|
||
|
|
||
|
// start tracer
|
||
|
[tracer start];
|
||
|
|
||
|
// expect start and stopped
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
[layer pop_addAnimation:anim forKey:animationKey];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 20.0, 1.0/60.0);
|
||
|
NSArray *allEvents = tracer.allEvents;
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
XCTAssertTrue(completionBlock, @"completion block did not execute %@", allEvents);
|
||
|
XCTAssertTrue(completionBlockFinished, @"completion block did not finish %@", allEvents);
|
||
|
|
||
|
// assert animation has not been removed
|
||
|
XCTAssertTrue(anim == [layer pop_animationForKey:animationKey], @"expected animation on layer animations:%@", [layer pop_animationKeys]);
|
||
|
}
|
||
|
|
||
|
- (void)testRemovedOnCompletionNoContinuations
|
||
|
{
|
||
|
static NSString *animationKey = @"key";
|
||
|
static NSArray *velocities = @[@50.0, @100.0, @20.0, @80.0];
|
||
|
static NSArray *durations = @[@2.0, @0.5, @0.5, @2.0];
|
||
|
|
||
|
CALayer *layer = self.layer1;
|
||
|
POPDecayAnimation *anim = self._positionXAnimation;
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
|
||
|
// cleanup
|
||
|
[layer pop_removeAllAnimations];
|
||
|
|
||
|
// configure animation
|
||
|
anim.removedOnCompletion = NO;
|
||
|
anim.delegate = delegate;
|
||
|
|
||
|
// start tracer
|
||
|
[tracer start];
|
||
|
|
||
|
__block CFTimeInterval beginTime;
|
||
|
__block BOOL completionBlock = NO;
|
||
|
__block BOOL completionBlockFinished = NO;
|
||
|
|
||
|
[velocities enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *ptrStop) {
|
||
|
anim.velocity = obj;
|
||
|
|
||
|
if (0 == idx) {
|
||
|
[tracer reset];
|
||
|
|
||
|
// starts and stops
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
anim.completionBlock = ^(POPAnimation *a, BOOL finished) {
|
||
|
completionBlock = YES;
|
||
|
completionBlockFinished = finished;
|
||
|
};
|
||
|
|
||
|
[layer pop_addAnimation:anim forKey:animationKey];
|
||
|
|
||
|
beginTime = self.beginTime;
|
||
|
CFTimeInterval dt = [durations[idx] doubleValue];
|
||
|
POPAnimatorRenderDuration(self.animator, beginTime, dt, 1.0/60.0);
|
||
|
beginTime += dt;
|
||
|
|
||
|
NSArray *allEvents = tracer.allEvents;
|
||
|
NSArray *didReachEvents = [tracer eventsWithType:kPOPAnimationEventDidReachToValue];
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
XCTAssertTrue(1 == didReachEvents.count, @"unexpected didReachEvents %@", didReachEvents);
|
||
|
XCTAssertTrue(completionBlock, @"completion block did not execute %@", allEvents);
|
||
|
XCTAssertTrue(completionBlockFinished, @"completion block did not finish %@", allEvents);
|
||
|
} else if (velocities.count - 1 == idx) {
|
||
|
// continue stoped animation
|
||
|
[tracer reset];
|
||
|
completionBlock = NO;
|
||
|
completionBlockFinished = NO;
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
CFTimeInterval dt = [durations[idx] doubleValue];
|
||
|
POPAnimatorRenderDuration(self.animator, beginTime, dt, 1.0/60.0);
|
||
|
beginTime += dt;
|
||
|
|
||
|
NSArray *allEvents = tracer.allEvents;
|
||
|
NSArray *didReachEvents = [tracer eventsWithType:kPOPAnimationEventDidReachToValue];
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
XCTAssertTrue(1 == didReachEvents.count, @"unexpected didReachEvents %@", didReachEvents);
|
||
|
XCTAssertTrue(completionBlock, @"completion block did not execute %@", allEvents);
|
||
|
XCTAssertTrue(completionBlockFinished, @"completion block did not finish %@", allEvents);
|
||
|
} else {
|
||
|
// continue stoped (idx = 1) or started animation
|
||
|
if (1 == idx) {
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
}
|
||
|
|
||
|
// reset state
|
||
|
[tracer reset];
|
||
|
completionBlock = NO;
|
||
|
completionBlockFinished = NO;
|
||
|
|
||
|
CFTimeInterval dt = [durations[idx] doubleValue];
|
||
|
POPAnimatorRenderDuration(self.animator, beginTime, dt, 1.0/60.0);
|
||
|
beginTime += dt;
|
||
|
|
||
|
NSArray *allEvents = tracer.allEvents;
|
||
|
NSArray *didReachEvents = [tracer eventsWithType:kPOPAnimationEventDidReachToValue];
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
XCTAssertTrue(0 == didReachEvents.count, @"unexpected didReachEvents %@", didReachEvents);
|
||
|
XCTAssertFalse(completionBlock, @"completion block did not execute %@ %@", anim, allEvents);
|
||
|
XCTAssertFalse(completionBlockFinished, @"completion block did not finish %@ %@", anim, allEvents);
|
||
|
}
|
||
|
|
||
|
// assert animation has not been removed
|
||
|
XCTAssertTrue(anim == [layer pop_animationForKey:animationKey], @"expected animation on layer animations:%@", [layer pop_animationKeys]);
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
- (void)testNoOperationAnimation
|
||
|
{
|
||
|
const CGPoint initialValue = CGPointMake(100, 100);
|
||
|
|
||
|
CALayer *layer = self.layer1;
|
||
|
layer.position = initialValue;
|
||
|
[layer pop_removeAllAnimations];
|
||
|
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPosition];
|
||
|
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
anim.delegate = delegate;
|
||
|
|
||
|
// starts and stops
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
[layer pop_addAnimation:anim forKey:animationKey];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 5, 1.0/60.0);
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
|
||
|
// verify number values
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
for (POPAnimationValueEvent *writeEvent in writeEvents) {
|
||
|
XCTAssertEqualObjects(writeEvent.value, [NSValue valueWithCGPoint:initialValue], @"unexpected write event:%@ anim:%@", writeEvent, anim);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)testContinuation
|
||
|
{
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerPositionX];
|
||
|
anim.fromValue = @0.0;
|
||
|
anim.velocity = @1000.0;
|
||
|
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
anim.delegate = delegate;
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
CALayer *layer = self.layer1;
|
||
|
[layer pop_addAnimation:anim forKey:animationKey];
|
||
|
|
||
|
// run animation, not till completion
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 1, 1.0/60.0);
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
[tracer reset];
|
||
|
|
||
|
// verify start delegation
|
||
|
[delegate verify];
|
||
|
|
||
|
// update velocity of active animation
|
||
|
anim.velocity = @1000.0;
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
// run animation some more
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime + 1, 4, 1.0/60.0);
|
||
|
NSArray *moreWriteEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
|
||
|
// verify stop delegation
|
||
|
[delegate verify];
|
||
|
|
||
|
// compare event values
|
||
|
POPAnimationValueEvent *firstEvent = [writeEvents firstObject];
|
||
|
POPAnimationValueEvent *lastEvent = [writeEvents lastObject];
|
||
|
POPAnimationValueEvent *firstMoreEvent = [moreWriteEvents firstObject];
|
||
|
XCTAssertTrue(NSOrderedAscending == [firstEvent.value compare:lastEvent.value]
|
||
|
&& NSOrderedAscending == [lastEvent.value compare:firstMoreEvent.value], @"write event values not monotonically increasing %@ %@ %@", firstEvent, lastEvent, firstMoreEvent);
|
||
|
}
|
||
|
|
||
|
- (void)testRectSupport
|
||
|
{
|
||
|
const CGRect fromRect = CGRectMake(0, 0, 0, 0);
|
||
|
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPLayerBounds];
|
||
|
anim.fromValue = [NSValue valueWithCGRect:fromRect];
|
||
|
anim.velocity = [NSValue valueWithCGRect:CGRectMake(100, 100, 1000, 1000)];
|
||
|
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
anim.delegate = delegate;
|
||
|
|
||
|
// expect start and stop to be called
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
// start tracer
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
CALayer *layer = self.layer1;
|
||
|
[layer pop_addAnimation:anim forKey:animationKey];
|
||
|
|
||
|
// run animation
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0);
|
||
|
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
|
||
|
POPAnimationValueEvent *lastEvent = [writeEvents lastObject];
|
||
|
CGRect lastRect = [lastEvent.value CGRectValue];
|
||
|
|
||
|
XCTAssertTrue(!CGRectEqualToRect(fromRect, lastRect), @"unexpected last rect value: %@", lastEvent);
|
||
|
XCTAssertTrue(lastRect.origin.x == lastRect.origin.y && lastRect.size.width == lastRect.size.height && lastRect.origin.x < lastRect.size.width, @"unexpected last rect value: %@", lastEvent);
|
||
|
}
|
||
|
|
||
|
#if TARGET_OS_IPHONE
|
||
|
- (void)testEdgeInsetsSupport
|
||
|
{
|
||
|
const UIEdgeInsets fromEdgeInsets = UIEdgeInsetsZero;
|
||
|
const UIEdgeInsets velocityEdgeInsets = UIEdgeInsetsMake(100, 100, 1000, 1000);
|
||
|
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animation];
|
||
|
anim.property = [POPAnimatableProperty propertyWithName:kPOPScrollViewContentInset];
|
||
|
anim.fromValue = [NSValue valueWithUIEdgeInsets:fromEdgeInsets];
|
||
|
anim.velocity = [NSValue valueWithUIEdgeInsets:velocityEdgeInsets];
|
||
|
|
||
|
id delegate = [OCMockObject niceMockForProtocol:@protocol(POPAnimationDelegate)];
|
||
|
anim.delegate = delegate;
|
||
|
|
||
|
// expect start and stop to be called
|
||
|
[[delegate expect] pop_animationDidStart:anim];
|
||
|
[[delegate expect] pop_animationDidStop:anim finished:YES];
|
||
|
|
||
|
// start tracer
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
id scrollView = [OCMockObject niceMockForClass:[UIScrollView class]];
|
||
|
[scrollView pop_addAnimation:anim forKey:nil];
|
||
|
|
||
|
// run animation
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 3, 1.0/60.0);
|
||
|
|
||
|
NSArray *writeEvents = [tracer eventsWithType:kPOPAnimationEventPropertyWrite];
|
||
|
|
||
|
// verify delegate
|
||
|
[delegate verify];
|
||
|
|
||
|
POPAnimationValueEvent *lastEvent = [writeEvents lastObject];
|
||
|
UIEdgeInsets lastEdgeInsets = [lastEvent.value UIEdgeInsetsValue];
|
||
|
|
||
|
XCTAssertTrue(!UIEdgeInsetsEqualToEdgeInsets(fromEdgeInsets, lastEdgeInsets), @"unexpected last edge insets value: %@", lastEvent);
|
||
|
XCTAssertTrue(lastEdgeInsets.top == lastEdgeInsets.left && lastEdgeInsets.bottom == lastEdgeInsets.right && lastEdgeInsets.top < lastEdgeInsets.bottom, @"unexpected last edge insets value: %@", lastEvent);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
- (void)testEndValueOnReuse
|
||
|
{
|
||
|
POPAnimatable *circle = [POPAnimatable new];
|
||
|
POPDecayAnimation *anim = self._positionXAnimation;
|
||
|
|
||
|
POPAnimationTracer *tracer = anim.tracer;
|
||
|
[tracer start];
|
||
|
|
||
|
// read out to value
|
||
|
CGFloat toValue = [anim.toValue floatValue];
|
||
|
[circle pop_addAnimation:anim forKey:@"key"];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 5.0, 1.0/60.0);
|
||
|
|
||
|
NSArray *stopEvent = [tracer eventsWithType:kPOPAnimationEventDidStop];
|
||
|
XCTAssertTrue(1 == stopEvent.count, @"unexpected events:%@", tracer.allEvents);
|
||
|
|
||
|
CGFloat lastValue = [[(POPAnimationValueEvent *)tracer.writeEvents.lastObject value] floatValue];
|
||
|
XCTAssertEqualWithAccuracy(toValue, lastValue, 0.5, @"expected:%f actual event:%@", lastValue, tracer.writeEvents.lastObject);
|
||
|
// update animation
|
||
|
anim.fromValue = @([anim.toValue floatValue] - 100);
|
||
|
anim.velocity = @(5000.);
|
||
|
|
||
|
// and reuse
|
||
|
[tracer reset];
|
||
|
[circle pop_addAnimation:anim forKey:@"key"];
|
||
|
POPAnimatorRenderDuration(self.animator, self.beginTime, 5.0, 1.0/60.0);
|
||
|
|
||
|
// verify decayed passed initial toValue
|
||
|
lastValue = [[(POPAnimationValueEvent *)tracer.writeEvents.lastObject value] floatValue];
|
||
|
XCTAssertTrue(lastValue > toValue, @"unexpected last value:%f", lastValue);
|
||
|
}
|
||
|
|
||
|
- (void)testComputedProperties
|
||
|
{
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:kPOPLayerPositionX];
|
||
|
|
||
|
// set velocity, test duration
|
||
|
anim.velocity = @(100);
|
||
|
CGFloat d1 = anim.duration;
|
||
|
XCTAssertTrue(d1 > 0, @"unexpected duration %@", anim);
|
||
|
|
||
|
// set velocity, test duration
|
||
|
anim.velocity = @(1000);
|
||
|
CGFloat d2 = anim.duration;
|
||
|
XCTAssertTrue(d2 > d1, @"unexpected duration %@", anim);
|
||
|
|
||
|
// set from value, test to value
|
||
|
anim.fromValue = @(0);
|
||
|
CGFloat p1 = [anim.toValue floatValue];
|
||
|
XCTAssertTrue(p1 > [anim.fromValue floatValue], @"unexpected to value %@", anim);
|
||
|
|
||
|
// set from value, test to value
|
||
|
anim.fromValue = @(10000);
|
||
|
CGFloat p2 = [anim.toValue floatValue];
|
||
|
XCTAssertTrue(p2 > [anim.fromValue floatValue] && p2 > p1, @"unexpected to value %@", anim);
|
||
|
}
|
||
|
|
||
|
- (void)testNSCopyingSupportPOPDecayAnimation
|
||
|
{
|
||
|
POPDecayAnimation *anim = [POPDecayAnimation animationWithPropertyNamed:@"test_prop_name"];
|
||
|
|
||
|
configureConcretePropertyAnimation(anim);
|
||
|
|
||
|
anim.velocity = @(1.8888);
|
||
|
anim.deceleration = -9.8;
|
||
|
|
||
|
POPDecayAnimation *copy = [anim copy];
|
||
|
|
||
|
XCTAssertEqualObjects(copy.velocity, anim.velocity, @"expected equality; value1:%@ value2:%@", copy.velocity, anim.velocity);
|
||
|
XCTAssertEqual(copy.deceleration, anim.deceleration, @"expected equality; value1:%@ value2:%@", @(copy.deceleration), @(anim.deceleration));
|
||
|
}
|
||
|
|
||
|
@end
|