1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.animation;
  27 
  28 import java.io.IOException;
  29 import java.io.OutputStream;
  30 import java.io.PrintStream;
  31 
  32 import com.sun.javafx.tk.Toolkit;
  33 import javafx.animation.Animation.Status;
  34 import javafx.event.ActionEvent;
  35 import javafx.event.EventHandler;
  36 import javafx.util.Duration;
  37 import com.sun.scenario.animation.AbstractMasterTimerMock;
  38 import com.sun.scenario.animation.shared.ClipEnvelopeMock;
  39 import org.junit.After;
  40 import org.junit.Before;
  41 import org.junit.Test;
  42 
  43 import static org.junit.Assert.*;
  44 
  45 public class AnimationTest {
  46 
  47     private static final Duration ONE_SEC = Duration.millis(1000);
  48     private static final Duration TWO_SECS = Duration.millis(2000);
  49     private static final Duration THREE_SECS = Duration.millis(3000);
  50     private static final Duration FOUR_SECS = Duration.millis(4000);
  51 
  52     private static final double DEFAULT_RATE = 1.0;
  53     private static final int DEFAULT_REPEAT_COUNT = 1;
  54     private static final boolean DEFAULT_AUTO_REVERSE = false;
  55 
  56     private static final double EPSILON = 1e-12;
  57 
  58     private AbstractMasterTimerMock timer;
  59     private Animation animation;
  60     private ClipEnvelopeMock clipEnvelope;
  61 
  62     @Before
  63     public void setUp() {
  64         timer = new AbstractMasterTimerMock();
  65         clipEnvelope = new ClipEnvelopeMock();
  66         animation = new AnimationImpl(timer, clipEnvelope, 1);
  67         animation.setCycleDuration(ONE_SEC);
  68         clipEnvelope.setAnimation(animation);
  69     }
  70 
  71     @After
  72     public void tearDown() {
  73         animation.stop();
  74     }
  75 
  76     @Test
  77     public void testConstructors() {
  78         final Animation animation0 = new AnimationImpl();
  79         assertEquals(DEFAULT_RATE, animation0.getRate(), EPSILON);
  80         assertEquals(0.0, animation0.getCurrentRate(), EPSILON);
  81         assertEquals(Duration.ZERO, animation0.getCycleDuration());
  82         assertEquals(Duration.ZERO, animation0.getTotalDuration());
  83         assertEquals(Duration.ZERO, animation0.getCurrentTime());
  84         assertEquals(DEFAULT_REPEAT_COUNT, animation0.getCycleCount());
  85         assertEquals(DEFAULT_AUTO_REVERSE, animation0.isAutoReverse());
  86         assertEquals(Status.STOPPED, animation0.getStatus());
  87         assertEquals(6000.0 / Toolkit.getToolkit().getMasterTimer().getDefaultResolution(), animation0.getTargetFramerate(), EPSILON);
  88         assertEquals(null, animation0.getOnFinished());
  89         assertEquals(0, animation0.getCuePoints().size());
  90 
  91         final Animation animation1 = new AnimationImpl(timer, clipEnvelope, 600);
  92         assertEquals(10.0, animation1.getTargetFramerate(), EPSILON);
  93     }
  94 
  95     @Test
  96     public void testReadOnlyProperties() {
  97         // currentRate
  98         assertEquals("currentRate", animation.currentRateProperty().getName());
  99         assertEquals(animation, animation.currentRateProperty().getBean());
 100 
 101         // cycleDuration
 102         assertEquals("cycleDuration", animation.cycleDurationProperty().getName());
 103         assertEquals(animation, animation.cycleDurationProperty().getBean());
 104 
 105         // totalDuration
 106         assertEquals("totalDuration", animation.totalDurationProperty().getName());
 107         assertEquals(animation, animation.totalDurationProperty().getBean());
 108 
 109         // currentTime
 110         assertEquals("currentTime", animation.currentTimeProperty().getName());
 111         assertEquals(animation, animation.currentTimeProperty().getBean());
 112 
 113         // status
 114         assertEquals("status", animation.statusProperty().getName());
 115         assertEquals(animation, animation.statusProperty().getBean());
 116 
 117     }
 118 
 119     @Test
 120     public void testCalculationOfTotalDuration() {
 121         // 1000ms
 122         assertEquals(ONE_SEC, animation.getTotalDuration());
 123         animation.setCycleCount(0);
 124         assertEquals(ONE_SEC, animation.getTotalDuration());
 125         animation.setCycleCount(7);
 126         assertEquals(ONE_SEC.multiply(7), animation.getTotalDuration());
 127         animation.setCycleCount(Animation.INDEFINITE);
 128         assertEquals(Duration.INDEFINITE, animation.getTotalDuration());
 129         animation.setCycleCount(1);
 130 
 131         // Duration.ZERO
 132         animation.setCycleDuration(Duration.ZERO);
 133         assertEquals(Duration.ZERO, animation.getTotalDuration());
 134         animation.setCycleCount(0);
 135         assertEquals(Duration.ZERO, animation.getTotalDuration());
 136         animation.setCycleCount(7);
 137         assertEquals(Duration.ZERO, animation.getTotalDuration());
 138         animation.setCycleCount(Animation.INDEFINITE);
 139         assertEquals(Duration.ZERO, animation.getTotalDuration());
 140         animation.setCycleCount(1);
 141 
 142         // Duration.INDEFINITE
 143         animation.setCycleDuration(Duration.INDEFINITE);
 144         assertEquals(Duration.INDEFINITE, animation.getTotalDuration());
 145         animation.setCycleCount(0);
 146         assertEquals(Duration.INDEFINITE, animation.getTotalDuration());
 147         animation.setCycleCount(7);
 148         assertEquals(Duration.INDEFINITE, animation.getTotalDuration());
 149         animation.setCycleCount(Animation.INDEFINITE);
 150         assertEquals(Duration.INDEFINITE, animation.getTotalDuration());
 151         animation.setCycleCount(1);
 152     }
 153 
 154     @Test
 155     public void testDecreaseTotalDuration() {
 156         animation.jumpTo(ONE_SEC);
 157         animation.setCycleDuration(ONE_SEC.divide(2));
 158         assertEquals(ONE_SEC.divide(2), animation.getCurrentTime());
 159         animation.setCycleDuration(Duration.ZERO);
 160         assertEquals(Duration.ZERO, animation.getCurrentTime());
 161     }
 162 
 163     @Test
 164     public void testJumpTo() {
 165         animation.setCycleDuration(TWO_SECS);
 166 
 167         // cycleCount = 1
 168         animation.jumpTo(ONE_SEC);
 169         assertEquals(ONE_SEC, animation.getCurrentTime());
 170         assertEquals(6000, clipEnvelope.getLastJumpTo());
 171         animation.jumpTo(TWO_SECS);
 172         assertEquals(TWO_SECS, animation.getCurrentTime());
 173         assertEquals(12000, clipEnvelope.getLastJumpTo());
 174         animation.jumpTo(Duration.ZERO);
 175         assertEquals(Duration.ZERO, animation.getCurrentTime());
 176         assertEquals(0, clipEnvelope.getLastJumpTo());
 177         animation.jumpTo(TWO_SECS.add(Duration.ONE));
 178         assertEquals(TWO_SECS, animation.getCurrentTime());
 179         assertEquals(12000, clipEnvelope.getLastJumpTo());
 180         animation.jumpTo(Duration.ONE.negate());
 181         assertEquals(Duration.ZERO, animation.getCurrentTime());
 182         assertEquals(0, clipEnvelope.getLastJumpTo());
 183 
 184         // cycleCount = 2
 185         animation.setCycleCount(2);
 186         animation.jumpTo(ONE_SEC);
 187         assertEquals(ONE_SEC, animation.getCurrentTime());
 188         assertEquals(6000, clipEnvelope.getLastJumpTo());
 189         animation.jumpTo(TWO_SECS);
 190         assertEquals(TWO_SECS, animation.getCurrentTime());
 191         assertEquals(12000, clipEnvelope.getLastJumpTo());
 192         animation.jumpTo(THREE_SECS);
 193         assertEquals(ONE_SEC, animation.getCurrentTime());
 194         assertEquals(18000, clipEnvelope.getLastJumpTo());
 195         animation.jumpTo(FOUR_SECS);
 196         assertEquals(TWO_SECS, animation.getCurrentTime());
 197         assertEquals(24000, clipEnvelope.getLastJumpTo());
 198         animation.jumpTo(Duration.ZERO);
 199         assertEquals(Duration.ZERO, animation.getCurrentTime());
 200         assertEquals(0, clipEnvelope.getLastJumpTo());
 201         animation.jumpTo(FOUR_SECS.add(Duration.ONE));
 202         assertEquals(TWO_SECS, animation.getCurrentTime());
 203         assertEquals(24000, clipEnvelope.getLastJumpTo());
 204         animation.jumpTo(Duration.ONE.negate());
 205         assertEquals(Duration.ZERO, animation.getCurrentTime());
 206         assertEquals(0, clipEnvelope.getLastJumpTo());
 207     }
 208 
 209     @Test
 210     public void testJumpTo_ZeroLengthAnimation() {
 211         animation.setCycleDuration(Duration.ZERO);
 212 
 213         // cycleCount = 1
 214         animation.jumpTo(Duration.ZERO);
 215         assertEquals(Duration.ZERO, animation.getCurrentTime());
 216         assertEquals(0, clipEnvelope.getLastJumpTo());
 217         animation.jumpTo(ONE_SEC);
 218         assertEquals(Duration.ZERO, animation.getCurrentTime());
 219         assertEquals(0, clipEnvelope.getLastJumpTo());
 220 
 221         // cycleCount = 2
 222         animation.setCycleCount(2);
 223         animation.jumpTo(Duration.ZERO);
 224         assertEquals(Duration.ZERO, animation.getCurrentTime());
 225         assertEquals(0, clipEnvelope.getLastJumpTo());
 226         animation.jumpTo(ONE_SEC);
 227         assertEquals(Duration.ZERO, animation.getCurrentTime());
 228         assertEquals(0, clipEnvelope.getLastJumpTo());
 229     }
 230 
 231     @Test
 232     public void testDurationRoundingError() {
 233         final Duration duration = Duration.millis(0.01);
 234         animation.setCycleDuration(duration);
 235         assertTrue(animation.getCycleDuration().greaterThan(Duration.ZERO));
 236 
 237         // should not be startable
 238         assertFalse(animation.impl_startable(true));
 239 
 240         // jump
 241         animation.jumpTo(Duration.ZERO);
 242         assertEquals(Duration.ZERO, animation.getCurrentTime());
 243         assertEquals(0, clipEnvelope.getLastJumpTo());
 244     }
 245 
 246     @Test(expected=NullPointerException.class)
 247     public void testJumpTo_Null() {
 248         animation.jumpTo((Duration)null);
 249     }
 250 
 251     @Test(expected=IllegalArgumentException.class)
 252     public void testJumpTo_UNKNOWN() {
 253         animation.jumpTo(Duration.UNKNOWN);
 254     }
 255 
 256     @Test
 257     public void testJumpToCuePoint_Default() {
 258         animation.getCuePoints().put("ONE_SEC", ONE_SEC);
 259         animation.getCuePoints().put("THREE_SECS", THREE_SECS);
 260         animation.setCycleDuration(TWO_SECS);
 261 
 262         // normal jumps
 263         animation.jumpTo("end");
 264         assertEquals(TWO_SECS, animation.getCurrentTime());
 265         animation.jumpTo("start");
 266         assertEquals(Duration.ZERO, animation.getCurrentTime());
 267         animation.jumpTo("ONE_SEC");
 268         assertEquals(ONE_SEC, animation.getCurrentTime());
 269 
 270         // jump to non-existing cue-point
 271         animation.jumpTo("undefined");
 272         assertEquals(ONE_SEC, animation.getCurrentTime());
 273 
 274         // jump to cue-point behind end of animation
 275         animation.jumpTo("THREE_SECS");
 276         assertEquals(TWO_SECS, animation.getCurrentTime());
 277     }
 278 
 279     @Test
 280     public void testJumpToCuePoint_ZeroLengthAnimation() {
 281         animation.getCuePoints().put("ONE_SEC", ONE_SEC);
 282         animation.setCycleDuration(Duration.ZERO);
 283 
 284         animation.jumpTo("start");
 285         assertEquals(Duration.ZERO, animation.getCurrentTime());
 286         animation.jumpTo("end");
 287         assertEquals(Duration.ZERO, animation.getCurrentTime());
 288         animation.jumpTo("ONE_SEC");
 289         assertEquals(Duration.ZERO, animation.getCurrentTime());
 290     }
 291 
 292     @Test(expected=NullPointerException.class)
 293     public void testJumpToCuePoint_Null() {
 294         animation.jumpTo((String)null);
 295     }
 296 
 297     @Test
 298     public void testPlay() {
 299         final OnFinishedListener listener = new OnFinishedListener();
 300         animation.setOnFinished(listener);
 301 
 302         // stopped timeline
 303         listener.wasCalled = false;
 304         animation.play();
 305         assertEquals(Status.RUNNING, animation.getStatus());
 306         assertFalse(listener.wasCalled);
 307         assertTrue(timer.containsPulseReceiver(animation.pulseReceiver));
 308 
 309         // calling play on playing timeline
 310         animation.play();
 311         assertEquals(Status.RUNNING, animation.getStatus());
 312         assertFalse(listener.wasCalled);
 313         assertTrue(timer.containsPulseReceiver(animation.pulseReceiver));
 314         animation.stop();
 315 
 316         // stopped timeline, rate = 0
 317         listener.wasCalled = false;
 318         animation.setRate(0.0);
 319         animation.play();
 320         assertEquals(Status.RUNNING, animation.getStatus());
 321         assertFalse(listener.wasCalled);
 322         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 323         animation.stop();
 324         animation.setRate(1.0);
 325 
 326         // stopped timeline, cycleDuration = 0
 327         listener.wasCalled = false;
 328         animation.setCycleDuration(Duration.ZERO);
 329         animation.play();
 330         assertEquals(Status.STOPPED, animation.getStatus());
 331         assertTrue(listener.wasCalled);
 332         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 333         animation.stop();
 334         animation.setCycleDuration(ONE_SEC);
 335 
 336         // paused timeline
 337         animation.play();
 338         animation.pause();
 339         animation.play();
 340         assertEquals(Status.RUNNING, animation.getStatus());
 341         assertTrue(timer.containsPulseReceiver(animation.pulseReceiver));
 342         animation.stop();
 343 
 344         // paused timeline, rate = 0
 345         animation.play();
 346         animation.pause();
 347         animation.setRate(0.0);
 348         animation.play();
 349         assertEquals(Status.RUNNING, animation.getStatus());
 350         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 351     }
 352 
 353     @Test
 354     public void testStop() {
 355         // stopped timeline
 356         animation.jumpTo(ONE_SEC);
 357         animation.stop();
 358         assertEquals(Status.STOPPED, animation.getStatus());
 359         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 360         assertEquals(ONE_SEC, animation.getCurrentTime());
 361         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 362 
 363         // playing timeline
 364         animation.jumpTo(ONE_SEC);
 365         animation.play();
 366         animation.stop();
 367         assertEquals(Status.STOPPED, animation.getStatus());
 368         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 369         assertEquals(Duration.ZERO, animation.getCurrentTime());
 370         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 371 
 372         // paused timeline
 373         animation.jumpTo(ONE_SEC);
 374         animation.play();
 375         animation.pause();
 376         animation.stop();
 377         assertEquals(Status.STOPPED, animation.getStatus());
 378         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 379         assertEquals(Duration.ZERO, animation.getCurrentTime());
 380         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 381     }
 382 
 383     @Test
 384     public void testPause() {
 385         // stopped timeline
 386         animation.jumpTo(ONE_SEC);
 387         animation.pause();
 388         assertEquals(Status.STOPPED, animation.getStatus());
 389         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 390         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 391 
 392         // playing timeline
 393         animation.jumpTo(ONE_SEC);
 394         animation.play();
 395         animation.pause();
 396         assertEquals(Status.PAUSED, animation.getStatus());
 397         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 398         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 399 
 400         // paused timeline
 401         animation.jumpTo(ONE_SEC);
 402         animation.play();
 403         animation.pause();
 404         animation.pause();
 405         assertEquals(Status.PAUSED, animation.getStatus());
 406         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 407         assertFalse(timer.containsPulseReceiver(animation.pulseReceiver));
 408     }
 409 
 410     @Test
 411     public void testStart() {
 412         // cycleDuration = 1000ms
 413         assertTrue(animation.impl_startable(true));
 414         animation.impl_start(true);
 415         assertEquals(Status.RUNNING, animation.getStatus());
 416         assertEquals(1.0, animation.getCurrentRate(), EPSILON);
 417         assertEquals(6000, clipEnvelope.getTimelineTicks());
 418         assertEquals(1.0, clipEnvelope.getRate(), EPSILON);
 419         assertEquals(false, clipEnvelope.getAutoReverse());
 420         assertEquals(1, clipEnvelope.getCycleCount());
 421         animation.impl_finished();
 422 
 423         // change all values and try again
 424         animation.setCycleDuration(TWO_SECS);
 425         animation.setRate(-2.0);
 426         animation.setAutoReverse(true);
 427         animation.setCycleCount(Animation.INDEFINITE);
 428         assertTrue(animation.impl_startable(true));
 429         animation.impl_start(true);
 430         assertEquals(Status.RUNNING, animation.getStatus());
 431         assertEquals(-2.0, animation.getCurrentRate(), EPSILON);
 432         assertEquals(12000, clipEnvelope.getTimelineTicks());
 433         assertEquals(-2.0, clipEnvelope.getRate(), EPSILON);
 434         assertEquals(true, clipEnvelope.getAutoReverse());
 435         assertEquals(Animation.INDEFINITE, clipEnvelope.getCycleCount());
 436         animation.impl_finished();
 437 
 438         // cycleDuration = 0
 439         animation.setCycleDuration(Duration.ZERO);
 440         assertFalse(animation.impl_startable(true));
 441     }
 442 
 443     @Test
 444     public void testChangeCycleDurationAfterFinish_RT32657() {
 445         animation.setCycleDuration(TWO_SECS);
 446         animation.play();
 447         assertEquals(Status.RUNNING, animation.getStatus());
 448         assertEquals(Duration.ZERO, animation.getCurrentTime());
 449         animation.impl_setCurrentTicks(12000);
 450         assertEquals(TWO_SECS, animation.getCurrentTime());
 451         animation.impl_finished();
 452 
 453         animation.setCycleDuration(ONE_SEC);
 454         animation.play();
 455         assertEquals(Status.RUNNING, animation.getStatus());
 456         assertEquals(Duration.ZERO, animation.getCurrentTime());
 457     }
 458 
 459     @Test
 460     public void testFinished() {
 461         final OnFinishedListener listener = new OnFinishedListener();
 462         animation.setOnFinished(listener);
 463 
 464         // stopped timeline
 465         animation.impl_finished();
 466         assertEquals(Status.STOPPED, animation.getStatus());
 467         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 468         assertTrue(listener.wasCalled);
 469 
 470         // playing timeline
 471         animation.play();
 472         animation.impl_finished();
 473         assertEquals(Status.STOPPED, animation.getStatus());
 474         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 475         assertTrue(listener.wasCalled);
 476 
 477         // paused timeline
 478         animation.play();
 479         animation.pause();
 480         animation.impl_finished();
 481         assertEquals(Status.STOPPED, animation.getStatus());
 482         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 483         assertTrue(listener.wasCalled);
 484     }
 485 
 486     @Test
 487     public void testFinished_ThrowsException() {
 488         final OnFinishedExceptionListener listener = new OnFinishedExceptionListener();
 489         final PrintStream defaultErrorStream = System.err;
 490         final PrintStream nirvana = new PrintStream(new OutputStream() {
 491             @Override
 492             public void write(int i) throws IOException {
 493             }
 494         });
 495         animation.setOnFinished(listener);
 496 
 497         // stopped timeline
 498         try {
 499             System.setErr(nirvana);
 500         } catch (SecurityException ex) {
 501             // ignore
 502         }
 503         animation.impl_finished();
 504         try {
 505             System.setErr(defaultErrorStream);
 506         } catch (SecurityException ex) {
 507             // ignore
 508         }
 509         assertEquals(Status.STOPPED, animation.getStatus());
 510         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 511         assertTrue(listener.wasCalled);
 512 
 513         // playing timeline
 514         animation.play();
 515         try {
 516             System.setErr(nirvana);
 517         } catch (SecurityException ex) {
 518             // ignore
 519         }
 520         animation.impl_finished();
 521         try {
 522             System.setErr(defaultErrorStream);
 523         } catch (SecurityException ex) {
 524             // ignore
 525         }
 526         assertEquals(Status.STOPPED, animation.getStatus());
 527         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 528         assertTrue(listener.wasCalled);
 529 
 530         // paused timeline
 531         animation.play();
 532         animation.pause();
 533         try {
 534             System.setErr(nirvana);
 535         } catch (SecurityException ex) {
 536             // ignore
 537         }
 538         animation.impl_finished();
 539         try {
 540             System.setErr(defaultErrorStream);
 541         } catch (SecurityException ex) {
 542             // ignore
 543         }
 544         assertEquals(Status.STOPPED, animation.getStatus());
 545         assertEquals(0.0, animation.getCurrentRate(), EPSILON);
 546         assertTrue(listener.wasCalled);
 547     }
 548 
 549     @Test
 550     public void testFullSpeedResolution() {
 551         final int resolution = Toolkit.getToolkit().getMasterTimer().getDefaultResolution();
 552 
 553         // send pulse
 554         animation.impl_timePulse(4 * resolution);
 555         assertEquals(4 * resolution, clipEnvelope.getLastTimePulse());
 556 
 557         // send half pulse
 558         animation.impl_timePulse(Math.round(4.5 * resolution));
 559         assertEquals(Math.round(4.5 * resolution), clipEnvelope.getLastTimePulse());
 560 
 561         // send full pulse
 562         animation.impl_timePulse(Math.round(5.5 * resolution));
 563         assertEquals(Math.round(5.5 * resolution), clipEnvelope.getLastTimePulse());
 564 
 565         // send half pulse
 566         animation.impl_timePulse(6 * resolution);
 567         assertEquals(6 * resolution, clipEnvelope.getLastTimePulse());
 568 
 569     }
 570 
 571     @Test
 572     public void testCustomResolution() {
 573         final int resolution = 100;
 574         animation = new AnimationImpl(timer, clipEnvelope, resolution);
 575 
 576         // send pulse
 577         animation.impl_timePulse(4 * resolution);
 578         assertEquals(4 * resolution, clipEnvelope.getLastTimePulse());
 579 
 580         // send half pulse
 581         animation.impl_timePulse(Math.round(4.5 * resolution));
 582         assertEquals(0, clipEnvelope.getLastTimePulse());
 583 
 584         // send full pulse
 585         animation.impl_timePulse(Math.round(5.5 * resolution));
 586         assertEquals(Math.round(5.5 * resolution), clipEnvelope.getLastTimePulse());
 587 
 588         // send half pulse, this time it should trigger a pulse
 589         animation.impl_timePulse(6 * resolution);
 590         assertEquals(6 * resolution, clipEnvelope.getLastTimePulse());
 591 
 592     }
 593 
 594     private static class OnFinishedListener implements EventHandler<ActionEvent> {
 595 
 596         private boolean wasCalled = false;
 597 
 598         @Override
 599         public void handle(ActionEvent event) {
 600             wasCalled = true;
 601         }
 602 
 603     }
 604 
 605     private static class OnFinishedExceptionListener implements EventHandler<ActionEvent> {
 606 
 607         private boolean wasCalled = false;
 608 
 609         @Override
 610         public void handle(ActionEvent event) {
 611             wasCalled = true;
 612             throw new RuntimeException("Test Exception");
 613         }
 614 
 615     }
 616 
 617 }