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 test.com.sun.scenario.animation.shared;
  27 
  28 import com.sun.javafx.animation.TickCalculation;
  29 import com.sun.scenario.animation.shared.GeneralClipInterpolatorShim;
  30 import static org.junit.Assert.assertEquals;
  31 import static org.junit.Assert.assertNotSame;
  32 import static org.junit.Assert.assertSame;
  33 import static org.junit.Assert.assertTrue;
  34 import javafx.animation.KeyFrame;
  35 import javafx.animation.KeyValue;
  36 import javafx.beans.property.IntegerProperty;
  37 import javafx.beans.property.SimpleIntegerProperty;
  38 import javafx.util.Duration;
  39 
  40 import org.junit.Test;
  41 
  42 public class GeneralClipInterpolatorTest {
  43         
  44         @Test
  45         public void testSetKeyFrame() {
  46         final KeyFrame kf1 = new KeyFrame(Duration.ZERO);
  47         final KeyFrame kf2 = new KeyFrame(Duration.millis(1000));
  48         final KeyFrame kf3 = new KeyFrame(Duration.millis(2000));
  49         final GeneralClipInterpolatorShim gci = new GeneralClipInterpolatorShim(new KeyFrame[] {kf1, kf2, kf3}, new long[] {0, 6000, 6000});
  50         
  51         assertSame   (gci, gci.setKeyFrames(new KeyFrame[]{kf1, kf2, kf3}, new long[] {0, 6000, 6000}));
  52         assertNotSame(gci, gci.setKeyFrames(new KeyFrame[]{kf1, kf2     }, new long[] {0, 6000      }));
  53         assertNotSame(gci, gci.setKeyFrames(new KeyFrame[]{kf1,      kf3}, new long[] {0,       6000}));
  54         assertSame   (gci, gci.setKeyFrames(new KeyFrame[]{kf1          }, new long[] {0            }));
  55         assertSame   (gci, gci.setKeyFrames(new KeyFrame[]{     kf2, kf3}, new long[] {   6000, 6000}));
  56         assertNotSame(gci, gci.setKeyFrames(new KeyFrame[]{     kf2     }, new long[] {   6000      }));
  57         assertNotSame(gci, gci.setKeyFrames(new KeyFrame[]{          kf3}, new long[] {         6000}));
  58         assertSame   (gci, gci.setKeyFrames(new KeyFrame[]{             }, new long[] {             }));
  59         }
  60         
  61         @Test
  62         public void test_OneKeyFrameOnly() {
  63                 // main purpose of this test is to ensure we do not throw exceptions
  64                 final KeyFrame kf1 = new KeyFrame(Duration.ZERO);
  65                 final KeyFrame kf2 = new KeyFrame(Duration.ZERO);
  66                 
  67         // one key frame
  68         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {kf1}, new long[] {0});
  69         gci1.validate(true);
  70         gci1.validate(true);
  71         gci1.setKeyFrames(new KeyFrame[]{kf2}, new long[] {6000});
  72         gci1.validate(true);
  73         gci1.setKeyFrames(new KeyFrame[]{}, new long[] {});
  74         gci1.validate(true);
  75         
  76         // no key frames
  77         final GeneralClipInterpolatorShim gci2 = new GeneralClipInterpolatorShim (new KeyFrame[] {}, new long[] {});
  78         gci2.validate(true);
  79         gci2.validate(true);
  80         gci2.setKeyFrames(new KeyFrame[]{kf1}, new long[] {0});
  81         gci2.validate(true);
  82     }
  83 
  84     @Test
  85     public void test_NoKeyValues() {
  86         final KeyFrame start1 = new KeyFrame(Duration.ZERO);
  87         final KeyFrame start2 = new KeyFrame(Duration.ZERO);
  88         final KeyFrame end1 = new KeyFrame(Duration.millis(1000));
  89         final KeyFrame end2a = new KeyFrame(Duration.millis(2000));
  90         final KeyFrame end2b = new KeyFrame(Duration.millis(3000));
  91         
  92         // four key frames
  93         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, start2, end1, end2a}, new long[] {0, 0, 6000, 12000});
  94         gci1.validate(true);
  95         gci1.interpolate(TickCalculation.fromMillis(300));
  96         gci1.interpolate(TickCalculation.fromMillis(1300));
  97         
  98         gci1.validate(true);
  99         gci1.interpolate(TickCalculation.fromMillis(800));
 100         gci1.interpolate(TickCalculation.fromMillis(1800));
 101         
 102         gci1.setKeyFrames(new KeyFrame[]{start1, start2, end1, end2b}, new long[] {0, 0, 6000, 18000});
 103         gci1.interpolate(TickCalculation.fromMillis(400));
 104         gci1.interpolate(TickCalculation.fromMillis(1400));
 105         
 106         gci1.validate(true);
 107         gci1.interpolate(TickCalculation.fromMillis(600));
 108         gci1.interpolate(TickCalculation.fromMillis(1600));
 109         
 110         // two key frames
 111         final GeneralClipInterpolatorShim gci2 = new GeneralClipInterpolatorShim (new KeyFrame[] {end1, end2a}, new long[] {6000, 12000});
 112         gci2.validate(true);
 113         gci2.interpolate(TickCalculation.fromMillis(300));
 114         gci2.interpolate(TickCalculation.fromMillis(1300));
 115         
 116         gci2.validate(true);
 117         gci2.interpolate(TickCalculation.fromMillis(800));
 118         gci2.interpolate(TickCalculation.fromMillis(1800));
 119         
 120         gci2.setKeyFrames(new KeyFrame[]{end1, end2b}, new long[] {6000, 18000});
 121         gci2.interpolate(TickCalculation.fromMillis(400));
 122         gci2.interpolate(TickCalculation.fromMillis(1400));
 123         
 124         gci2.validate(true);
 125         gci2.interpolate(TickCalculation.fromMillis(600));
 126         gci2.interpolate(TickCalculation.fromMillis(1600));
 127     }
 128 
 129     @Test
 130     public void test_ThreeKeyFrames_OneKeyValue() {
 131         final IntegerProperty v = new SimpleIntegerProperty();
 132         final KeyFrame start1 = new KeyFrame(Duration.ZERO);
 133         final KeyFrame start2 = new KeyFrame(Duration.ZERO, new KeyValue(v, 30));
 134         final KeyFrame mid1 = new KeyFrame(Duration.millis(1000), new KeyValue(v, 40));
 135         final KeyFrame end1 = new KeyFrame(Duration.millis(2000), new KeyValue(v, 60));
 136         final KeyFrame end2 = new KeyFrame(Duration.millis(4000), new KeyValue(v, 70));
 137         
 138         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, start2, mid1, end1}, new long[] {0, 0, 6000, 12000});
 139         v.set(0);
 140         gci1.validate(true);
 141         gci1.interpolate(TickCalculation.fromMillis(0));
 142         assertEquals(30, v.get());
 143         gci1.interpolate(TickCalculation.fromMillis(300));
 144         assertEquals(33, v.get());
 145         gci1.interpolate(TickCalculation.fromMillis(1000));
 146         assertEquals(40, v.get());
 147         gci1.interpolate(TickCalculation.fromMillis(1600));
 148         assertEquals(52, v.get());
 149         gci1.interpolate(TickCalculation.fromMillis(2000));
 150         assertEquals(60, v.get());
 151         
 152         // re-validate
 153         v.set(20);
 154         gci1.validate(true);
 155         gci1.interpolate(TickCalculation.fromMillis(0));
 156         assertEquals(30, v.get());
 157         gci1.interpolate(TickCalculation.fromMillis(800));
 158         assertEquals(38, v.get());
 159         gci1.interpolate(TickCalculation.fromMillis(1000));
 160         assertEquals(40, v.get());
 161         gci1.interpolate(TickCalculation.fromMillis(1200));
 162         assertEquals(44, v.get());
 163         gci1.interpolate(TickCalculation.fromMillis(2000));
 164         assertEquals(60, v.get());
 165         
 166         // set new key frames
 167         gci1.setKeyFrames(new KeyFrame[]{start1, start2, mid1, end2}, new long[] {0, 0, 6000, 24000});
 168         v.set(0);
 169         gci1.interpolate(TickCalculation.fromMillis(0));
 170         assertEquals(30, v.get());
 171         gci1.interpolate(TickCalculation.fromMillis(600));
 172         assertEquals(36, v.get());
 173         gci1.interpolate(TickCalculation.fromMillis(1000));
 174         assertEquals(40, v.get());
 175         gci1.interpolate(TickCalculation.fromMillis(1300));
 176         assertEquals(46, v.get());
 177         gci1.interpolate(TickCalculation.fromMillis(2000));
 178         assertEquals(60, v.get());
 179         
 180         // validate new key frames
 181         v.set(0);
 182         gci1.validate(true);
 183         gci1.interpolate(TickCalculation.fromMillis(0));
 184         assertEquals(30, v.get());
 185         gci1.interpolate(TickCalculation.fromMillis(700));
 186         assertEquals(37, v.get());
 187         gci1.interpolate(TickCalculation.fromMillis(1000));
 188         assertEquals(40, v.get());
 189         gci1.interpolate(TickCalculation.fromMillis(1300));
 190         assertEquals(43, v.get());
 191         gci1.interpolate(TickCalculation.fromMillis(4000));
 192         assertEquals(70, v.get());
 193     }
 194 
 195     @Test
 196     public void test_TwoKeyFrames_OneKeyValue() {
 197         final IntegerProperty v = new SimpleIntegerProperty();
 198         final KeyFrame mid1 = new KeyFrame(Duration.millis(1000), new KeyValue(v, 40));
 199         final KeyFrame end1 = new KeyFrame(Duration.millis(2000), new KeyValue(v, 60));
 200         final KeyFrame end2 = new KeyFrame(Duration.millis(4000), new KeyValue(v, 70));
 201 
 202         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {mid1, end1}, new long[] {6000, 12000});
 203         v.set(0);
 204         gci1.validate(true);
 205         gci1.interpolate(TickCalculation.fromMillis(0));
 206         assertEquals( 0, v.get());
 207         gci1.interpolate(TickCalculation.fromMillis(300));
 208         assertEquals(12, v.get());
 209         gci1.interpolate(TickCalculation.fromMillis(1000));
 210         assertEquals(40, v.get());
 211         gci1.interpolate(TickCalculation.fromMillis(1600));
 212         assertEquals(52, v.get());
 213         gci1.interpolate(TickCalculation.fromMillis(2000));
 214         assertEquals(60, v.get());
 215         
 216         // re-validate
 217         v.set(20);
 218         gci1.validate(true);
 219         gci1.interpolate(TickCalculation.fromMillis(0));
 220         assertEquals(20, v.get());
 221         gci1.interpolate(TickCalculation.fromMillis(800));
 222         assertEquals(36, v.get());
 223         gci1.interpolate(TickCalculation.fromMillis(1000));
 224         assertEquals(40, v.get());
 225         gci1.interpolate(TickCalculation.fromMillis(1200));
 226         assertEquals(44, v.get());
 227         gci1.interpolate(TickCalculation.fromMillis(2000));
 228         assertEquals(60, v.get());
 229         
 230         // set new key frames
 231         gci1.setKeyFrames(new KeyFrame[]{mid1, end2}, new long[] {6000, 24000});
 232         v.set(0);
 233         gci1.interpolate(TickCalculation.fromMillis(0));
 234         assertEquals(20, v.get());
 235         gci1.interpolate(TickCalculation.fromMillis(600));
 236         assertEquals(32, v.get());
 237         gci1.interpolate(TickCalculation.fromMillis(1000));
 238         assertEquals(40, v.get());
 239         gci1.interpolate(TickCalculation.fromMillis(1300));
 240         assertEquals(46, v.get());
 241         gci1.interpolate(TickCalculation.fromMillis(2000));
 242         assertEquals(60, v.get());
 243         
 244         // validate new key frames
 245         v.set(0);
 246         gci1.validate(true);
 247         gci1.interpolate(TickCalculation.fromMillis(0));
 248         assertEquals( 0, v.get());
 249         gci1.interpolate(TickCalculation.fromMillis(700));
 250         assertEquals(28, v.get());
 251         gci1.interpolate(TickCalculation.fromMillis(1000));
 252         assertEquals(40, v.get());
 253         gci1.interpolate(TickCalculation.fromMillis(1300));
 254         assertEquals(43, v.get());
 255         gci1.interpolate(TickCalculation.fromMillis(4000));
 256         assertEquals(70, v.get());
 257     }
 258 
 259     @Test
 260     public void test_ThreeKeyFrames_ThreeKeyValues() {
 261         final IntegerProperty v1 = new SimpleIntegerProperty();
 262         final IntegerProperty v2 = new SimpleIntegerProperty();
 263         final IntegerProperty v3 = new SimpleIntegerProperty();
 264         final IntegerProperty v4 = new SimpleIntegerProperty();
 265         final KeyFrame start1 = new KeyFrame(Duration.ZERO, new KeyValue(v3, 230), new KeyValue(v4, 330));
 266         final KeyFrame start2 = new KeyFrame(Duration.ZERO, new KeyValue(v2, 130));
 267         final KeyFrame mid1 = new KeyFrame(Duration.millis(1000), new KeyValue(v1, 40), new KeyValue(v2, 140), new KeyValue(v3, 240));
 268         final KeyFrame end1 = new KeyFrame(Duration.millis(2000), new KeyValue(v1, 60), new KeyValue(v2, 160));
 269         final KeyFrame end2 = new KeyFrame(Duration.millis(4000), new KeyValue(v1, 70), new KeyValue(v2, 170));
 270         
 271         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, start2, mid1, end1}, new long[] {0, 0, 6000, 12000});
 272         v1.set(  0);
 273         v2.set(100);
 274         v3.set(200);
 275         v4.set(300);
 276         gci1.validate(true);
 277         gci1.interpolate(TickCalculation.fromMillis(0));
 278         assertEquals(  0, v1.get());
 279         assertEquals(130, v2.get());
 280         assertEquals(230, v3.get());
 281         assertEquals(300, v4.get());
 282         gci1.interpolate(TickCalculation.fromMillis(300));
 283         assertEquals( 12, v1.get());
 284         assertEquals(133, v2.get());
 285         assertEquals(233, v3.get());
 286         assertEquals(300, v4.get());
 287         gci1.interpolate(TickCalculation.fromMillis(1000));
 288         assertEquals( 40, v1.get());
 289         assertEquals(140, v2.get());
 290         assertEquals(240, v3.get());
 291         assertEquals(300, v4.get());
 292         gci1.interpolate(TickCalculation.fromMillis(1600));
 293         assertEquals( 52, v1.get());
 294         assertEquals(152, v2.get());
 295         assertEquals(240, v3.get());
 296         assertEquals(300, v4.get());
 297         gci1.interpolate(TickCalculation.fromMillis(2000));
 298         assertEquals( 60, v1.get());
 299         assertEquals(160, v2.get());
 300         assertEquals(240, v3.get());
 301         assertEquals(300, v4.get());
 302         
 303         // re-validate
 304         v1.set( 20);
 305         v2.set(120);
 306         v3.set(220);
 307         v4.set(320);
 308         gci1.validate(true);
 309         gci1.interpolate(TickCalculation.fromMillis(0));
 310         assertEquals( 20, v1.get());
 311         assertEquals(130, v2.get());
 312         assertEquals(230, v3.get());
 313         assertEquals(320, v4.get());
 314         gci1.interpolate(TickCalculation.fromMillis(800));
 315         assertEquals( 36, v1.get());
 316         assertEquals(138, v2.get());
 317         assertEquals(238, v3.get());
 318         assertEquals(320, v4.get());
 319         gci1.interpolate(TickCalculation.fromMillis(1000));
 320         assertEquals( 40, v1.get());
 321         assertEquals(140, v2.get());
 322         assertEquals(240, v3.get());
 323         assertEquals(320, v4.get());
 324         gci1.interpolate(TickCalculation.fromMillis(1200));
 325         assertEquals( 44, v1.get());
 326         assertEquals(144, v2.get());
 327         assertEquals(240, v3.get());
 328         assertEquals(320, v4.get());
 329         gci1.interpolate(TickCalculation.fromMillis(2000));
 330         assertEquals( 60, v1.get());
 331         assertEquals(160, v2.get());
 332         assertEquals(240, v3.get());
 333         assertEquals(320, v4.get());
 334         
 335         // change key frames
 336         gci1.setKeyFrames(new KeyFrame[]{start1, start2, mid1, end2}, new long[] {0, 0, 6000, 24000});
 337         v1.set(  0);
 338         v2.set(100);
 339         v3.set(200);
 340         v4.set(300);
 341         gci1.interpolate(TickCalculation.fromMillis(0));
 342         assertEquals( 20, v1.get());
 343         assertEquals(130, v2.get());
 344         assertEquals(230, v3.get());
 345         assertEquals(300, v4.get());
 346         gci1.interpolate(TickCalculation.fromMillis(300));
 347         assertEquals( 26, v1.get());
 348         assertEquals(133, v2.get());
 349         assertEquals(233, v3.get());
 350         assertEquals(300, v4.get());
 351         gci1.interpolate(TickCalculation.fromMillis(1000));
 352         assertEquals( 40, v1.get());
 353         assertEquals(140, v2.get());
 354         assertEquals(240, v3.get());
 355         assertEquals(300, v4.get());
 356         gci1.interpolate(TickCalculation.fromMillis(1300));
 357         assertEquals( 46, v1.get());
 358         assertEquals(146, v2.get());
 359         assertEquals(240, v3.get());
 360         assertEquals(300, v4.get());
 361         gci1.interpolate(TickCalculation.fromMillis(2000));
 362         assertEquals( 60, v1.get());
 363         assertEquals(160, v2.get());
 364         assertEquals(240, v3.get());
 365         assertEquals(300, v4.get());
 366         
 367         // validate new key frames
 368         v1.set( 20);
 369         v2.set(120);
 370         v3.set(220);
 371         v4.set(320);
 372         gci1.validate(true);
 373         gci1.interpolate(TickCalculation.fromMillis(0));
 374         assertEquals( 20, v1.get());
 375         assertEquals(130, v2.get());
 376         assertEquals(230, v3.get());
 377         assertEquals(320, v4.get());
 378         gci1.interpolate(TickCalculation.fromMillis(600));
 379         assertEquals( 32, v1.get());
 380         assertEquals(136, v2.get());
 381         assertEquals(236, v3.get());
 382         assertEquals(320, v4.get());
 383         gci1.interpolate(TickCalculation.fromMillis(1000));
 384         assertEquals( 40, v1.get());
 385         assertEquals(140, v2.get());
 386         assertEquals(240, v3.get());
 387         assertEquals(320, v4.get());
 388         gci1.interpolate(TickCalculation.fromMillis(1300));
 389         assertEquals( 43, v1.get());
 390         assertEquals(143, v2.get());
 391         assertEquals(240, v3.get());
 392         assertEquals(320, v4.get());
 393         gci1.interpolate(TickCalculation.fromMillis(4000));
 394         assertEquals( 70, v1.get());
 395         assertEquals(170, v2.get());
 396         assertEquals(240, v3.get());
 397         assertEquals(320, v4.get());
 398     }
 399 
 400     @Test
 401     public void test_TwoKeyFrames_ThreeKeyValues() {
 402         final IntegerProperty v1 = new SimpleIntegerProperty();
 403         final IntegerProperty v2 = new SimpleIntegerProperty();
 404         final IntegerProperty v3 = new SimpleIntegerProperty();
 405         final KeyFrame mid1 = new KeyFrame(Duration.millis(1000), new KeyValue(v1, 40), new KeyValue(v2, 140), new KeyValue(v3, 240));
 406         final KeyFrame end1 = new KeyFrame(Duration.millis(2000), new KeyValue(v1, 60), new KeyValue(v2, 160), new KeyValue(v3, 260));
 407         final KeyFrame end2 = new KeyFrame(Duration.millis(4000), new KeyValue(v1, 70), new KeyValue(v2, 170), new KeyValue(v3, 270));
 408 
 409         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {mid1, end1}, new long[] {6000, 12000});
 410         v1.set(  0);
 411         v2.set(100);
 412         v3.set(200);
 413         gci1.validate(true);
 414         gci1.interpolate(TickCalculation.fromMillis(0));
 415         assertEquals(  0, v1.get());
 416         assertEquals(100, v2.get());
 417         assertEquals(200, v3.get());
 418         gci1.interpolate(TickCalculation.fromMillis(300));
 419         assertEquals( 12, v1.get());
 420         assertEquals(112, v2.get());
 421         assertEquals(212, v3.get());
 422         gci1.interpolate(TickCalculation.fromMillis(1000));
 423         assertEquals( 40, v1.get());
 424         assertEquals(140, v2.get());
 425         assertEquals(240, v3.get());
 426         gci1.interpolate(TickCalculation.fromMillis(1600));
 427         assertEquals( 52, v1.get());
 428         assertEquals(152, v2.get());
 429         assertEquals(252, v3.get());
 430         gci1.interpolate(TickCalculation.fromMillis(2000));
 431         assertEquals( 60, v1.get());
 432         assertEquals(160, v2.get());
 433         assertEquals(260, v3.get());
 434         
 435         // re-validate
 436         v1.set( 20);
 437         v2.set(120);
 438         v3.set(220);
 439         gci1.validate(true);
 440         gci1.interpolate(TickCalculation.fromMillis(0));
 441         assertEquals( 20, v1.get());
 442         assertEquals(120, v2.get());
 443         assertEquals(220, v3.get());
 444         gci1.interpolate(TickCalculation.fromMillis(800));
 445         assertEquals( 36, v1.get());
 446         assertEquals(136, v2.get());
 447         assertEquals(236, v3.get());
 448         gci1.interpolate(TickCalculation.fromMillis(1000));
 449         assertEquals( 40, v1.get());
 450         assertEquals(140, v2.get());
 451         assertEquals(240, v3.get());
 452         gci1.interpolate(TickCalculation.fromMillis(1200));
 453         assertEquals( 44, v1.get());
 454         assertEquals(144, v2.get());
 455         assertEquals(244, v3.get());
 456         gci1.interpolate(TickCalculation.fromMillis(2000));
 457         assertEquals( 60, v1.get());
 458         assertEquals(160, v2.get());
 459         assertEquals(260, v3.get());
 460         
 461         // change key frames
 462         gci1.setKeyFrames(new KeyFrame[]{mid1, end2}, new long[] {6000, 24000});
 463         v1.set(  0);
 464         v2.set(100);
 465         v3.set(200);
 466         gci1.interpolate(TickCalculation.fromMillis(0));
 467         assertEquals( 20, v1.get());
 468         assertEquals(120, v2.get());
 469         assertEquals(220, v3.get());
 470         gci1.interpolate(TickCalculation.fromMillis(300));
 471         assertEquals( 26, v1.get());
 472         assertEquals(126, v2.get());
 473         assertEquals(226, v3.get());
 474         gci1.interpolate(TickCalculation.fromMillis(1000));
 475         assertEquals( 40, v1.get());
 476         assertEquals(140, v2.get());
 477         assertEquals(240, v3.get());
 478         gci1.interpolate(TickCalculation.fromMillis(1300));
 479         assertEquals( 46, v1.get());
 480         assertEquals(146, v2.get());
 481         assertEquals(246, v3.get());
 482         gci1.interpolate(TickCalculation.fromMillis(2000));
 483         assertEquals( 60, v1.get());
 484         assertEquals(160, v2.get());
 485         assertEquals(260, v3.get());
 486         
 487         // validate new key frames
 488         v1.set( 20);
 489         v2.set(120);
 490         v3.set(220);
 491         gci1.validate(true);
 492         gci1.interpolate(TickCalculation.fromMillis(0));
 493         assertEquals( 20, v1.get());
 494         assertEquals(120, v2.get());
 495         assertEquals(220, v3.get());
 496         gci1.interpolate(TickCalculation.fromMillis(600));
 497         assertEquals( 32, v1.get());
 498         assertEquals(132, v2.get());
 499         assertEquals(232, v3.get());
 500         gci1.interpolate(TickCalculation.fromMillis(1000));
 501         assertEquals( 40, v1.get());
 502         assertEquals(140, v2.get());
 503         assertEquals(240, v3.get());
 504         gci1.interpolate(TickCalculation.fromMillis(1300));
 505         assertEquals( 43, v1.get());
 506         assertEquals(143, v2.get());
 507         assertEquals(243, v3.get());
 508         gci1.interpolate(TickCalculation.fromMillis(4000));
 509         assertEquals( 70, v1.get());
 510         assertEquals(170, v2.get());
 511         assertEquals(270, v3.get());
 512     }
 513 
 514 
 515     @Test
 516     public void test_DuplicateKeyValue() {
 517         final IntegerProperty v1 = new SimpleIntegerProperty();
 518         final IntegerProperty v2 = new SimpleIntegerProperty();
 519         final KeyFrame start1 = new KeyFrame(Duration.ZERO, new KeyValue(v1, 30), new KeyValue(v2, 0));
 520         final KeyFrame start2 = new KeyFrame(Duration.ZERO, new KeyValue(v1, 30), new KeyValue(v1, -30), new KeyValue(v2, 0));
 521         final KeyFrame mid1 = new KeyFrame(Duration.millis(1000), new KeyValue(v1, 40), new KeyValue(v2, 100));
 522         final KeyFrame mid2 = new KeyFrame(Duration.millis(1000), new KeyValue(v1, 40), new KeyValue(v1, -40), new KeyValue(v2, 100));
 523         final KeyFrame end1 = new KeyFrame(Duration.millis(2000), new KeyValue(v1, 60), new KeyValue(v2, 0));
 524         final KeyFrame end2 = new KeyFrame(Duration.millis(2000), new KeyValue(v1, 60), new KeyValue(v1, -60), new KeyValue(v2, 0));
 525 
 526         // single value in start, single value in mid, duplicate value in end
 527         final GeneralClipInterpolatorShim gci1 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, mid1, end2}, new long[] {0, 6000, 12000});
 528         v1.set(0);
 529         v2.set(0);
 530         gci1.validate(true);
 531         gci1.interpolate(TickCalculation.fromMillis(0));
 532         assertEquals(30, v1.get());
 533         assertEquals(0, v2.get());
 534         gci1.interpolate(TickCalculation.fromMillis(300));
 535         assertEquals(33, v1.get());
 536         assertEquals(30, v2.get());
 537         gci1.interpolate(TickCalculation.fromMillis(1000));
 538         assertEquals(40, v1.get());
 539         assertEquals(100, v2.get());
 540         gci1.interpolate(TickCalculation.fromMillis(1600));
 541         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()));
 542         assertEquals(40, v2.get());
 543         gci1.interpolate(TickCalculation.fromMillis(2000));
 544         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 545         assertEquals(0, v2.get());
 546 
 547         // single value in start, duplicate value in mid, single value in end
 548         final GeneralClipInterpolatorShim gci2 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, mid2, end1}, new long[] {0, 6000, 12000});
 549         v1.set(0);
 550         v2.set(0);
 551         gci2.validate(true);
 552         gci2.interpolate(TickCalculation.fromMillis(0));
 553         assertEquals(30, v1.get());
 554         assertEquals(0, v2.get());
 555         gci2.interpolate(TickCalculation.fromMillis(300));
 556         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (9 == v1.get()));
 557         assertEquals(30, v2.get());
 558         gci2.interpolate(TickCalculation.fromMillis(1000));
 559         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 560         assertEquals(100, v2.get());
 561         gci2.interpolate(TickCalculation.fromMillis(1600));
 562         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (20 == v1.get()));
 563         assertEquals(40, v2.get());
 564         gci2.interpolate(TickCalculation.fromMillis(2000));
 565         assertEquals(60, v1.get());
 566         assertEquals(0, v2.get());
 567 
 568         // duplicate value in start, single value in mid, single value in end
 569         final GeneralClipInterpolatorShim gci3 = new GeneralClipInterpolatorShim (new KeyFrame[] {start2, mid1, end1}, new long[] {0, 6000, 12000});
 570         v1.set(0);
 571         v2.set(0);
 572         gci3.validate(true);
 573         gci3.interpolate(TickCalculation.fromMillis(0));
 574         assertTrue("v1.get(): " + v1.get(), (30 == v1.get()) || (-30 == v1.get()));
 575         assertEquals(0, v2.get());
 576         gci3.interpolate(TickCalculation.fromMillis(300));
 577         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (-9 == v1.get()));
 578         assertEquals(30, v2.get());
 579         gci3.interpolate(TickCalculation.fromMillis(1000));
 580         assertEquals(40, v1.get());
 581         assertEquals(100, v2.get());
 582         gci3.interpolate(TickCalculation.fromMillis(1600));
 583         assertEquals(52, v1.get());
 584         assertEquals(40, v2.get());
 585         gci3.interpolate(TickCalculation.fromMillis(2000));
 586         assertEquals(60, v1.get());
 587         assertEquals(0, v2.get());
 588 
 589         // duplicate value in start, duplicate value in mid, single value in end
 590         final GeneralClipInterpolatorShim gci4 = new GeneralClipInterpolatorShim (new KeyFrame[] {start2, mid2, end1}, new long[] {0, 6000, 12000});
 591         v1.set(0);
 592         v2.set(0);
 593         gci4.validate(true);
 594         gci4.interpolate(TickCalculation.fromMillis(0));
 595         assertTrue("v1.get(): " + v1.get(), (30 == v1.get()) || (-30 == v1.get()));
 596         assertEquals(0, v2.get());
 597         gci4.interpolate(TickCalculation.fromMillis(300));
 598         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (9 == v1.get()) || (-9 == v1.get()) || (-33 == v1.get()));
 599         assertEquals(30, v2.get());
 600         gci4.interpolate(TickCalculation.fromMillis(1000));
 601         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 602         assertEquals(100, v2.get());
 603         gci4.interpolate(TickCalculation.fromMillis(1600));
 604         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (20 == v1.get()));
 605         assertEquals(40, v2.get());
 606         gci4.interpolate(TickCalculation.fromMillis(2000));
 607         assertEquals(60, v1.get());
 608         assertEquals(0, v2.get());
 609 
 610         // duplicate value in start, single value in mid, duplicate value in end
 611         final GeneralClipInterpolatorShim gci5 = new GeneralClipInterpolatorShim (new KeyFrame[] {start2, mid1, end2}, new long[] {0, 6000, 12000});
 612         v1.set(0);
 613         v2.set(0);
 614         gci5.validate(true);
 615         gci5.interpolate(TickCalculation.fromMillis(0));
 616         assertTrue("v1.get(): " + v1.get(), (30 == v1.get()) || (-30 == v1.get()));
 617         assertEquals(0, v2.get());
 618         gci5.interpolate(TickCalculation.fromMillis(300));
 619         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (-9 == v1.get()));
 620         assertEquals(30, v2.get());
 621         gci5.interpolate(TickCalculation.fromMillis(1000));
 622         assertEquals(40, v1.get());
 623         assertEquals(100, v2.get());
 624         gci5.interpolate(TickCalculation.fromMillis(1600));
 625         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()));
 626         assertEquals(40, v2.get());
 627         gci5.interpolate(TickCalculation.fromMillis(2000));
 628         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 629         assertEquals(0, v2.get());
 630 
 631         // single value in start, duplicate value in mid, duplicate value in end
 632         final GeneralClipInterpolatorShim gci6 = new GeneralClipInterpolatorShim (new KeyFrame[] {start1, mid2, end2}, new long[] {0, 6000, 12000});
 633         v1.set(0);
 634         v2.set(0);
 635         gci6.validate(true);
 636         gci6.interpolate(TickCalculation.fromMillis(0));
 637         assertEquals(30, v1.get());
 638         assertEquals(0, v2.get());
 639         gci6.interpolate(TickCalculation.fromMillis(300));
 640         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (9 == v1.get()));
 641         assertEquals(30, v2.get());
 642         gci6.interpolate(TickCalculation.fromMillis(1000));
 643         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 644         assertEquals(100, v2.get());
 645         gci6.interpolate(TickCalculation.fromMillis(1600));
 646         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()) || (20 == v1.get()) || (-52 == v1.get()));
 647         assertEquals(40, v2.get());
 648         gci6.interpolate(TickCalculation.fromMillis(2000));
 649         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 650         assertEquals(0, v2.get());
 651 
 652         // duplicate value in start, duplicate value in mid, duplicate value in end
 653         final GeneralClipInterpolatorShim gci7 = new GeneralClipInterpolatorShim (new KeyFrame[] {start2, mid2, end2}, new long[] {0, 6000, 12000});
 654         v1.set(0);
 655         v2.set(0);
 656         gci7.validate(true);
 657         gci7.interpolate(TickCalculation.fromMillis(0));
 658         assertTrue("v1.get(): " + v1.get(), (30 == v1.get()) || (-30 == v1.get()));
 659         assertEquals(0, v2.get());
 660         gci7.interpolate(TickCalculation.fromMillis(300));
 661         assertTrue("v1.get(): " + v1.get(), (33 == v1.get()) || (9 == v1.get()) || (-9 == v1.get()) || (-33 == v1.get()));
 662         assertEquals(30, v2.get());
 663         gci7.interpolate(TickCalculation.fromMillis(1000));
 664         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 665         assertEquals(100, v2.get());
 666         gci7.interpolate(TickCalculation.fromMillis(1600));
 667         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()) || (20 == v1.get()) || (-52 == v1.get()));
 668         assertEquals(40, v2.get());
 669         gci7.interpolate(TickCalculation.fromMillis(2000));
 670         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 671         assertEquals(0, v2.get());
 672 
 673         // no value in start, single value in mid, duplicate value in end
 674         final GeneralClipInterpolatorShim gci8 = new GeneralClipInterpolatorShim (new KeyFrame[] {mid1, end2}, new long[] {6000, 12000});
 675         v1.set(0);
 676         v2.set(0);
 677         gci8.validate(true);
 678         gci8.interpolate(TickCalculation.fromMillis(0));
 679         assertEquals(0, v1.get());
 680         assertEquals(0, v2.get());
 681         gci8.interpolate(TickCalculation.fromMillis(400));
 682         assertEquals(16, v1.get());
 683         assertEquals(40, v2.get());
 684         gci8.interpolate(TickCalculation.fromMillis(1000));
 685         assertEquals(40, v1.get());
 686         assertEquals(100, v2.get());
 687         gci8.interpolate(TickCalculation.fromMillis(1600));
 688         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()));
 689         assertEquals(40, v2.get());
 690         gci8.interpolate(TickCalculation.fromMillis(2000));
 691         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 692         assertEquals(0, v2.get());
 693 
 694         // no value in start, duplicate value in mid, single value in end
 695         final GeneralClipInterpolatorShim gci9 = new GeneralClipInterpolatorShim (new KeyFrame[] {mid2, end1}, new long[] {6000, 12000});
 696         v1.set(0);
 697         v2.set(0);
 698         gci9.validate(true);
 699         gci9.interpolate(TickCalculation.fromMillis(0));
 700         assertEquals(0, v1.get());
 701         assertEquals(0, v2.get());
 702         gci9.interpolate(TickCalculation.fromMillis(400));
 703         assertTrue("v1.get(): " + v1.get(), (16 == v1.get()) || (-16 == v1.get()));
 704         assertEquals(40, v2.get());
 705         gci9.interpolate(TickCalculation.fromMillis(1000));
 706         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 707         assertEquals(100, v2.get());
 708         gci9.interpolate(TickCalculation.fromMillis(1600));
 709         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (20 == v1.get()));
 710         assertEquals(40, v2.get());
 711         gci9.interpolate(TickCalculation.fromMillis(2000));
 712         assertEquals(60, v1.get());
 713         assertEquals(0, v2.get());
 714 
 715         // no value in start, duplicate value in mid, duplicate value in end
 716         final GeneralClipInterpolatorShim gci10 = new GeneralClipInterpolatorShim (new KeyFrame[] {mid2, end2}, new long[] {6000, 12000});
 717         v1.set(0);
 718         v2.set(0);
 719         gci10.validate(true);
 720         gci10.interpolate(TickCalculation.fromMillis(0));
 721         assertEquals(0, v1.get());
 722         assertEquals(0, v2.get());
 723         gci10.interpolate(TickCalculation.fromMillis(400));
 724         assertTrue("v1.get(): " + v1.get(), (16 == v1.get()) || (-16 == v1.get()));
 725         assertEquals(40, v2.get());
 726         gci10.interpolate(TickCalculation.fromMillis(1000));
 727         assertTrue("v1.get(): " + v1.get(), (40 == v1.get()) || (-40 == v1.get()));
 728         assertEquals(100, v2.get());
 729         gci10.interpolate(TickCalculation.fromMillis(1600));
 730         assertTrue("v1.get(): " + v1.get(), (52 == v1.get()) || (-20 == v1.get()) || (20 == v1.get()) || (-52 == v1.get()));
 731         assertEquals(40, v2.get());
 732         gci10.interpolate(TickCalculation.fromMillis(2000));
 733         assertTrue("v1.get(): " + v1.get(), (60 == v1.get()) || (-60 == v1.get()));
 734         assertEquals(0, v2.get());
 735     }
 736 }