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.javafx.test;
  27 
  28 import javafx.beans.property.ReadOnlyProperty;
  29 import javafx.beans.InvalidationListener;
  30 import javafx.beans.Observable;
  31 import javafx.beans.value.ObservableValue;
  32 
  33 import org.junit.Assert;
  34 import org.junit.Test;
  35 
  36 public abstract class PropertiesTestBase {
  37 
  38     private final Configuration configuration;
  39 
  40     public PropertiesTestBase(final Configuration configuration) {
  41         this.configuration = configuration;
  42     }
  43 
  44     @Test
  45     public void testGetBean() {
  46         configuration.getBeanTest();
  47     }
  48 
  49     @Test
  50     public void testGetName() {
  51         configuration.getNameTest();
  52     }
  53 
  54     @Test
  55     public void testBasicAccess() {
  56         configuration.basicAccessTest();
  57     }
  58 
  59     @Test
  60     public void testBinding() {
  61         configuration.bindingTest();
  62     }
  63 
  64     /**
  65      * Single bean, single property configuration.
  66      */
  67     public static Object[] config(final Object bean,
  68                                   final String propertyName,
  69                                   final Object propertyValue1,
  70                                   final Object propertyValue2) {
  71         return config(new Configuration(bean,
  72                                         propertyName,
  73                                         propertyValue1,
  74                                         propertyValue2));
  75     }
  76 
  77     /**
  78      * Single bean, single property configuration with custom value comparator.
  79      */
  80     public static Object[] config(final Object bean,
  81                                   final String propertyName,
  82                                   final Object propertyValue1,
  83                                   final Object propertyValue2,
  84                                   final ValueComparator comparator) {
  85         return config(new Configuration(bean,
  86                                         propertyName,
  87                                         propertyValue1,
  88                                         propertyValue2,
  89                                         comparator));
  90     }
  91 
  92     /**
  93      * Single bean, propertyA (source) and propertyB (dependent) property
  94      * configuration.
  95      */
  96     public static Object[] config(final Object beanA,
  97                                   final String propertyAName,
  98                                   final Object propertyAValue1,
  99                                   final Object propertyAValue2,
 100                                   final String propertyBName,
 101                                   final Object propertyBValue1,
 102                                   final Object propertyBValue2) {
 103         return config(new Configuration(beanA,
 104                                         propertyAName,
 105                                         propertyAValue1,
 106                                         propertyAValue2,
 107                                         propertyBName,
 108                                         propertyBValue1,
 109                                         propertyBValue2));
 110     }
 111 
 112     /**
 113      * BeanA with propertyA (source) and BeanB with propertyB (dependent)
 114      * configuration.
 115      */
 116     public static Object[] config(final Object beanA,
 117                                   final String propertyAName,
 118                                   final Object propertyAValue1,
 119                                   final Object propertyAValue2,
 120                                   final Object beanB,
 121                                   final String propertyBName,
 122                                   final Object propertyBValue1,
 123                                   final Object propertyBValue2) {
 124         return config(new Configuration(beanA,
 125                                         propertyAName,
 126                                         propertyAValue1,
 127                                         propertyAValue2,
 128                                         beanB,
 129                                         propertyBName,
 130                                         propertyBValue1,
 131                                         propertyBValue2));
 132     }
 133 
 134     /**
 135      * BeanA with propertyA (source) and BeanB with propertyB (dependent)
 136      * with custom value comparator configuration.
 137      */
 138     public static Object[] config(final Object beanA,
 139                                   final String propertyAName,
 140                                   final Object propertyAValue1,
 141                                   final Object propertyAValue2,
 142                                   final Object beanB,
 143                                   final String propertyBName,
 144                                   final Object propertyBValue1,
 145                                   final Object propertyBValue2,
 146                                   final ValueComparator propertyBComparator) {
 147         return config(new Configuration(beanA,
 148                                         propertyAName,
 149                                         propertyAValue1,
 150                                         propertyAValue2,
 151                                         beanB,
 152                                         propertyBName,
 153                                         propertyBValue1,
 154                                         propertyBValue2,
 155                                         propertyBComparator));
 156     }
 157 
 158     public static Object[] config(final Configuration configuration) {
 159         return new Object[] { configuration };
 160     }
 161 
 162     public static class Configuration {
 163         private final Object beanA;
 164 
 165         private final PropertyReference propertyAReference;
 166 
 167         private final Object propertyAValue1;
 168 
 169         private final Object propertyAValue2;
 170 
 171         private final Object beanB;
 172 
 173         private final PropertyReference propertyBReference;
 174 
 175         private final Object propertyBValue1;
 176 
 177         private final Object propertyBValue2;
 178 
 179         private final ValueComparator propertyBComparator;
 180 
 181         private boolean allowMultipleNotifications;
 182 
 183         public Configuration(final Object bean,
 184                              final String propertyName,
 185                              final Object propertyValue1,
 186                              final Object propertyValue2) {
 187             this(bean, propertyName, propertyValue1, propertyValue2,
 188                  bean, propertyName, propertyValue1, propertyValue2,
 189                  ValueComparator.DEFAULT);
 190         }
 191 
 192         public Configuration(final Object bean,
 193                              final String propertyName,
 194                              final Object propertyValue1,
 195                              final Object propertyValue2,
 196                              final ValueComparator valueComparator) {
 197             this(bean, propertyName, propertyValue1, propertyValue2,
 198                  bean, propertyName, propertyValue1, propertyValue2,
 199                  valueComparator);
 200         }
 201 
 202         public Configuration(final Object bean,
 203                              final String propertyAName,
 204                              final Object propertyAValue1,
 205                              final Object propertyAValue2,
 206                              final String propertyBName,
 207                              final Object propertyBValue1,
 208                              final Object propertyBValue2) {
 209             this(bean, propertyAName, propertyAValue1, propertyAValue2,
 210                  bean, propertyBName, propertyBValue1, propertyBValue2,
 211                  ValueComparator.DEFAULT);
 212         }
 213 
 214         public Configuration(final Object beanA,
 215                              final String propertyAName,
 216                              final Object propertyAValue1,
 217                              final Object propertyAValue2,
 218                              final Object beanB,
 219                              final String propertyBName,
 220                              final Object propertyBValue1,
 221                              final Object propertyBValue2) {
 222             this(beanA, propertyAName, propertyAValue1, propertyAValue2,
 223                  beanB, propertyBName, propertyBValue1, propertyBValue2,
 224                  ValueComparator.DEFAULT);
 225         }
 226         
 227         public Configuration(final Object beanA,
 228                              final String propertyAName,
 229                              final Object propertyAValue1,
 230                              final Object propertyAValue2,
 231                              final Object beanB,
 232                              final String propertyBName,
 233                              final Object propertyBValue1,
 234                              final Object propertyBValue2,
 235                              final ValueComparator propertyBComparator) {
 236             this.beanA = beanA;
 237             this.propertyAReference = PropertyReference.createForBean(
 238                                               beanA.getClass(),
 239                                               propertyAName);
 240             this.propertyAValue1 = propertyAValue1;
 241             this.propertyAValue2 = propertyAValue2;
 242             this.beanB = beanB;
 243             this.propertyBReference = PropertyReference.createForBean(
 244                                               beanB.getClass(),
 245                                               propertyBName);
 246             this.propertyBValue1 = propertyBValue1;
 247             this.propertyBValue2 = propertyBValue2;
 248             this.propertyBComparator = propertyBComparator;
 249         }
 250 
 251         public void setAllowMultipleNotifications(
 252                 final boolean allowMultipleNotifications) {
 253             this.allowMultipleNotifications = allowMultipleNotifications;
 254         }
 255 
 256         public void getBeanTest() {
 257             final ReadOnlyProperty<?> propertyA =
 258                     (ReadOnlyProperty<?>) BindingHelper.getPropertyModel(
 259                                                   beanA, propertyAReference);
 260             final ReadOnlyProperty<?> propertyB =
 261                     (ReadOnlyProperty<?>) BindingHelper.getPropertyModel(
 262                                                   beanB, propertyBReference);
 263 
 264             Assert.assertSame(beanA, propertyA.getBean());
 265             Assert.assertSame(beanB, propertyB.getBean());
 266         }
 267         
 268         public void getNameTest() {
 269             final ReadOnlyProperty<?> propertyA =
 270                     (ReadOnlyProperty<?>) BindingHelper.getPropertyModel(
 271                                                   beanA, propertyAReference);
 272             final ReadOnlyProperty<?> propertyB =
 273                     (ReadOnlyProperty<?>) BindingHelper.getPropertyModel(
 274                                                   beanB, propertyBReference);
 275 
 276             Assert.assertEquals(propertyAReference.getPropertyName(),
 277                                 propertyA.getName());
 278             Assert.assertEquals(propertyBReference.getPropertyName(),
 279                                 propertyB.getName());
 280         }
 281 
 282         public void basicAccessTest() {
 283             // set to first value and verify dependet value
 284             propertyAReference.setValue(beanA, propertyAValue1);
 285             propertyBComparator.assertEquals(
 286                     propertyBValue1,
 287                     propertyBReference.getValue(beanB));
 288 
 289             final ValueInvalidationListener valueInvalidationListener =
 290                     new ValueInvalidationListener(allowMultipleNotifications);
 291             final ObservableValue observableValueB =
 292                     (ObservableValue) BindingHelper.getPropertyModel(
 293                                                   beanB, propertyBReference);
 294 
 295             // register listener
 296             observableValueB.addListener(valueInvalidationListener);
 297 
 298             // set to second value
 299             propertyAReference.setValue(beanA, propertyAValue2);
 300 
 301             // verify that the listener has been called
 302             valueInvalidationListener.assertCalled();
 303             valueInvalidationListener.reset();
 304 
 305             // test whether the second dependent value is set
 306             propertyBComparator.assertEquals(
 307                     propertyBValue2,
 308                     propertyBReference.getValue(beanB));
 309 
 310             // set to the second value again
 311             propertyAReference.setValue(beanA, propertyAValue2);
 312 
 313             // verify that the listener has not been called
 314             valueInvalidationListener.assertNotCalled();
 315 
 316             // unregister listener
 317             observableValueB.removeListener(valueInvalidationListener);
 318 
 319             // set to the first value again and test
 320             propertyAReference.setValue(beanA, propertyAValue1);
 321             propertyBComparator.assertEquals(
 322                     propertyBValue1,
 323                     propertyBReference.getValue(beanB));
 324 
 325             // verify that the listener has not been called
 326             valueInvalidationListener.assertNotCalled();
 327         }
 328 
 329         public void bindingTest() {
 330             // set to the first value
 331             propertyAReference.setValue(beanA, propertyAValue1);
 332 
 333             // bind to a variable set to second value
 334             final Object firstVariable =
 335                     BindingHelper.createVariable(propertyAValue2);
 336             BindingHelper.bind(beanA, propertyAReference, firstVariable);
 337 
 338             // test what we get
 339             propertyBComparator.assertEquals(
 340                     propertyBValue2,
 341                     propertyBReference.getValue(beanB));
 342 
 343             final ValueInvalidationListener valueInvalidationListener =
 344                     new ValueInvalidationListener(allowMultipleNotifications);
 345             final ObservableValue observableValue =
 346                     (ObservableValue) BindingHelper.getPropertyModel(
 347                                                   beanB, propertyBReference);
 348 
 349             // register listener
 350             observableValue.addListener(valueInvalidationListener);
 351 
 352             // change the value of the bound variable
 353             BindingHelper.setWritableValue(propertyAReference.getValueType(),
 354                                            firstVariable, propertyAValue1);
 355 
 356             // verify that the listener has been called
 357             valueInvalidationListener.assertCalled();
 358             valueInvalidationListener.reset();
 359 
 360             // check the value
 361             propertyBComparator.assertEquals(
 362                     propertyBValue1,
 363                     propertyBReference.getValue(beanB));
 364 
 365             // change binding
 366             final Object secondVariable =
 367                     BindingHelper.createVariable(propertyAValue2);
 368             BindingHelper.bind(beanA, propertyAReference, secondVariable);
 369 
 370             // verify that the listener has been called
 371             valueInvalidationListener.assertCalled();
 372             valueInvalidationListener.reset();
 373 
 374             // check the value
 375             propertyBComparator.assertEquals(
 376                     propertyBValue2,
 377                     propertyBReference.getValue(beanB));
 378 
 379             // unbind
 380             BindingHelper.unbind(beanA, propertyAReference);
 381 
 382             // verify that the listener has not been called
 383             valueInvalidationListener.assertNotCalled();
 384 
 385             // change the value of the last bound variable
 386             BindingHelper.setWritableValue(propertyAReference.getValueType(),
 387                                            secondVariable, propertyAValue1);
 388 
 389             // verify that the listener has not been called
 390             valueInvalidationListener.assertNotCalled();
 391 
 392             // check that the current property value equals to the last
 393             // value set by binding
 394             propertyBComparator.assertEquals(
 395                     propertyBValue2,
 396                     propertyBReference.getValue(beanB));
 397 
 398             // set to the first value again
 399             propertyAReference.setValue(beanA, propertyAValue1);
 400 
 401             // verify that the listener has been called
 402             valueInvalidationListener.assertCalled();
 403             valueInvalidationListener.reset();
 404 
 405             // check the value
 406             propertyBComparator.assertEquals(
 407                     propertyBValue1,
 408                     propertyBReference.getValue(beanB));
 409 
 410             // unregister listener
 411             observableValue.removeListener(valueInvalidationListener);
 412         }
 413     }
 414 
 415     private static final class ValueInvalidationListener
 416             implements InvalidationListener {
 417         private final boolean allowMultipleNotifications;
 418 
 419         private int counter;
 420 
 421         public ValueInvalidationListener(
 422                 final boolean allowMultipleNotifications) {
 423             this.allowMultipleNotifications = allowMultipleNotifications;
 424         }
 425 
 426         public void reset() {
 427             counter = 0;
 428         }
 429 
 430         public void assertCalled() {
 431             if (counter == 0) {
 432                 Assert.fail("Listener has not been called!");
 433                 return;
 434             }
 435 
 436             if (!allowMultipleNotifications && (counter > 1)) {
 437                 Assert.fail("Listener called multiple times!");
 438             }
 439         }
 440 
 441         public void assertNotCalled() {
 442             if (counter != 0) {
 443                 Assert.fail("Listener has been called!");
 444                 return;
 445             }
 446         }
 447 
 448         @Override
 449         public void invalidated(final Observable valueModel) {
 450             ++counter;
 451         }
 452     }
 453 }