blob: eb9465b259dc5dc1d5c264579ea6264898e966b5 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.animation.client;
import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
import com.google.gwt.animation.client.testing.StubAnimationScheduler;
import com.google.gwt.core.client.Duration;
import com.google.gwt.junit.client.GWTTestCase;
import java.util.List;
/**
* Tests the {@link Animation} class.
*
* <p>
* This class uses the {@link StubAnimationScheduler} to manually trigger
* callbacks.
* </p>
*/
public class AnimationTest extends GWTTestCase {
/**
* A default implementation of {@link Animation} used for testing.
*/
private class DefaultAnimation extends Animation {
protected boolean canceled = false;
protected boolean completed = false;
protected double curProgress = -1.0;
protected boolean started = false;
protected boolean updated = false;
public DefaultAnimation() {
super(scheduler);
}
/**
* Assert the value of canceled.
*/
public void assertCancelled(boolean expected) {
assertEquals(expected, canceled);
}
/**
* Assert the value of completed.
*/
public void assertCompleted(boolean expected) {
assertEquals(expected, completed);
}
/**
* Assert that the progress equals the specified value.
*/
public void assertProgress(double expected) {
assertEquals(expected, curProgress);
}
/**
* Assert the value of started.
*/
public void assertStarted(boolean expected) {
assertEquals(expected, started);
}
/**
* Assert the value of updated.
*/
public void assertUpdated(boolean expected) {
assertEquals(expected, updated);
}
public void reset() {
canceled = false;
completed = false;
updated = false;
started = false;
curProgress = -1.0;
}
@Override
protected void onCancel() {
super.onCancel();
canceled = true;
}
@Override
protected void onComplete() {
super.onComplete();
completed = true;
}
@Override
protected void onStart() {
super.onStart();
started = true;
}
@Override
protected void onUpdate(double progress) {
updated = true;
curProgress = progress;
}
}
/**
* A custom {@link Animation} used for testing.
*/
private class TestAnimation extends DefaultAnimation {
@Override
protected void onCancel() {
canceled = true;
}
@Override
protected void onComplete() {
completed = true;
}
@Override
protected void onStart() {
started = true;
}
}
/**
* The maximum delay before an animation will run. Animations may run slowly
* if the browser tab is not focused.
*
* Increase this multiplier to increase the duration of the tests, reducing
* the potential of an error caused by timing issues.
*/
private static int DELAY_MULTIPLIER = 3000;
private List<AnimationCallback> callbacks;
private double curTime;
private StubAnimationScheduler scheduler;
@Override
public String getModuleName() {
return "com.google.gwt.animation.Animation";
}
/**
* Test canceling an {@link Animation} after it completes.
*/
public void testCancelAfterOnComplete() {
final TestAnimation anim = new TestAnimation();
anim.run(DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.reset();
// Complete the animation.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER + 100);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(true);
anim.assertCancelled(false);
assertEquals(0, callbacks.size());
anim.reset();
// Cancel the animation.
anim.cancel(); // no-op.
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertProgress(-1);
anim.assertCancelled(false);
}
/**
* Test canceling an {@link Animation} before onStart is called.
*/
public void testCancelBeforeOnStart() {
final TestAnimation anim = new TestAnimation();
// Run the animation in the future.
anim.run(DELAY_MULTIPLIER, curTime + 1000);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
assertEquals(1, callbacks.size());
anim.reset();
// Cancel the animation before it starts.
anim.cancel();
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(true);
assertEquals(0, callbacks.size());
}
/**
* Test canceling an {@link Animation} between updates.
*/
public void testCancelBetweenUpdates() {
TestAnimation anim = new TestAnimation();
anim.run(10 * DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.reset();
// Update the animation.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(true);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.reset();
// Cancel the animation.
assertEquals(1, callbacks.size());
anim.cancel();
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(true);
anim.assertProgress(-1.0);
assertEquals(0, callbacks.size());
}
/**
* Test canceling an {@link Animation} within onComplete.
*/
public void testCancelDuringOnComplete() {
final TestAnimation anim = new TestAnimation() {
@Override
protected void onComplete() {
super.onComplete();
assertStarted(false);
assertUpdated(false);
assertCompleted(true);
assertCancelled(false);
reset();
// Cancel the animation.
cancel(); // no-op.
}
};
// Run the animation.
anim.run(DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.reset();
// Force the animation to complete.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER + 100);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
assertEquals(0, callbacks.size());
}
/**
* Test canceling an {@link Animation} within onStart.
*/
public void testCancelDuringOnStart() {
final TestAnimation anim = new TestAnimation() {
@Override
protected void onStart() {
super.onStart();
assertStarted(true);
assertUpdated(false);
assertCompleted(false);
assertCancelled(false);
reset();
// Cancel the animation.
cancel();
}
};
// Run the animation.
anim.run(DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCancelled(true);
anim.assertCompleted(false);
assertEquals(0, callbacks.size());
}
/**
* Test canceling an {@link Animation} during an update.
*/
public void testCancelDuringOnUpdate() {
final TestAnimation anim = new TestAnimation() {
@Override
protected void onUpdate(double progress) {
super.onUpdate(progress);
assertStarted(false);
assertUpdated(true);
assertCompleted(false);
assertCancelled(false);
reset();
// Cancel the test while it is running.
cancel();
}
};
// Run the animation.
anim.run(10 * DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.assertProgress(-1.0);
anim.reset();
// Force the update.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(true);
anim.assertProgress(-1.0);
assertEquals(0, callbacks.size());
}
/**
* Test the default implementations of events in {@link Animation}.
*/
public void testDefaultAnimation() {
// Verify initial state
final DefaultAnimation anim = new DefaultAnimation();
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCancelled(false);
anim.assertCompleted(false);
// Starting an animation calls onUpdate(interpolate(0.0))
anim.reset();
anim.onStart();
anim.assertProgress(0.0);
anim.assertStarted(true);
anim.assertCompleted(false);
anim.assertCancelled(false);
// Completing an animation calls onUpdate(interpolate(1.0))
anim.reset();
anim.onComplete();
anim.assertProgress(1.0);
anim.assertStarted(false);
anim.assertCompleted(true);
anim.assertCancelled(false);
// Canceling an animation that is not running does not call onStart or
// onComplete
anim.reset();
anim.onCancel();
anim.assertProgress(-1.0);
anim.assertStarted(false);
anim.assertCompleted(false);
anim.assertCancelled(true);
// Canceling an animation before it starts does not call onStart or
// onComplete
anim.reset();
anim.run(10 * DELAY_MULTIPLIER, curTime + DELAY_MULTIPLIER);
anim.cancel();
anim.assertProgress(-1.0);
anim.assertStarted(false);
anim.assertCompleted(false);
anim.assertCancelled(true);
}
/**
* Test that restarting an {@link Animation} within onComplete does not break.
* See issue 5639.
*/
public void testRunDuringOnComplete() {
final TestAnimation anim = new TestAnimation() {
@Override
protected void onComplete() {
super.onComplete();
assertStarted(false);
assertUpdated(false);
assertCompleted(true);
assertCancelled(false);
reset();
// Run the animation.
run(DELAY_MULTIPLIER);
}
};
// Run the animation.
anim.run(DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
anim.reset();
// Force the animation to complete.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER + 100);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.assertCancelled(false);
assertEquals(1, callbacks.size());
}
/**
* Test that an animation runs in the future.
*/
public void testRunFuture() {
final TestAnimation anim = new TestAnimation();
anim.run(2 * DELAY_MULTIPLIER, curTime + 2 * DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.reset();
// Update, but still before the start time.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.reset();
// Start the animation.
executeLastCallbackAt(curTime + 2 * DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.reset();
// Update the animation.
executeLastCallbackAt(curTime + 3 * DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(true);
anim.assertCompleted(false);
anim.reset();
// Complete the animation.
executeLastCallbackAt(curTime + 4 * DELAY_MULTIPLIER + 100);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(true);
}
/**
* Test that an animation runs synchronously if its duration is 0.
*/
public void testRunNow() {
final TestAnimation anim = new TestAnimation();
anim.run(2 * DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.reset();
// Update the progress.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(true);
anim.assertCompleted(false);
anim.reset();
// Complete the animation.
executeLastCallbackAt(curTime + 2 * DELAY_MULTIPLIER + 100);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(true);
}
/**
* Test running an animation that started in the past.
*/
public void testRunPast() {
final TestAnimation anim = new TestAnimation();
anim.run(3 * DELAY_MULTIPLIER, curTime - DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(false);
anim.reset();
// Update the progress.
executeLastCallbackAt(curTime + DELAY_MULTIPLIER);
anim.assertStarted(false);
anim.assertUpdated(true);
anim.assertCompleted(false);
anim.reset();
// Complete the animation.
executeLastCallbackAt(curTime + 2 * DELAY_MULTIPLIER + 100);
anim.assertStarted(false);
anim.assertUpdated(false);
anim.assertCompleted(true);
}
/**
* Test running an animation that started and finished in the past.
*/
public void testRunPaster() {
final TestAnimation anim = new TestAnimation();
anim.run(DELAY_MULTIPLIER, curTime - 2 * DELAY_MULTIPLIER);
anim.assertStarted(true);
anim.assertUpdated(false);
anim.assertCompleted(true);
}
@Override
protected void gwtSetUp() throws Exception {
scheduler = new StubAnimationScheduler();
callbacks = scheduler.getAnimationCallbacks();
curTime = Duration.currentTimeMillis();
}
@Override
protected void gwtTearDown() throws Exception {
scheduler = null;
callbacks = null;
}
/**
* Execute the last callback requested from the scheduler at the specified
* time.
*
* @param timestamp the time to pass to the callback
*/
private void executeLastCallbackAt(double timestamp) {
assertTrue(callbacks.size() > 0);
AnimationCallback callback = callbacks.remove(callbacks.size() - 1);
callback.execute(timestamp);
}
}