1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javafx.beans.property;
  27 
  28 import javafx.beans.InvalidationListenerMock;
  29 import javafx.beans.value.ChangeListenerMock;
  30 import javafx.beans.value.ObservableObjectValueStub;
  31 import javafx.collections.FXCollections;
  32 import javafx.collections.MockMapObserver;
  33 import javafx.collections.ObservableMap;
  34 import org.junit.Before;
  35 import org.junit.Test;
  36 
  37 import java.util.Collections;
  38 import java.util.HashMap;
  39 
  40 import static javafx.collections.MockMapObserver.Call;
  41 import static org.junit.Assert.*;
  42 
  43 public class MapPropertyBaseTest {
  44 
  45     private static final Object NO_BEAN = null;
  46     private static final String NO_NAME_1 = null;
  47     private static final String NO_NAME_2 = "";
  48     private static final Object KEY_1b = new Object();
  49     private static final Object DATA_1b = new Object();
  50     private static final Object KEY_2a_0 = new Object();
  51     private static final Object DATA_2a_0 = new Object();
  52     private static final Object KEY_2a_1 = new Object();
  53     private static final Object DATA_2a_1 = new Object();
  54     private static final Object KEY_2b_0 = new Object();
  55     private static final Object DATA_2b_0 = new Object();
  56     private static final Object KEY_2b_1 = new Object();
  57     private static final Object DATA_2b_1 = new Object();
  58     private static final Object KEY_2b_2 = new Object();
  59     private static final Object DATA_2b_2 = new Object();
  60     private static final ObservableMap<Object, Object> UNDEFINED = FXCollections.observableMap(Collections.emptyMap());
  61     private static final ObservableMap<Object, Object> VALUE_1a = FXCollections.observableMap(Collections.emptyMap());
  62     private static final ObservableMap<Object, Object> VALUE_1b = FXCollections.observableMap(Collections.singletonMap(KEY_1b, DATA_1b));
  63     private static final ObservableMap<Object, Object> VALUE_2a = FXCollections.observableMap(new HashMap<Object, Object>());
  64 
  65     static {
  66         VALUE_2a.put(KEY_2a_0, DATA_2a_0);
  67         VALUE_2a.put(KEY_2a_1, DATA_2a_1);
  68     }
  69     private static final ObservableMap<Object, Object> VALUE_2b = FXCollections.observableMap(new HashMap<Object, Object>());
  70 
  71     static {
  72         VALUE_2b.put(KEY_2b_0, DATA_2b_0);
  73         VALUE_2b.put(KEY_2b_1, DATA_2b_1);
  74         VALUE_2b.put(KEY_2b_2, DATA_2b_2);
  75     }
  76     private MapPropertyMock property;
  77     private InvalidationListenerMock invalidationListener;
  78     private ChangeListenerMock<ObservableMap<Object, Object>> changeListener;
  79     private MockMapObserver<Object, Object> mapChangeListener;
  80 
  81     @Before
  82     public void setUp() throws Exception {
  83         property = new MapPropertyMock();
  84         invalidationListener = new InvalidationListenerMock();
  85         changeListener = new ChangeListenerMock<ObservableMap<Object, Object>>(UNDEFINED);
  86         mapChangeListener = new MockMapObserver<Object, Object>();
  87     }
  88 
  89     private void attachInvalidationListener() {
  90         property.addListener(invalidationListener);
  91         property.get();
  92         invalidationListener.reset();
  93     }
  94 
  95     private void attachChangeListener() {
  96         property.addListener(changeListener);
  97         property.get();
  98         changeListener.reset();
  99     }
 100 
 101     private void attachMapChangeListener() {
 102         property.addListener(mapChangeListener);
 103         property.get();
 104         mapChangeListener.clear();
 105     }
 106 
 107     @Test
 108     public void testConstructor() {
 109         final MapProperty<Object, Object> p1 = new SimpleMapProperty<Object, Object>();
 110         assertEquals(null, p1.get());
 111         assertEquals(null, p1.getValue());
 112         assertFalse(property.isBound());
 113 
 114         final MapProperty<Object, Object> p2 = new SimpleMapProperty<Object, Object>(VALUE_1b);
 115         assertEquals(VALUE_1b, p2.get());
 116         assertEquals(VALUE_1b, p2.getValue());
 117         assertFalse(property.isBound());
 118     }
 119 
 120     @Test
 121     public void testEmptyProperty() {
 122         assertEquals("empty", property.emptyProperty().getName());
 123         assertEquals(property, property.emptyProperty().getBean());
 124         assertTrue(property.emptyProperty().get());
 125 
 126         property.set(VALUE_2a);
 127         assertFalse(property.emptyProperty().get());
 128         property.set(VALUE_1a);
 129         assertTrue(property.emptyProperty().get());
 130     }
 131 
 132     @Test
 133     public void testSizeProperty() {
 134         assertEquals("size", property.sizeProperty().getName());
 135         assertEquals(property, property.sizeProperty().getBean());
 136         assertEquals(0, property.sizeProperty().get());
 137 
 138         property.set(VALUE_2a);
 139         assertEquals(2, property.sizeProperty().get());
 140         property.set(VALUE_1a);
 141         assertEquals(0, property.sizeProperty().get());
 142     }
 143 
 144     @Test
 145     public void testInvalidationListener() {
 146         attachInvalidationListener();
 147         property.set(VALUE_2a);
 148         invalidationListener.check(property, 1);
 149         property.removeListener(invalidationListener);
 150         invalidationListener.reset();
 151         property.set(VALUE_1a);
 152         invalidationListener.check(null, 0);
 153     }
 154 
 155     @Test
 156     public void testChangeListener() {
 157         attachChangeListener();
 158         property.set(VALUE_2a);
 159         changeListener.check(property, null, VALUE_2a, 1);
 160         property.removeListener(changeListener);
 161         changeListener.reset();
 162         property.set(VALUE_1a);
 163         changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 164     }
 165 
 166     @Test
 167     public void testMapChangeListener() {
 168         attachMapChangeListener();
 169         property.set(VALUE_2a);
 170         mapChangeListener.assertMultipleCalls(new Call[]{new Call(KEY_2a_0, null, DATA_2a_0), new Call(KEY_2a_1, null, DATA_2a_1)});
 171         property.removeListener(mapChangeListener);
 172         mapChangeListener.clear();
 173         property.set(VALUE_1a);
 174         assertEquals(0, mapChangeListener.getCallsNumber());
 175     }
 176     
 177     @Test
 178     public void testSourceMap_Invalidation() {
 179         final ObservableMap<Object, Object> source1 = FXCollections.observableMap(new HashMap<Object, Object>());
 180         final ObservableMap<Object, Object> source2 = FXCollections.observableMap(new HashMap<Object, Object>());
 181         final Object key = new Object();
 182         final Object value1 = new Object();
 183         final Object value2 = new Object();
 184         
 185         // constructor
 186         property = new MapPropertyMock(source1);
 187         property.reset();
 188         attachInvalidationListener();
 189         
 190         // add element
 191         source1.put(key, value1);
 192         assertEquals(value1, property.get(key));
 193         property.check(1);
 194         invalidationListener.check(property, 1);
 195         
 196         // replace element
 197         source1.put(key, value2);
 198         assertEquals(value2, property.get(key));
 199         property.check(1);
 200         invalidationListener.check(property, 1);
 201         
 202         // remove element
 203         source1.remove(key);
 204         assertNull(property.get(key));
 205         property.check(1);
 206         invalidationListener.check(property, 1);
 207         
 208         // set
 209         property.set(source2);
 210         property.get();
 211         property.reset();
 212         invalidationListener.reset();
 213         
 214         // add element
 215         source2.put(key, value1);
 216         assertEquals(value1, property.get(key));
 217         property.check(1);
 218         invalidationListener.check(property, 1);
 219         
 220         // replace element
 221         source2.put(key, value2);
 222         assertEquals(value2, property.get(key));
 223         property.check(1);
 224         invalidationListener.check(property, 1);
 225         
 226         // remove element
 227         source2.remove(key);
 228         assertNull(property.get(key));
 229         property.check(1);
 230         invalidationListener.check(property, 1);
 231     }
 232 
 233     @Test
 234     public void testSourceMap_Change() {
 235         final ObservableMap<Object, Object> source1 = FXCollections.observableMap(new HashMap<Object, Object>());
 236         final ObservableMap<Object, Object> source2 = FXCollections.observableMap(new HashMap<Object, Object>());
 237         final Object key = new Object();
 238         final Object value1 = new Object();
 239         final Object value2 = new Object();
 240         
 241         // constructor
 242         property = new MapPropertyMock(source1);
 243         property.reset();
 244         attachChangeListener();
 245         
 246         // add element
 247         source1.put(key, value1);
 248         assertEquals(value1, property.get(key));
 249         property.check(1);
 250         changeListener.check(property, source1, source1, 1);
 251         
 252         // replace element
 253         source1.put(key, value2);
 254         assertEquals(value2, property.get(key));
 255         property.check(1);
 256         changeListener.check(property, source1, source1, 1);
 257         
 258         // remove element
 259         source1.remove(key);
 260         assertNull(property.get(key));
 261         property.check(1);
 262         changeListener.check(property, source1, source1, 1);
 263         
 264         // set
 265         property.set(source2);
 266         property.get();
 267         property.reset();
 268         changeListener.reset();
 269         
 270         // add element
 271         source2.put(key, value1);
 272         assertEquals(value1, property.get(key));
 273         property.check(1);
 274         changeListener.check(property, source2, source2, 1);
 275         
 276         // replace element
 277         source2.put(key, value2);
 278         assertEquals(value2, property.get(key));
 279         property.check(1);
 280         changeListener.check(property, source2, source2, 1);
 281         
 282         // remove element
 283         source2.remove(key);
 284         assertNull(property.get(key));
 285         property.check(1);
 286         changeListener.check(property, source2, source2, 1);
 287     }
 288 
 289     @Test
 290     public void testSourceMap_MapChange() {
 291         final ObservableMap<Object, Object> source1 = FXCollections.observableMap(new HashMap<Object, Object>());
 292         final ObservableMap<Object, Object> source2 = FXCollections.observableMap(new HashMap<Object, Object>());
 293         final Object key = new Object();
 294         final Object value1 = new Object();
 295         final Object value2 = new Object();
 296         
 297         // constructor
 298         property = new MapPropertyMock(source1);
 299         property.reset();
 300         attachMapChangeListener();
 301         
 302         // add element
 303         source1.put(key, value1);
 304         assertEquals(value1, property.get(key));
 305         property.check(1);
 306         mapChangeListener.assertAdded(MockMapObserver.Tuple.tup(key, value1));
 307         mapChangeListener.clear();
 308         
 309         // replace element
 310         source1.put(key, value2);
 311         assertEquals(value2, property.get(key));
 312         property.check(1);
 313         mapChangeListener.assertMultipleCalls(new Call<Object, Object>(key, value1, value2));
 314         mapChangeListener.clear();
 315         
 316         // remove element
 317         source1.remove(key);
 318         assertNull(property.get(key));
 319         property.check(1);
 320         mapChangeListener.assertRemoved(MockMapObserver.Tuple.tup(key, value2));
 321         mapChangeListener.clear();
 322         
 323         // set
 324         property.set(source2);
 325         property.get();
 326         property.reset();
 327         mapChangeListener.clear();
 328         
 329         // add element
 330         source2.put(key, value1);
 331         assertEquals(value1, property.get(key));
 332         property.check(1);
 333         mapChangeListener.assertAdded(MockMapObserver.Tuple.tup(key, value1));
 334         mapChangeListener.clear();
 335         
 336         // replace element
 337         source2.put(key, value2);
 338         assertEquals(value2, property.get(key));
 339         property.check(1);
 340         mapChangeListener.assertMultipleCalls(new Call<Object, Object>(key, value1, value2));
 341         mapChangeListener.clear();
 342         
 343         // remove element
 344         source2.remove(key);
 345         assertNull(property.get(key));
 346         property.check(1);
 347         mapChangeListener.assertRemoved(MockMapObserver.Tuple.tup(key, value2));
 348         mapChangeListener.clear();
 349     }
 350 
 351     @Test
 352     public void testMap_Invalidation() {
 353         attachInvalidationListener();
 354 
 355         // set value once
 356         property.set(VALUE_2a);
 357         assertEquals(VALUE_2a, property.get());
 358         property.check(1);
 359         invalidationListener.check(property, 1);
 360 
 361         // set same value again
 362         property.set(VALUE_2a);
 363         assertEquals(VALUE_2a, property.get());
 364         property.check(0);
 365         invalidationListener.check(null, 0);
 366 
 367         // set value twice without reading
 368         property.set(VALUE_1a);
 369         property.set(VALUE_2b);
 370         assertEquals(VALUE_2b, property.get());
 371         property.check(1);
 372         invalidationListener.check(property, 1);
 373     }
 374 
 375     @Test
 376     public void testMap_Change() {
 377         attachChangeListener();
 378 
 379         // set value once
 380         property.set(VALUE_2a);
 381         assertEquals(VALUE_2a, property.get());
 382         property.check(1);
 383         changeListener.check(property, null, VALUE_2a, 1);
 384 
 385         // set same value again
 386         property.set(VALUE_2a);
 387         assertEquals(VALUE_2a, property.get());
 388         property.check(0);
 389         changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 390 
 391         // set value twice without reading
 392         property.set(VALUE_1a);
 393         property.set(VALUE_1b);
 394         assertEquals(VALUE_1b, property.get());
 395         property.check(2);
 396         changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 397     }
 398 
 399     @Test
 400     public void testMap_MapChange() {
 401         attachMapChangeListener();
 402 
 403         // set value once
 404         property.set(VALUE_2a);
 405         assertEquals(VALUE_2a, property.get());
 406         property.check(1);
 407         mapChangeListener.assertMultipleCalls(new Call[]{new Call(KEY_2a_0, null, DATA_2a_0), new Call(KEY_2a_1, null, DATA_2a_1)});
 408 
 409         // set same value again
 410         mapChangeListener.clear();
 411         property.set(VALUE_2a);
 412         assertEquals(VALUE_2a, property.get());
 413         property.check(0);
 414         assertEquals(0, mapChangeListener.getCallsNumber());
 415 
 416         // set value twice without reading
 417         property.set(VALUE_1a);
 418         mapChangeListener.clear();
 419         property.set(VALUE_1b);
 420         assertEquals(VALUE_1b, property.get());
 421         property.check(2);
 422         mapChangeListener.assertAdded(MockMapObserver.Tuple.tup(KEY_1b, DATA_1b));
 423     }
 424 
 425     @Test
 426     public void testMapValue_Invalidation() {
 427         attachInvalidationListener();
 428 
 429         // set value once
 430         property.setValue(VALUE_2a);
 431         assertEquals(VALUE_2a, property.get());
 432         property.check(1);
 433         invalidationListener.check(property, 1);
 434 
 435         // set same value again
 436         property.setValue(VALUE_2a);
 437         assertEquals(VALUE_2a, property.get());
 438         property.check(0);
 439         invalidationListener.check(null, 0);
 440 
 441         // set value twice without reading
 442         property.setValue(VALUE_1a);
 443         property.setValue(VALUE_1b);
 444         assertEquals(VALUE_1b, property.get());
 445         property.check(1);
 446         invalidationListener.check(property, 1);
 447     }
 448 
 449     @Test
 450     public void testMapValue_Change() {
 451         attachChangeListener();
 452 
 453         // set value once
 454         property.setValue(VALUE_2a);
 455         assertEquals(VALUE_2a, property.get());
 456         property.check(1);
 457         changeListener.check(property, null, VALUE_2a, 1);
 458 
 459         // set same value again
 460         property.setValue(VALUE_2a);
 461         assertEquals(VALUE_2a, property.get());
 462         property.check(0);
 463         changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 464 
 465         // set value twice without reading
 466         property.setValue(VALUE_1a);
 467         property.setValue(VALUE_1b);
 468         assertEquals(VALUE_1b, property.get());
 469         property.check(2);
 470         changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 471     }
 472 
 473     @Test
 474     public void testMapValue_MapChange() {
 475         attachMapChangeListener();
 476 
 477         // set value once
 478         property.setValue(VALUE_2a);
 479         assertEquals(VALUE_2a, property.get());
 480         property.check(1);
 481         mapChangeListener.assertMultipleCalls(new Call[]{new Call(KEY_2a_0, null, DATA_2a_0), new Call(KEY_2a_1, null, DATA_2a_1)});
 482 
 483         // set same value again
 484         mapChangeListener.clear();
 485         property.setValue(VALUE_2a);
 486         assertEquals(VALUE_2a, property.get());
 487         property.check(0);
 488         assertEquals(0, mapChangeListener.getCallsNumber());
 489 
 490         // set value twice without reading
 491         property.setValue(VALUE_1a);
 492         mapChangeListener.clear();
 493         property.setValue(VALUE_1b);
 494         assertEquals(VALUE_1b, property.get());
 495         property.check(2);
 496         mapChangeListener.assertAdded(MockMapObserver.Tuple.tup(KEY_1b, DATA_1b));
 497     }
 498 
 499     @Test(expected = RuntimeException.class)
 500     public void testMapBoundValue() {
 501         final MapProperty<Object, Object> v = new SimpleMapProperty<Object, Object>(VALUE_1a);
 502         property.bind(v);
 503         property.set(VALUE_1a);
 504     }
 505 
 506     @Test
 507     public void testBind_Invalidation() {
 508         attachInvalidationListener();
 509         final ObservableObjectValueStub<ObservableMap<Object, Object>> v = new ObservableObjectValueStub<ObservableMap<Object, Object>>(FXCollections.observableMap(VALUE_1a));
 510 
 511         property.bind(v);
 512         assertEquals(VALUE_1a, property.get());
 513         assertTrue(property.isBound());
 514         property.check(1);
 515         invalidationListener.check(property, 1);
 516 
 517         // change binding once
 518         v.set(VALUE_2a);
 519         assertEquals(VALUE_2a, property.get());
 520         property.check(1);
 521         invalidationListener.check(property, 1);
 522 
 523         // change binding twice without reading
 524         v.set(VALUE_1a);
 525         v.set(VALUE_1b);
 526         assertEquals(VALUE_1b, property.get());
 527         property.check(1);
 528         invalidationListener.check(property, 1);
 529 
 530         // change binding twice to same value
 531         v.set(VALUE_1a);
 532         v.set(VALUE_1a);
 533         assertEquals(VALUE_1a, property.get());
 534         property.check(1);
 535         invalidationListener.check(property, 1);
 536     }
 537 
 538     @Test
 539     public void testBind_Change() {
 540         attachChangeListener();
 541         final ObservableObjectValueStub<ObservableMap<Object, Object>> v = new ObservableObjectValueStub<ObservableMap<Object, Object>>(FXCollections.observableMap(VALUE_1a));
 542 
 543         property.bind(v);
 544         assertEquals(VALUE_1a, property.get());
 545         assertTrue(property.isBound());
 546         property.check(1);
 547         changeListener.check(property, null, VALUE_1a, 1);
 548 
 549         // change binding once
 550         v.set(VALUE_2a);
 551         assertEquals(VALUE_2a, property.get());
 552         property.check(1);
 553         changeListener.check(property, VALUE_1a, VALUE_2a, 1);
 554 
 555         // change binding twice without reading
 556         v.set(VALUE_1a);
 557         v.set(VALUE_1b);
 558         assertEquals(VALUE_1b, property.get());
 559         property.check(2);
 560         changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 561 
 562         // change binding twice to same value
 563         v.set(VALUE_1a);
 564         v.set(VALUE_1a);
 565         assertEquals(VALUE_1a, property.get());
 566         property.check(2);
 567         changeListener.check(property, VALUE_1b, VALUE_1a, 1);
 568     }
 569 
 570     @Test
 571     public void testBind_MapChange() {
 572         attachMapChangeListener();
 573         final ObservableObjectValueStub<ObservableMap<Object, Object>> v = new ObservableObjectValueStub<ObservableMap<Object, Object>>(FXCollections.observableMap(VALUE_1a));
 574 
 575         property.bind(v);
 576         assertEquals(VALUE_1a, property.get());
 577         assertTrue(property.isBound());
 578         property.check(1);
 579         assertEquals(0, mapChangeListener.getCallsNumber());
 580 
 581         // change binding once
 582         mapChangeListener.clear();
 583         v.set(VALUE_2a);
 584         assertEquals(VALUE_2a, property.get());
 585         property.check(1);
 586         mapChangeListener.assertMultipleCalls(new Call[]{new Call(KEY_2a_0, null, DATA_2a_0), new Call(KEY_2a_1, null, DATA_2a_1)});
 587 
 588         // change binding twice without reading
 589         v.set(VALUE_1a);
 590         mapChangeListener.clear();
 591         v.set(VALUE_1b);
 592         assertEquals(VALUE_1b, property.get());
 593         property.check(2);
 594         mapChangeListener.assertAdded(MockMapObserver.Tuple.tup(KEY_1b, DATA_1b));
 595 
 596         // change binding twice to same value
 597         v.set(VALUE_1a);
 598         mapChangeListener.clear();
 599         v.set(VALUE_1a);
 600         assertEquals(VALUE_1a, property.get());
 601         property.check(2);
 602         assertEquals(0, mapChangeListener.getCallsNumber());
 603     }
 604 
 605     @Test(expected = NullPointerException.class)
 606     public void testBindToNull() {
 607         property.bind(null);
 608     }
 609 
 610     @Test
 611     public void testRebind() {
 612         attachInvalidationListener();
 613         final MapProperty<Object, Object> v1 = new SimpleMapProperty<Object, Object>(VALUE_1a);
 614         final MapProperty<Object, Object> v2 = new SimpleMapProperty<Object, Object>(VALUE_2a);
 615         property.bind(v1);
 616         property.get();
 617         property.reset();
 618         invalidationListener.reset();
 619 
 620         // rebind causes invalidation event
 621         property.bind(v2);
 622         assertEquals(VALUE_2a, property.get());
 623         assertTrue(property.isBound());
 624         assertEquals(1, property.counter);
 625         invalidationListener.check(property, 1);
 626         property.reset();
 627 
 628         // change old binding
 629         v1.set(VALUE_1b);
 630         assertEquals(VALUE_2a, property.get());
 631         assertEquals(0, property.counter);
 632         invalidationListener.check(null, 0);
 633         property.reset();
 634 
 635         // change new binding
 636         v2.set(VALUE_2b);
 637         assertEquals(VALUE_2b, property.get());
 638         assertEquals(1, property.counter);
 639         invalidationListener.check(property, 1);
 640         property.reset();
 641 
 642         // rebind to same observable should have no effect
 643         property.bind(v2);
 644         assertEquals(VALUE_2b, property.get());
 645         assertTrue(property.isBound());
 646         assertEquals(0, property.counter);
 647         invalidationListener.check(null, 0);
 648     }
 649 
 650     @Test
 651     public void testUnbind() {
 652         attachInvalidationListener();
 653         final MapProperty<Object, Object> v = new SimpleMapProperty<Object, Object>(VALUE_1a);
 654         property.bind(v);
 655         property.unbind();
 656         assertEquals(VALUE_1a, property.get());
 657         assertFalse(property.isBound());
 658         property.reset();
 659         invalidationListener.reset();
 660 
 661         // change binding
 662         v.set(VALUE_2a);
 663         assertEquals(VALUE_1a, property.get());
 664         assertEquals(0, property.counter);
 665         invalidationListener.check(null, 0);
 666         property.reset();
 667 
 668         // set value
 669         property.set(VALUE_1b);
 670         assertEquals(VALUE_1b, property.get());
 671         assertEquals(1, property.counter);
 672         invalidationListener.check(property, 1);
 673     }
 674 
 675     @Test
 676     public void testAddingListenerWillAlwaysReceiveInvalidationEvent() {
 677         final MapProperty<Object, Object> v = new SimpleMapProperty<Object, Object>(VALUE_1a);
 678         final InvalidationListenerMock listener2 = new InvalidationListenerMock();
 679         final InvalidationListenerMock listener3 = new InvalidationListenerMock();
 680 
 681         // setting the property
 682         property.set(VALUE_1a);
 683         property.addListener(listener2);
 684         listener2.reset();
 685         property.set(VALUE_1b);
 686         listener2.check(property, 1);
 687 
 688         // binding the property
 689         property.bind(v);
 690         v.set(VALUE_2a);
 691         property.addListener(listener3);
 692         v.get();
 693         listener3.reset();
 694         v.set(VALUE_2b);
 695         listener3.check(property, 1);
 696     }
 697 
 698     @Test
 699     public void testToString() {
 700         final ObservableMap<Object, Object> value0 = null;
 701         final ObservableMap<Object, Object> value1 = FXCollections.observableMap(new HashMap<Object, Object>());
 702         value1.put(new Object(), new Object());
 703         value1.put(new Object(), new Object());
 704         final ObservableMap<Object, Object> value2 = FXCollections.observableMap(new HashMap<Object, Object>());
 705         final MapProperty<Object, Object> v = new SimpleMapProperty<Object, Object>(value2);
 706 
 707         property.set(value1);
 708         assertEquals("MapProperty [value: " + value1 + "]", property.toString());
 709 
 710         property.bind(v);
 711         assertEquals("MapProperty [bound, invalid]", property.toString());
 712         property.get();
 713         assertEquals("MapProperty [bound, value: " + value2 + "]", property.toString());
 714         v.set(value1);
 715         assertEquals("MapProperty [bound, invalid]", property.toString());
 716         property.get();
 717         assertEquals("MapProperty [bound, value: " + value1 + "]", property.toString());
 718 
 719         final Object bean = new Object();
 720         final String name = "My name";
 721         final MapProperty<Object, Object> v1 = new MapPropertyMock(bean, name);
 722         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + null + "]", v1.toString());
 723         v1.set(value1);
 724         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + value1 + "]", v1.toString());
 725         v1.set(value0);
 726         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString());
 727 
 728         final MapProperty<Object, Object> v2 = new MapPropertyMock(bean, NO_NAME_1);
 729         assertEquals("MapProperty [bean: " + bean.toString() + ", value: " + null + "]", v2.toString());
 730         v2.set(value1);
 731         assertEquals("MapProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v2.toString());
 732         v1.set(value0);
 733         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString());
 734 
 735         final MapProperty<Object, Object> v3 = new MapPropertyMock(bean, NO_NAME_2);
 736         assertEquals("MapProperty [bean: " + bean.toString() + ", value: " + null + "]", v3.toString());
 737         v3.set(value1);
 738         assertEquals("MapProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v3.toString());
 739         v1.set(value0);
 740         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString());
 741 
 742         final MapProperty<Object, Object> v4 = new MapPropertyMock(NO_BEAN, name);
 743         assertEquals("MapProperty [name: My name, value: " + null + "]", v4.toString());
 744         v4.set(value1);
 745         v1.set(value0);
 746         assertEquals("MapProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString());
 747         assertEquals("MapProperty [name: My name, value: " + value1 + "]", v4.toString());
 748     }
 749 
 750     private static class MapPropertyMock extends MapPropertyBase<Object, Object> {
 751 
 752         private final Object bean;
 753         private final String name;
 754         private int counter;
 755 
 756         private MapPropertyMock() {
 757             this.bean = NO_BEAN;
 758             this.name = NO_NAME_1;
 759         }
 760 
 761         private MapPropertyMock(Object bean, String name) {
 762             this.bean = bean;
 763             this.name = name;
 764         }
 765         
 766         private MapPropertyMock(ObservableMap<Object, Object> initialValue) {
 767             super(initialValue);
 768             this.bean = NO_BEAN;
 769             this.name = NO_NAME_1;
 770         }
 771 
 772         @Override
 773         protected void invalidated() {
 774             counter++;
 775         }
 776 
 777         private void check(int expected) {
 778             assertEquals(expected, counter);
 779             reset();
 780         }
 781 
 782         private void reset() {
 783             counter = 0;
 784         }
 785 
 786         @Override
 787         public Object getBean() {
 788             return bean;
 789         }
 790 
 791         @Override
 792         public String getName() {
 793             return name;
 794         }
 795     }
 796 }