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.javafx.beans.property;
  27 
  28 
  29 import javafx.beans.property.ObjectProperty;
  30 import javafx.beans.property.ReadOnlyObjectProperty;
  31 import javafx.beans.property.ReadOnlyObjectWrapper;
  32 import javafx.beans.property.SimpleObjectProperty;
  33 import static org.junit.Assert.assertEquals;
  34 import static org.junit.Assert.assertFalse;
  35 import static org.junit.Assert.assertTrue;
  36 
  37 import test.javafx.beans.InvalidationListenerMock;
  38 import test.javafx.beans.value.ChangeListenerMock;
  39 import javafx.beans.value.ObservableObjectValueStub;
  40 
  41 import org.junit.Before;
  42 import org.junit.Test;
  43 
  44 public class ReadOnlyObjectWrapperTest {
  45 
  46     private static final Object UNDEFINED = null;
  47     private static final Object DEFAULT = null;
  48     private static final Object VALUE_1 = new Object();
  49     private static final Object VALUE_2 = new Object();
  50     
  51     private ReadOnlyObjectWrapperMock property;
  52     private ReadOnlyObjectProperty<Object> readOnlyProperty;
  53     private InvalidationListenerMock internalInvalidationListener;
  54     private InvalidationListenerMock publicInvalidationListener;
  55     private ChangeListenerMock<Object> internalChangeListener;
  56     private ChangeListenerMock<Object> publicChangeListener;
  57     
  58     @Before
  59     public void setUp() throws Exception {
  60         property = new ReadOnlyObjectWrapperMock();
  61         readOnlyProperty = property.getReadOnlyProperty();
  62         internalInvalidationListener = new InvalidationListenerMock();
  63         publicInvalidationListener = new InvalidationListenerMock();
  64         internalChangeListener = new ChangeListenerMock<Object>(UNDEFINED);
  65         publicChangeListener = new ChangeListenerMock<Object>(UNDEFINED);
  66     }
  67     
  68     private void attachInvalidationListeners() {
  69         property.addListener(internalInvalidationListener);
  70         readOnlyProperty.addListener(publicInvalidationListener);
  71         property.get();
  72         readOnlyProperty.get();
  73         internalInvalidationListener.reset();
  74         publicInvalidationListener.reset();
  75     }
  76 
  77     private void attachInternalChangeListener() {
  78         property.addListener(internalChangeListener);
  79         property.get();
  80         internalChangeListener.reset();
  81     }
  82 
  83     private void attachPublicChangeListener() {
  84         readOnlyProperty.addListener(publicChangeListener);
  85         readOnlyProperty.get();
  86         publicChangeListener.reset();
  87     }
  88 
  89     @Test
  90     public void testConstructor_NoArguments() {
  91         final ReadOnlyObjectWrapper<Object> p1 = new ReadOnlyObjectWrapper<Object>();
  92         assertEquals(DEFAULT, p1.get());
  93         assertEquals((Object)DEFAULT, p1.getValue());
  94         assertFalse(property.isBound());
  95         assertEquals(null, p1.getBean());
  96         assertEquals("", p1.getName());
  97         final ReadOnlyObjectProperty<Object> r1 = p1.getReadOnlyProperty();
  98         assertEquals(DEFAULT, r1.get());
  99         assertEquals((Object)DEFAULT, r1.getValue());
 100         assertEquals(null, r1.getBean());
 101         assertEquals("", r1.getName());
 102     }
 103     
 104     @Test
 105     public void testConstructor_InitialValue() {
 106         final ReadOnlyObjectWrapper<Object> p1 = new ReadOnlyObjectWrapper<Object>(VALUE_1);
 107         assertEquals(VALUE_1, p1.get());
 108         assertEquals((Object)VALUE_1, p1.getValue());
 109         assertFalse(property.isBound());
 110         assertEquals(null, p1.getBean());
 111         assertEquals("", p1.getName());
 112         final ReadOnlyObjectProperty<Object> r1 = p1.getReadOnlyProperty();
 113         assertEquals(VALUE_1, r1.get());
 114         assertEquals((Object)VALUE_1, r1.getValue());
 115         assertEquals(null, r1.getBean());
 116         assertEquals("", r1.getName());
 117     }
 118     
 119     @Test
 120     public void testConstructor_Bean_Name() {
 121         final Object bean = new Object();
 122         final String name = "My name";
 123         final ReadOnlyObjectWrapper<Object> p1 = new ReadOnlyObjectWrapper<Object>(bean, name);
 124         assertEquals(DEFAULT, p1.get());
 125         assertEquals((Object)DEFAULT, p1.getValue());
 126         assertFalse(property.isBound());
 127         assertEquals(bean, p1.getBean());
 128         assertEquals(name, p1.getName());
 129         final ReadOnlyObjectProperty<Object> r1 = p1.getReadOnlyProperty();
 130         assertEquals(DEFAULT, r1.get());
 131         assertEquals((Object)DEFAULT, r1.getValue());
 132         assertEquals(bean, r1.getBean());
 133         assertEquals(name, r1.getName());
 134     }
 135     
 136     @Test
 137     public void testConstructor_Bean_Name_InitialValue() {
 138         final Object bean = new Object();
 139         final String name = "My name";
 140         final ReadOnlyObjectWrapper<Object> p1 = new ReadOnlyObjectWrapper<Object>(bean, name, VALUE_1);
 141         assertEquals(VALUE_1, p1.get());
 142         assertEquals((Object)VALUE_1, p1.getValue());
 143         assertFalse(property.isBound());
 144         assertEquals(bean, p1.getBean());
 145         assertEquals(name, p1.getName());
 146         final ReadOnlyObjectProperty<Object> r1 = p1.getReadOnlyProperty();
 147         assertEquals(VALUE_1, r1.get());
 148         assertEquals((Object)VALUE_1, r1.getValue());
 149         assertEquals(bean, r1.getBean());
 150         assertEquals(name, r1.getName());
 151     }
 152 
 153     @Test
 154     public void testLazySet() {
 155         attachInvalidationListeners();
 156         
 157         // set value once
 158         property.set(VALUE_1);
 159         assertEquals(VALUE_1, property.get());
 160         property.check(1);
 161         internalInvalidationListener.check(property, 1);
 162         assertEquals(VALUE_1, readOnlyProperty.get());
 163         publicInvalidationListener.check(readOnlyProperty, 1);
 164         
 165         // set same value again
 166         property.set(VALUE_1);
 167         assertEquals(VALUE_1, property.get());
 168         property.check(0);
 169         internalInvalidationListener.check(null, 0);
 170         assertEquals(VALUE_1, readOnlyProperty.get());
 171         publicInvalidationListener.check(null, 0);
 172         
 173         // set value twice without reading
 174         property.set(VALUE_2);
 175         property.set(VALUE_1);
 176         assertEquals(VALUE_1, property.get());
 177         property.check(1);
 178         internalInvalidationListener.check(property, 1);
 179         assertEquals(VALUE_1, readOnlyProperty.get());
 180         publicInvalidationListener.check(readOnlyProperty, 1);
 181     }
 182     
 183     @Test
 184     public void testInternalEagerSet() {
 185         attachInternalChangeListener();
 186         
 187         // set value once
 188         property.set(VALUE_1);
 189         assertEquals(VALUE_1, property.get());
 190         property.check(1);
 191         internalChangeListener.check(property, DEFAULT, VALUE_1, 1);
 192         assertEquals(VALUE_1, readOnlyProperty.get());
 193         
 194         // set same value again
 195         property.set(VALUE_1);
 196         assertEquals(VALUE_1, property.get());
 197         property.check(0);
 198         internalChangeListener.check(null, UNDEFINED, UNDEFINED, 0);
 199         assertEquals(VALUE_1, readOnlyProperty.get());
 200         
 201         // set value twice without reading
 202         property.set(VALUE_2);
 203         property.set(VALUE_1);
 204         assertEquals(VALUE_1, property.get());
 205         property.check(2);
 206         internalChangeListener.check(property, VALUE_2, VALUE_1, 2);
 207         assertEquals(VALUE_1, readOnlyProperty.get());
 208     }
 209     
 210     @Test
 211     public void testPublicEagerSet() {
 212         attachPublicChangeListener();
 213         
 214         // set value once
 215         property.set(VALUE_1);
 216         assertEquals(VALUE_1, property.get());
 217         property.check(1);
 218         assertEquals(VALUE_1, readOnlyProperty.get());
 219         publicChangeListener.check(readOnlyProperty, DEFAULT, VALUE_1, 1);
 220         
 221         // set same value again
 222         property.set(VALUE_1);
 223         assertEquals(VALUE_1, property.get());
 224         property.check(0);
 225         assertEquals(VALUE_1, readOnlyProperty.get());
 226         publicChangeListener.check(null, UNDEFINED, UNDEFINED, 0);
 227         
 228         // set value twice without reading
 229         property.set(VALUE_2);
 230         property.set(VALUE_1);
 231         assertEquals(VALUE_1, property.get());
 232         property.check(2);
 233         assertEquals(VALUE_1, readOnlyProperty.get());
 234         publicChangeListener.check(readOnlyProperty, VALUE_2, VALUE_1, 2);
 235     }
 236 
 237     @Test
 238     public void testLazySetValue() {
 239         attachInvalidationListeners();
 240         
 241         // set value once
 242         property.setValue(VALUE_1);
 243         assertEquals(VALUE_1, property.get());
 244         property.check(1);
 245         internalInvalidationListener.check(property, 1);
 246         assertEquals(VALUE_1, readOnlyProperty.get());
 247         publicInvalidationListener.check(readOnlyProperty, 1);
 248         
 249         // set same value again
 250         property.setValue(VALUE_1);
 251         assertEquals(VALUE_1, property.get());
 252         property.check(0);
 253         internalInvalidationListener.check(null, 0);
 254         assertEquals(VALUE_1, readOnlyProperty.get());
 255         publicInvalidationListener.check(null, 0);
 256         
 257         // set value twice without reading
 258         property.setValue(VALUE_2);
 259         property.setValue(VALUE_1);
 260         assertEquals(VALUE_1, property.get());
 261         property.check(1);
 262         internalInvalidationListener.check(property, 1);
 263         assertEquals(VALUE_1, readOnlyProperty.get());
 264         publicInvalidationListener.check(readOnlyProperty, 1);
 265     }
 266     
 267     @Test
 268     public void testInternalEagerSetValue() {
 269         attachInternalChangeListener();
 270         
 271         // set value once
 272         property.setValue(VALUE_1);
 273         assertEquals(VALUE_1, property.get());
 274         property.check(1);
 275         internalChangeListener.check(property, DEFAULT, VALUE_1, 1);
 276         assertEquals(VALUE_1, readOnlyProperty.get());
 277         
 278         // set same value again
 279         property.setValue(VALUE_1);
 280         assertEquals(VALUE_1, property.get());
 281         property.check(0);
 282         internalChangeListener.check(null, UNDEFINED, UNDEFINED, 0);
 283         assertEquals(VALUE_1, readOnlyProperty.get());
 284         
 285         // set value twice without reading
 286         property.setValue(VALUE_2);
 287         property.setValue(VALUE_1);
 288         assertEquals(VALUE_1, property.get());
 289         property.check(2);
 290         internalChangeListener.check(property, VALUE_2, VALUE_1, 2);
 291         assertEquals(VALUE_1, readOnlyProperty.get());
 292     }
 293     
 294     @Test
 295     public void testPublicEagerSetValue() {
 296         attachPublicChangeListener();
 297         
 298         // set value once
 299         property.setValue(VALUE_1);
 300         assertEquals(VALUE_1, property.get());
 301         property.check(1);
 302         assertEquals(VALUE_1, readOnlyProperty.get());
 303         publicChangeListener.check(readOnlyProperty, DEFAULT, VALUE_1, 1);
 304         
 305         // set same value again
 306         property.setValue(VALUE_1);
 307         assertEquals(VALUE_1, property.get());
 308         property.check(0);
 309         assertEquals(VALUE_1, readOnlyProperty.get());
 310         publicChangeListener.check(null, UNDEFINED, UNDEFINED, 0);
 311         
 312         // set value twice without reading
 313         property.setValue(VALUE_2);
 314         property.setValue(VALUE_1);
 315         assertEquals(VALUE_1, property.get());
 316         property.check(2);
 317         assertEquals(VALUE_1, readOnlyProperty.get());
 318         publicChangeListener.check(readOnlyProperty, VALUE_2, VALUE_1, 2);
 319     }
 320     
 321     @Test(expected=RuntimeException.class)
 322     public void testSetBoundValue() {
 323         final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1);
 324         property.bind(v);
 325         property.set(VALUE_1);
 326     }
 327 
 328     @Test
 329     public void testLazyBind_primitive() {
 330         attachInvalidationListeners();
 331         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 332 
 333         property.bind(v);
 334         assertEquals(VALUE_1, property.get());
 335         assertTrue(property.isBound());
 336         property.check(1);
 337         internalInvalidationListener.check(property, 1);
 338         assertEquals(VALUE_1, readOnlyProperty.get());
 339         publicInvalidationListener.check(readOnlyProperty, 1);
 340 
 341         // change binding once
 342         v.set(VALUE_2);
 343         assertEquals(VALUE_2, property.get());
 344         property.check(1);
 345         internalInvalidationListener.check(property, 1);
 346         assertEquals(VALUE_2, readOnlyProperty.get());
 347         publicInvalidationListener.check(readOnlyProperty, 1);
 348 
 349         // change binding twice without reading
 350         v.set(VALUE_1);
 351         v.set(VALUE_2);
 352         assertEquals(VALUE_2, property.get());
 353         property.check(1);
 354         internalInvalidationListener.check(property, 1);
 355         assertEquals(VALUE_2, readOnlyProperty.get());
 356         publicInvalidationListener.check(readOnlyProperty, 1);
 357 
 358         // change binding twice to same value
 359         v.set(VALUE_1);
 360         v.set(VALUE_1);
 361         assertEquals(VALUE_1, property.get());
 362         property.check(1);
 363         internalInvalidationListener.check(property, 1);
 364         assertEquals(VALUE_1, readOnlyProperty.get());
 365         publicInvalidationListener.check(readOnlyProperty, 1);
 366     }
 367 
 368     @Test
 369     public void testInternalEagerBind_primitive() {
 370         attachInternalChangeListener();
 371         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 372 
 373         property.bind(v);
 374         assertEquals(VALUE_1, property.get());
 375         assertTrue(property.isBound());
 376         property.check(1);
 377         internalChangeListener.check(property, DEFAULT, VALUE_1, 1);
 378         assertEquals(VALUE_1, readOnlyProperty.get());
 379 
 380         // change binding once
 381         v.set(VALUE_2);
 382         assertEquals(VALUE_2, property.get());
 383         property.check(1);
 384         internalChangeListener.check(property, VALUE_1, VALUE_2, 1);
 385         assertEquals(VALUE_2, readOnlyProperty.get());
 386 
 387         // change binding twice without reading
 388         v.set(VALUE_1);
 389         v.set(VALUE_2);
 390         assertEquals(VALUE_2, property.get());
 391         property.check(2);
 392         internalChangeListener.check(property, VALUE_1, VALUE_2, 2);
 393         assertEquals(VALUE_2, readOnlyProperty.get());
 394 
 395         // change binding twice to same value
 396         v.set(VALUE_1);
 397         v.set(VALUE_1);
 398         assertEquals(VALUE_1, property.get());
 399         property.check(2);
 400         internalChangeListener.check(property, VALUE_2, VALUE_1, 1);
 401         assertEquals(VALUE_1, readOnlyProperty.get());
 402     }
 403     
 404     @Test
 405     public void testPublicEagerBind_primitive() {
 406         attachPublicChangeListener();
 407         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 408 
 409         property.bind(v);
 410         assertEquals(VALUE_1, property.get());
 411         assertTrue(property.isBound());
 412         property.check(1);
 413         assertEquals(VALUE_1, readOnlyProperty.get());
 414         publicChangeListener.check(readOnlyProperty, DEFAULT, VALUE_1, 1);
 415 
 416         // change binding once
 417         v.set(VALUE_2);
 418         assertEquals(VALUE_2, property.get());
 419         property.check(1);
 420         assertEquals(VALUE_2, readOnlyProperty.get());
 421         publicChangeListener.check(readOnlyProperty, VALUE_1, VALUE_2, 1);
 422 
 423         // change binding twice without reading
 424         v.set(VALUE_1);
 425         v.set(VALUE_2);
 426         assertEquals(VALUE_2, property.get());
 427         property.check(2);
 428         assertEquals(VALUE_2, readOnlyProperty.get());
 429         publicChangeListener.check(readOnlyProperty, VALUE_1, VALUE_2, 2);
 430 
 431         // change binding twice to same value
 432         v.set(VALUE_1);
 433         v.set(VALUE_1);
 434         assertEquals(VALUE_1, property.get());
 435         property.check(2);
 436         assertEquals(VALUE_1, readOnlyProperty.get());
 437         publicChangeListener.check(readOnlyProperty, VALUE_2, VALUE_1, 1);
 438     }
 439     
 440     @Test
 441     public void testLazyBind_generic() {
 442         attachInvalidationListeners();
 443         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 444 
 445         property.bind(v);
 446         assertEquals(VALUE_1, property.get());
 447         assertTrue(property.isBound());
 448         property.check(1);
 449         internalInvalidationListener.check(property, 1);
 450         assertEquals(VALUE_1, readOnlyProperty.get());
 451         publicInvalidationListener.check(readOnlyProperty, 1);
 452 
 453         // change binding once
 454         v.set(VALUE_2);
 455         assertEquals(VALUE_2, property.get());
 456         property.check(1);
 457         internalInvalidationListener.check(property, 1);
 458         assertEquals(VALUE_2, readOnlyProperty.get());
 459         publicInvalidationListener.check(readOnlyProperty, 1);
 460 
 461         // change binding twice without reading
 462         v.set(VALUE_1);
 463         v.set(VALUE_2);
 464         assertEquals(VALUE_2, property.get());
 465         property.check(1);
 466         internalInvalidationListener.check(property, 1);
 467         assertEquals(VALUE_2, readOnlyProperty.get());
 468         publicInvalidationListener.check(readOnlyProperty, 1);
 469 
 470         // change binding twice to same value
 471         v.set(VALUE_1);
 472         v.set(VALUE_1);
 473         assertEquals(VALUE_1, property.get());
 474         property.check(1);
 475         internalInvalidationListener.check(property, 1);
 476         assertEquals(VALUE_1, readOnlyProperty.get());
 477         publicInvalidationListener.check(readOnlyProperty, 1);
 478     }
 479 
 480     @Test
 481     public void testInternalEagerBind_generic() {
 482         attachInternalChangeListener();
 483         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 484 
 485         property.bind(v);
 486         assertEquals(VALUE_1, property.get());
 487         assertTrue(property.isBound());
 488         property.check(1);
 489         internalChangeListener.check(property, DEFAULT, VALUE_1, 1);
 490         assertEquals(VALUE_1, readOnlyProperty.get());
 491 
 492         // change binding once
 493         v.set(VALUE_2);
 494         assertEquals(VALUE_2, property.get());
 495         property.check(1);
 496         internalChangeListener.check(property, VALUE_1, VALUE_2, 1);
 497         assertEquals(VALUE_2, readOnlyProperty.get());
 498 
 499         // change binding twice without reading
 500         v.set(VALUE_1);
 501         v.set(VALUE_2);
 502         assertEquals(VALUE_2, property.get());
 503         property.check(2);
 504         internalChangeListener.check(property, VALUE_1, VALUE_2, 2);
 505         assertEquals(VALUE_2, readOnlyProperty.get());
 506 
 507         // change binding twice to same value
 508         v.set(VALUE_1);
 509         v.set(VALUE_1);
 510         assertEquals(VALUE_1, property.get());
 511         property.check(2);
 512         internalChangeListener.check(property, VALUE_2, VALUE_1, 1);
 513         assertEquals(VALUE_1, readOnlyProperty.get());
 514     }
 515 
 516     @Test
 517     public void testPublicEagerBind_generic() {
 518         attachPublicChangeListener();
 519         final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1);
 520 
 521         property.bind(v);
 522         assertEquals(VALUE_1, property.get());
 523         assertTrue(property.isBound());
 524         property.check(1);
 525         assertEquals(VALUE_1, readOnlyProperty.get());
 526         publicChangeListener.check(readOnlyProperty, DEFAULT, VALUE_1, 1);
 527 
 528         // change binding once
 529         v.set(VALUE_2);
 530         assertEquals(VALUE_2, property.get());
 531         property.check(1);
 532         assertEquals(VALUE_2, readOnlyProperty.get());
 533         publicChangeListener.check(readOnlyProperty, VALUE_1, VALUE_2, 1);
 534 
 535         // change binding twice without reading
 536         v.set(VALUE_1);
 537         v.set(VALUE_2);
 538         assertEquals(VALUE_2, property.get());
 539         property.check(2);
 540         assertEquals(VALUE_2, readOnlyProperty.get());
 541         publicChangeListener.check(readOnlyProperty, VALUE_1, VALUE_2, 2);
 542 
 543         // change binding twice to same value
 544         v.set(VALUE_1);
 545         v.set(VALUE_1);
 546         assertEquals(VALUE_1, property.get());
 547         property.check(2);
 548         assertEquals(VALUE_1, readOnlyProperty.get());
 549         publicChangeListener.check(readOnlyProperty, VALUE_2, VALUE_1, 1);
 550     }
 551     
 552     @Test(expected=NullPointerException.class)
 553     public void testBindToNull() {
 554         property.bind(null);
 555     }
 556 
 557     @Test
 558     public void testRebind() {
 559         attachInvalidationListeners();
 560         final ObjectProperty<Object> v1 = new SimpleObjectProperty<Object>(VALUE_1);
 561         final ObjectProperty<Object> v2 = new SimpleObjectProperty<Object>(VALUE_2);
 562         property.bind(v1);
 563         property.get();
 564         readOnlyProperty.get();
 565         property.reset();
 566         internalInvalidationListener.reset();
 567         publicInvalidationListener.reset();
 568         
 569         // rebind causes invalidation event
 570         property.bind(v2);
 571         assertEquals(VALUE_2, property.get());
 572         assertTrue(property.isBound());
 573         property.check(1);
 574         internalInvalidationListener.check(property, 1);
 575         assertEquals(VALUE_2, readOnlyProperty.get());
 576         publicInvalidationListener.check(readOnlyProperty, 1);
 577         
 578         // change new binding
 579         v2.set(VALUE_1);
 580         assertEquals(VALUE_1, property.get());
 581         property.check(1);
 582         internalInvalidationListener.check(property, 1);
 583         assertEquals(VALUE_1, readOnlyProperty.get());
 584         publicInvalidationListener.check(readOnlyProperty, 1);
 585         
 586         // change old binding
 587         v1.set(VALUE_2);
 588         assertEquals(VALUE_1, property.get());
 589         property.check(0);
 590         internalInvalidationListener.check(null, 0);
 591         assertEquals(VALUE_1, readOnlyProperty.get());
 592         publicInvalidationListener.check(null, 0);
 593         
 594         // rebind to same observable should have no effect
 595         property.bind(v2);
 596         assertEquals(VALUE_1, property.get());
 597         assertTrue(property.isBound());
 598         property.check(0);
 599         internalInvalidationListener.check(null, 0);
 600         assertEquals(VALUE_1, readOnlyProperty.get());
 601         publicInvalidationListener.check(null, 0);
 602     }
 603 
 604     @Test
 605     public void testUnbind() {
 606         attachInvalidationListeners();
 607         final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1);
 608         property.bind(v);
 609         property.unbind();
 610         assertEquals(VALUE_1, property.get());
 611         assertFalse(property.isBound());
 612         assertEquals(VALUE_1, readOnlyProperty.get());
 613         property.reset();
 614         internalInvalidationListener.reset();
 615         publicInvalidationListener.reset();
 616         
 617         // change binding
 618         v.set(VALUE_2);
 619         assertEquals(VALUE_1, property.get());
 620         property.check(0);
 621         internalInvalidationListener.check(null, 0);
 622         assertEquals(VALUE_1, readOnlyProperty.get());
 623         publicInvalidationListener.check(null, 0);
 624         
 625         // set value
 626         property.set(VALUE_2);
 627         assertEquals(VALUE_2, property.get());
 628         property.check(1);
 629         internalInvalidationListener.check(property, 1);
 630         assertEquals(VALUE_2, readOnlyProperty.get());
 631         publicInvalidationListener.check(readOnlyProperty, 1);
 632     }
 633     
 634     @Test
 635     public void testAddingListenerWillAlwaysReceiveInvalidationEvent() {
 636         final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1);
 637         final InvalidationListenerMock internalListener2 = new InvalidationListenerMock();
 638         final InvalidationListenerMock internalListener3 = new InvalidationListenerMock();
 639         final InvalidationListenerMock publicListener2 = new InvalidationListenerMock();
 640         final InvalidationListenerMock publicListener3 = new InvalidationListenerMock();
 641 
 642         // setting the property,checking internal
 643         property.set(VALUE_1);
 644         property.addListener(internalListener2);
 645         internalListener2.reset();
 646         property.set(VALUE_2);
 647         internalListener2.check(property, 1);
 648         
 649         // setting the property, checking public
 650         property.set(VALUE_1);
 651         readOnlyProperty.addListener(publicListener2);
 652         publicListener2.reset();
 653         property.set(VALUE_2);
 654         publicListener2.check(readOnlyProperty, 1);
 655         
 656         // binding the property, checking internal
 657         property.bind(v);
 658         v.set(VALUE_2);
 659         property.addListener(internalListener3);
 660         v.get();
 661         internalListener3.reset();
 662         v.set(VALUE_1);
 663         internalListener3.check(property, 1);
 664         
 665         // binding the property, checking public
 666         property.bind(v);
 667         v.set(VALUE_2);
 668         readOnlyProperty.addListener(publicListener3);
 669         v.get();
 670         publicListener3.reset();
 671         v.set(VALUE_1);
 672         publicListener3.check(readOnlyProperty, 1);
 673     }
 674     
 675     @Test
 676     public void testRemoveListeners() {
 677         attachInvalidationListeners();
 678         attachInternalChangeListener();
 679         property.removeListener(internalInvalidationListener);
 680         property.removeListener(internalChangeListener);
 681         property.get();
 682         internalInvalidationListener.reset();
 683         internalChangeListener.reset();
 684         
 685         property.set(VALUE_1);
 686         internalInvalidationListener.check(null, 0);
 687         internalChangeListener.check(null, UNDEFINED, UNDEFINED, 0);
 688         
 689         // no read only property created => no-op
 690         final ReadOnlyObjectWrapper<Object> v1 = new ReadOnlyObjectWrapper<Object>();
 691         v1.removeListener(internalInvalidationListener);
 692         v1.removeListener(internalChangeListener);
 693     }
 694     
 695     @Test
 696     public void testNoReadOnlyPropertyCreated() {
 697         final ObjectProperty<Object> v1 = new SimpleObjectProperty<Object>(VALUE_1);
 698         final ReadOnlyObjectWrapper<Object> p1 = new ReadOnlyObjectWrapper<Object>();
 699         
 700         p1.set(VALUE_1);
 701         p1.bind(v1);
 702         assertEquals(VALUE_1, p1.get());
 703         v1.set(VALUE_2);
 704         assertEquals(VALUE_2, p1.get());
 705     }
 706     
 707     @Test
 708     public void testToString() {
 709         final ObjectProperty<Object> v1 = new SimpleObjectProperty<Object>(VALUE_1);
 710         
 711         property.set(VALUE_1);
 712         assertEquals("ObjectProperty [value: " + VALUE_1 + "]", property.toString());
 713         assertEquals("ReadOnlyObjectProperty [value: " + VALUE_1 + "]", readOnlyProperty.toString());
 714         
 715         property.bind(v1);
 716         assertEquals("ObjectProperty [bound, invalid]", property.toString());
 717         assertEquals("ReadOnlyObjectProperty [value: " + VALUE_1 + "]", readOnlyProperty.toString());
 718         property.get();
 719         assertEquals("ObjectProperty [bound, value: " + VALUE_1 + "]", property.toString());
 720         assertEquals("ReadOnlyObjectProperty [value: " + VALUE_1 + "]", readOnlyProperty.toString());
 721         v1.set(VALUE_2);
 722         assertEquals("ObjectProperty [bound, invalid]", property.toString());
 723         assertEquals("ReadOnlyObjectProperty [value: " + VALUE_2 + "]", readOnlyProperty.toString());
 724         property.get();
 725         assertEquals("ObjectProperty [bound, value: " + VALUE_2 + "]", property.toString());
 726         assertEquals("ReadOnlyObjectProperty [value: " + VALUE_2 + "]", readOnlyProperty.toString());
 727         
 728         final Object bean = new Object();
 729         final String name = "My name";
 730         final ReadOnlyObjectWrapper<Object> v2 = new ReadOnlyObjectWrapper<Object>(bean, name);
 731         assertEquals("ObjectProperty [bean: " + bean.toString() + ", name: My name, value: " + DEFAULT + "]", v2.toString());
 732         assertEquals("ReadOnlyObjectProperty [bean: " + bean.toString() + ", name: My name, value: " + DEFAULT + "]", v2.getReadOnlyProperty().toString());
 733         
 734         final ReadOnlyObjectWrapper<Object> v3 = new ReadOnlyObjectWrapper<Object>(bean, "");
 735         assertEquals("ObjectProperty [bean: " + bean.toString() + ", value: " + DEFAULT + "]", v3.toString());
 736         assertEquals("ReadOnlyObjectProperty [bean: " + bean.toString() + ", value: " + DEFAULT + "]", v3.getReadOnlyProperty().toString());
 737 
 738         final ReadOnlyObjectWrapper<Object> v4 = new ReadOnlyObjectWrapper<Object>(null, name);
 739         assertEquals("ObjectProperty [name: My name, value: " + DEFAULT + "]", v4.toString());
 740         assertEquals("ReadOnlyObjectProperty [name: My name, value: " + DEFAULT + "]", v4.getReadOnlyProperty().toString());
 741     }
 742     
 743     private static class ReadOnlyObjectWrapperMock extends ReadOnlyObjectWrapper<Object> {
 744         
 745         private int counter;
 746         
 747         @Override
 748         protected void invalidated() {
 749             counter++;
 750         }
 751         
 752         private void check(int expected) {
 753             assertEquals(expected, counter);
 754             reset();
 755         }
 756         
 757         private void reset() {
 758             counter = 0;
 759         }
 760     }
 761 }