| /* |
| * 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(); |
| assertFalse(anim.isRunning()); |
| anim.run(DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| anim.assertStarted(true); |
| anim.assertUpdated(false); |
| anim.assertCompleted(false); |
| anim.assertCancelled(false); |
| anim.reset(); |
| |
| // Complete the animation. |
| // TODO(cromwellian) remove this 4000 hack after the failure is found |
| executeLastCallbackAt(curTime + DELAY_MULTIPLIER + 4000); |
| assertFalse(anim.isRunning()); |
| 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. |
| assertFalse(anim.isRunning()); |
| 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(); |
| assertFalse(anim.isRunning()); |
| |
| // Run the animation in the future. |
| anim.run(DELAY_MULTIPLIER, curTime + 1000); |
| assertTrue(anim.isRunning()); |
| 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(); |
| assertFalse(anim.isRunning()); |
| 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(); |
| assertFalse(anim.isRunning()); |
| anim.run(10 * DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| anim.assertStarted(true); |
| anim.assertUpdated(false); |
| anim.assertCompleted(false); |
| anim.assertCancelled(false); |
| anim.reset(); |
| |
| |
| // Update the animation. |
| executeLastCallbackAt(curTime + DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| anim.assertStarted(false); |
| anim.assertUpdated(true); |
| anim.assertCompleted(false); |
| anim.assertCancelled(false); |
| anim.reset(); |
| |
| // Cancel the animation. |
| assertEquals(1, callbacks.size()); |
| anim.cancel(); |
| assertFalse(anim.isRunning()); |
| 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. |
| } |
| }; |
| |
| assertFalse(anim.isRunning()); |
| |
| // Run the animation. |
| anim.run(DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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()); |
| assertFalse(anim.isRunning()); |
| } |
| |
| /** |
| * 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(); |
| } |
| }; |
| |
| assertFalse(anim.isRunning()); |
| |
| // Run the animation. |
| anim.run(DELAY_MULTIPLIER); |
| assertFalse(anim.isRunning()); |
| 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(); |
| } |
| }; |
| |
| assertFalse(anim.isRunning()); |
| |
| // Run the animation. |
| anim.run(10 * DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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(); |
| assertFalse(anim.isRunning()); |
| 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); |
| assertTrue(anim.isRunning()); |
| anim.cancel(); |
| assertFalse(anim.isRunning()); |
| 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); |
| } |
| }; |
| |
| assertFalse(anim.isRunning()); |
| |
| // Run the animation. |
| anim.run(DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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(); |
| assertFalse(anim.isRunning()); |
| anim.run(2 * DELAY_MULTIPLIER, curTime + 2 * DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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); |
| assertFalse(anim.isRunning()); |
| } |
| |
| /** |
| * Test that an animation runs synchronously if its duration is 0. |
| */ |
| public void testRunNow() { |
| final TestAnimation anim = new TestAnimation(); |
| assertFalse(anim.isRunning()); |
| anim.run(2 * DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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); |
| assertFalse(anim.isRunning()); |
| } |
| |
| /** |
| * Test running an animation that started in the past. |
| */ |
| public void testRunPast() { |
| final TestAnimation anim = new TestAnimation(); |
| assertFalse(anim.isRunning()); |
| anim.run(3 * DELAY_MULTIPLIER, curTime - DELAY_MULTIPLIER); |
| assertTrue(anim.isRunning()); |
| 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); |
| assertFalse(anim.isRunning()); |
| } |
| |
| /** |
| * Test running an animation that started and finished in the past. |
| */ |
| public void testRunPaster() { |
| final TestAnimation anim = new TestAnimation(); |
| assertFalse(anim.isRunning()); |
| anim.run(DELAY_MULTIPLIER, curTime - 2 * DELAY_MULTIPLIER); |
| anim.assertStarted(true); |
| anim.assertUpdated(false); |
| anim.assertCompleted(true); |
| assertFalse(anim.isRunning()); |
| } |
| |
| @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); |
| } |
| } |