blob: 5a1e92058b48dc188a710ccb716f8d4340159f7a [file] [log] [blame]
package com.airbnb.lottie;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.graphics.Rect;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.SparseArrayCompat;
import com.airbnb.lottie.model.Font;
import com.airbnb.lottie.model.FontCharacter;
import com.airbnb.lottie.model.layer.Layer;
import com.airbnb.lottie.utils.LottieValueAnimator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static junit.framework.Assert.assertEquals;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.times;
@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class LottieValueAnimatorUnitTest {
private interface VerifyListener {
void verify(InOrder inOrder);
}
private LottieValueAnimator animator;
private Animator.AnimatorListener spyListener;
private InOrder inOrder;
private AtomicBoolean isDone;
@Before
public void setup() {
// Choreographer#postFrameCallback hangs with robolectric.
animator = new LottieValueAnimator() {
@Override public void postFrameCallback() {
isRunning = true;
}
@Override public void removeFrameCallback() {
isRunning = false;
}
};
LottieComposition composition = new LottieComposition();
composition.init(new Rect(), 0, 1000, 1000, new ArrayList<Layer>(),
new LongSparseArray<Layer>(0), new HashMap<String, List<Layer>>(0),
new HashMap<String, LottieImageAsset>(0), new SparseArrayCompat<FontCharacter>(0),
new HashMap<String, Font>(0));
animator.setComposition(composition);
spyListener = Mockito.mock(Animator.AnimatorListener.class);
isDone = new AtomicBoolean(false);
}
@Test
public void testInitialState() {
assertEquals(0f, animator.getFrame());
}
@Test
public void testResumingMaintainsValue() {
animator.setFrame(500);
animator.resumeAnimation();
assertEquals(500f, animator.getFrame());
}
@Test
public void testFrameConvertsToAnimatedFraction() {
animator.setFrame(500);
animator.resumeAnimation();
assertEquals(0.5f, animator.getAnimatedFraction());
assertEquals(0.5f, animator.getAnimatedValueAbsolute());
}
@Test
public void testPlayingResetsValue() {
animator.setFrame(500);
animator.playAnimation();
assertEquals(0f, animator.getFrame());
assertEquals(0f, animator.getAnimatedFraction());
}
@Test
public void testReversingMaintainsValue() {
animator.setFrame(250);
animator.reverseAnimationSpeed();
assertEquals(250f, animator.getFrame());
assertEquals(0.75f, animator.getAnimatedFraction());
assertEquals(0.25f, animator.getAnimatedValueAbsolute());
}
@Test
public void testReversingWithMinValueMaintainsValue() {
animator.setMinFrame(100);
animator.setFrame(1000);
animator.reverseAnimationSpeed();
assertEquals(1000f, animator.getFrame());
assertEquals(0f, animator.getAnimatedFraction());
assertEquals(1f, animator.getAnimatedValueAbsolute());
}
@Test
public void testReversingWithMaxValueMaintainsValue() {
animator.setMaxFrame(900);
animator.reverseAnimationSpeed();
assertEquals(0f, animator.getFrame());
assertEquals(1f, animator.getAnimatedFraction());
assertEquals(0f, animator.getAnimatedValueAbsolute());
}
@Test
public void testResumeReversingWithMinValueMaintainsValue() {
animator.setMaxFrame(900);
animator.reverseAnimationSpeed();
animator.resumeAnimation();
assertEquals(900f, animator.getFrame());
assertEquals(0f, animator.getAnimatedFraction());
assertEquals(0.9f, animator.getAnimatedValueAbsolute());
}
@Test
public void testPlayReversingWithMinValueMaintainsValue() {
animator.setMaxFrame(900);
animator.reverseAnimationSpeed();
animator.playAnimation();
assertEquals(900f, animator.getFrame());
assertEquals(0f, animator.getAnimatedFraction());
assertEquals(0.9f, animator.getAnimatedValueAbsolute());
}
@Test
public void testMinAndMaxBothSet() {
animator.setMinFrame(200);
animator.setMaxFrame(800);
animator.setFrame(400);
assertEquals(0.33f, animator.getAnimatedFraction(), 0.01);
assertEquals(0.4f, animator.getAnimatedValueAbsolute());
animator.reverseAnimationSpeed();
assertEquals(400f, animator.getFrame());
assertEquals(0.66f, animator.getAnimatedFraction(), 0.01);
assertEquals(0.4f, animator.getAnimatedValueAbsolute());
animator.resumeAnimation();
assertEquals(400f, animator.getFrame());
assertEquals(0.66f, animator.getAnimatedFraction(), 0.01);
assertEquals(0.4f, animator.getAnimatedValueAbsolute());
animator.playAnimation();
assertEquals(800f, animator.getFrame());
assertEquals(0f, animator.getAnimatedFraction());
assertEquals(0.8f, animator.getAnimatedValueAbsolute());
}
@Test
public void testDefaultAnimator() {
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
inOrder.verify(spyListener, times(1)).onAnimationStart(animator, false);
inOrder.verify(spyListener, times(1)).onAnimationEnd(animator, false);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
Mockito.verify(spyListener, times(0)).onAnimationRepeat(animator);
}
});
}
@Test
public void testReverseAnimator() {
animator.reverseAnimationSpeed();
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
inOrder.verify(spyListener, times(1)).onAnimationStart(animator, true);
inOrder.verify(spyListener, times(1)).onAnimationEnd(animator, true);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
Mockito.verify(spyListener, times(0)).onAnimationRepeat(animator);
}
});
}
@Test
public void testLoopingAnimatorOnce() {
animator.setRepeatCount(1);
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
Mockito.verify(spyListener, times(1)).onAnimationStart(animator, false);
Mockito.verify(spyListener, times(1)).onAnimationRepeat(animator);
Mockito.verify(spyListener, times(1)).onAnimationEnd(animator, false);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
}
});
}
@Test
public void testLoopingAnimatorZeroTimes() {
animator.setRepeatCount(0);
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
Mockito.verify(spyListener, times(1)).onAnimationStart(animator, false);
Mockito.verify(spyListener, times(0)).onAnimationRepeat(animator);
Mockito.verify(spyListener, times(1)).onAnimationEnd(animator, false);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
}
});
}
@Test
public void testLoopingAnimatorTwice() {
animator.setRepeatCount(2);
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
Mockito.verify(spyListener, times(1)).onAnimationStart(animator, false);
Mockito.verify(spyListener, times(2)).onAnimationRepeat(animator);
Mockito.verify(spyListener, times(1)).onAnimationEnd(animator, false);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
}
});
}
@Test
public void testLoopingAnimatorOnceReverse() {
animator.setFrame(1000);
animator.setRepeatCount(1);
animator.reverseAnimationSpeed();
testAnimator(new VerifyListener() {
@Override public void verify(InOrder inOrder) {
inOrder.verify(spyListener, times(1)).onAnimationStart(animator, true);
inOrder.verify(spyListener, times(1)).onAnimationRepeat(animator);
inOrder.verify(spyListener, times(1)).onAnimationEnd(animator, true);
Mockito.verify(spyListener, times(0)).onAnimationCancel(animator);
}
});
}
private void testAnimator(final VerifyListener verifyListener) {
spyListener = Mockito.spy(new AnimatorListenerAdapter() {
@Override public void onAnimationEnd(Animator animation) {
verifyListener.verify(inOrder);
isDone.set(true);
}
});
inOrder = inOrder(spyListener);
animator.addListener(spyListener);
animator.playAnimation();
while (!isDone.get()) {
animator.doFrame(System.nanoTime());
}
}
}