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 static org.junit.Assert.assertEquals;
  29 import static org.junit.Assert.assertFalse;
  30 import static org.junit.Assert.assertTrue;
  31 
  32 import javafx.beans.InvalidationListenerMock;
  33 import javafx.beans.value.ChangeListenerMock;
  34 import javafx.beans.value.ObservableObjectValueStub;
  35 
  36 import org.junit.Before;
  37 import org.junit.Test;
  38 
  39 public class ObjectPropertyBaseTest {
  40 
  41     private static final Object NO_BEAN = null;
  42     private static final String NO_NAME_1 = null;
  43     private static final String NO_NAME_2 = "";
  44     private static final Object UNDEFINED = new Object();
  45         private static final Object VALUE_1a = new Object();
  46         private static final Object VALUE_1b = new Object();
  47         private static final Object VALUE_2a = new Object();
  48         private static final Object VALUE_2b = new Object();
  49         
  50         private ObjectPropertyMock property;
  51         private InvalidationListenerMock invalidationListener;
  52         private ChangeListenerMock<Object> changeListener;
  53 
  54         @Before
  55         public void setUp() throws Exception {
  56                 property = new ObjectPropertyMock();
  57                 invalidationListener = new InvalidationListenerMock();
  58         changeListener = new ChangeListenerMock<Object>(UNDEFINED);
  59         }
  60 
  61         private void attachInvalidationListener() {
  62                 property.addListener(invalidationListener);
  63                 property.get();
  64                 invalidationListener.reset();
  65         }
  66 
  67         private void attachChangeListener() {
  68                 property.addListener(changeListener);
  69                 property.get();
  70                 changeListener.reset();
  71         }
  72 
  73         @Test
  74         public void testConstructor() {
  75                 final ObjectProperty<Object> p1 = new SimpleObjectProperty<Object>();
  76                 assertEquals(null, p1.get());
  77                 assertEquals(null, p1.getValue());
  78                 assertFalse(property.isBound());
  79                 
  80                 final ObjectProperty<Object> p2 = new SimpleObjectProperty<Object>(VALUE_1b);
  81                 assertEquals(VALUE_1b, p2.get());
  82                 assertEquals(VALUE_1b, p2.getValue());
  83                 assertFalse(property.isBound());
  84         }
  85 
  86     @Test
  87     public void testInvalidationListener() {
  88         attachInvalidationListener();
  89         property.set(VALUE_2a);
  90         invalidationListener.check(property, 1);
  91         property.removeListener(invalidationListener);
  92         invalidationListener.reset();
  93         property.set(VALUE_1a);
  94         invalidationListener.check(null, 0);
  95     }
  96 
  97     @Test
  98     public void testChangeListener() {
  99         attachChangeListener();
 100         property.set(VALUE_2a);
 101         changeListener.check(property, null, VALUE_2a, 1);
 102         property.removeListener(changeListener);
 103         changeListener.reset();
 104         property.set(VALUE_1a);
 105         changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 106     }
 107 
 108         @Test
 109         public void testLazySet() {
 110                 attachInvalidationListener();
 111 
 112                 // set value once
 113                 property.set(VALUE_2a);
 114                 assertEquals(VALUE_2a, property.get());
 115                 property.check(1);
 116                 invalidationListener.check(property, 1);
 117 
 118                 // set same value again
 119                 property.set(VALUE_2a);
 120                 assertEquals(VALUE_2a, property.get());
 121                 property.check(0);
 122                 invalidationListener.check(null, 0);
 123 
 124                 // set value twice without reading
 125                 property.set(VALUE_1a);
 126                 property.set(VALUE_1b);
 127                 assertEquals(VALUE_1b, property.get());
 128                 property.check(1);
 129                 invalidationListener.check(property, 1);
 130         }
 131 
 132         @Test
 133         public void testEagerSet() {
 134                 attachChangeListener();
 135 
 136                 // set value once
 137                 property.set(VALUE_2a);
 138                 assertEquals(VALUE_2a, property.get());
 139                 property.check(1);
 140                 changeListener.check(property, null, VALUE_2a, 1);
 141 
 142                 // set same value again
 143                 property.set(VALUE_2a);
 144                 assertEquals(VALUE_2a, property.get());
 145                 property.check(0);
 146                 changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 147 
 148                 // set value twice without reading
 149                 property.set(VALUE_1a);
 150                 property.set(VALUE_1b);
 151                 assertEquals(VALUE_1b, property.get());
 152                 property.check(2);
 153                 changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 154         }
 155 
 156         @Test
 157         public void testLazySetValue() {
 158                 attachInvalidationListener();
 159 
 160                 // set value once
 161                 property.setValue(VALUE_2a);
 162                 assertEquals(VALUE_2a, property.get());
 163                 property.check(1);
 164                 invalidationListener.check(property, 1);
 165 
 166                 // set same value again
 167                 property.setValue(VALUE_2a);
 168                 assertEquals(VALUE_2a, property.get());
 169                 property.check(0);
 170                 invalidationListener.check(null, 0);
 171 
 172                 // set value twice without reading
 173                 property.setValue(VALUE_1a);
 174                 property.setValue(VALUE_1b);
 175                 assertEquals(VALUE_1b, property.get());
 176                 property.check(1);
 177                 invalidationListener.check(property, 1);
 178         }
 179 
 180         @Test
 181         public void testEagerSetValue() {
 182                 attachChangeListener();
 183 
 184                 // set value once
 185                 property.setValue(VALUE_2a);
 186                 assertEquals(VALUE_2a, property.get());
 187                 property.check(1);
 188                 changeListener.check(property, null, VALUE_2a, 1);
 189 
 190                 // set same value again
 191                 property.setValue(VALUE_2a);
 192                 assertEquals(VALUE_2a, property.get());
 193                 property.check(0);
 194                 changeListener.check(null, UNDEFINED, UNDEFINED, 0);
 195 
 196                 // set value twice without reading
 197                 property.setValue(VALUE_1a);
 198                 property.setValue(VALUE_1b);
 199                 assertEquals(VALUE_1b, property.get());
 200                 property.check(2);
 201                 changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 202         }
 203 
 204         @Test(expected=RuntimeException.class)
 205         public void testSetBoundValue() {
 206                 final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1a);
 207                 property.bind(v);
 208                 property.set(VALUE_1a);
 209         }
 210 
 211         @Test
 212         public void testLazyBind() {
 213                 attachInvalidationListener();
 214                 final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1a);
 215 
 216                 property.bind(v);
 217                 assertEquals(VALUE_1a, property.get());
 218                 assertTrue(property.isBound());
 219                 property.check(1);
 220                 invalidationListener.check(property, 1);
 221 
 222                 // change binding once
 223                 v.set(VALUE_2a);
 224                 assertEquals(VALUE_2a, property.get());
 225                 property.check(1);
 226                 invalidationListener.check(property, 1);
 227 
 228                 // change binding twice without reading
 229                 v.set(VALUE_1a);
 230                 v.set(VALUE_1b);
 231                 assertEquals(VALUE_1b, property.get());
 232                 property.check(1);
 233                 invalidationListener.check(property, 1);
 234 
 235                 // change binding twice to same value
 236                 v.set(VALUE_1a);
 237                 v.set(VALUE_1a);
 238                 assertEquals(VALUE_1a, property.get());
 239                 property.check(1);
 240                 invalidationListener.check(property, 1);
 241         }
 242 
 243         @Test
 244         public void testEagerBind() {
 245                 attachChangeListener();
 246                 final ObservableObjectValueStub<Object> v = new ObservableObjectValueStub<Object>(VALUE_1a);
 247 
 248                 property.bind(v);
 249                 assertEquals(VALUE_1a, property.get());
 250                 assertTrue(property.isBound());
 251                 property.check(1);
 252                 changeListener.check(property, null, VALUE_1a, 1);
 253 
 254                 // change binding once
 255                 v.set(VALUE_2a);
 256                 assertEquals(VALUE_2a, property.get());
 257                 property.check(1);
 258                 changeListener.check(property, VALUE_1a, VALUE_2a, 1);
 259 
 260                 // change binding twice without reading
 261                 v.set(VALUE_1a);
 262                 v.set(VALUE_1b);
 263                 assertEquals(VALUE_1b, property.get());
 264                 property.check(2);
 265                 changeListener.check(property, VALUE_1a, VALUE_1b, 2);
 266 
 267                 // change binding twice to same value
 268                 v.set(VALUE_1a);
 269                 v.set(VALUE_1a);
 270                 assertEquals(VALUE_1a, property.get());
 271                 property.check(2);
 272                 changeListener.check(property, VALUE_1b, VALUE_1a, 1);
 273         }
 274 
 275         @Test(expected=NullPointerException.class)
 276         public void testBindToNull() {
 277                 property.bind(null);
 278         }
 279 
 280         @Test
 281         public void testRebind() {
 282                 attachInvalidationListener();
 283                 final ObjectProperty<Object> v1 = new SimpleObjectProperty<Object>(VALUE_1a);
 284                 final ObjectProperty<Object> v2 = new SimpleObjectProperty<Object>(VALUE_2a);
 285                 property.bind(v1);
 286                 property.get();
 287                 property.reset();
 288                 invalidationListener.reset();
 289                 
 290                 // rebind causes invalidation event
 291                 property.bind(v2);
 292                 assertEquals(VALUE_2a, property.get());
 293                 assertTrue(property.isBound());
 294                 assertEquals(1, property.counter);
 295                 invalidationListener.check(property, 1);
 296                 property.reset();
 297                 
 298                 // change old binding
 299                 v1.set(VALUE_1b);
 300                 assertEquals(VALUE_2a, property.get());
 301                 assertEquals(0, property.counter);
 302                 invalidationListener.check(null, 0);
 303                 property.reset();
 304                 
 305                 // change new binding
 306                 v2.set(VALUE_2b);
 307                 assertEquals(VALUE_2b, property.get());
 308                 assertEquals(1, property.counter);
 309                 invalidationListener.check(property, 1);
 310                 property.reset();
 311                 
 312                 // rebind to same observable should have no effect
 313                 property.bind(v2);
 314                 assertEquals(VALUE_2b, property.get());
 315                 assertTrue(property.isBound());
 316                 assertEquals(0, property.counter);
 317                 invalidationListener.check(null, 0);
 318         }
 319 
 320         @Test
 321         public void testUnbind() {
 322                 attachInvalidationListener();
 323                 final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1a);
 324                 property.bind(v);
 325                 property.unbind();
 326                 assertEquals(VALUE_1a, property.get());
 327                 assertFalse(property.isBound());
 328         property.reset();
 329         invalidationListener.reset();
 330                 
 331                 // change binding
 332                 v.set(VALUE_2a);
 333                 assertEquals(VALUE_1a, property.get());
 334                 assertEquals(0, property.counter);
 335                 invalidationListener.check(null, 0);
 336                 property.reset();
 337                 
 338                 // set value
 339                 property.set(VALUE_1b);
 340                 assertEquals(VALUE_1b, property.get());
 341                 assertEquals(1, property.counter);
 342                 invalidationListener.check(property, 1);
 343         }
 344         
 345         @Test
 346         public void testAddingListenerWillAlwaysReceiveInvalidationEvent() {
 347                 final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(VALUE_1a);
 348                 final InvalidationListenerMock listener2 = new InvalidationListenerMock();
 349                 final InvalidationListenerMock listener3 = new InvalidationListenerMock();
 350 
 351                 // setting the property
 352                 property.set(VALUE_1a);
 353                 property.addListener(listener2);
 354                 listener2.reset();
 355                 property.set(VALUE_1b);
 356                 listener2.check(property, 1);
 357                 
 358                 // binding the property
 359                 property.bind(v);
 360                 v.set(VALUE_2a);
 361                 property.addListener(listener3);
 362                 v.get();
 363                 listener3.reset();
 364                 v.set(VALUE_2b);
 365                 listener3.check(property, 1);
 366         }
 367         
 368         @Test
 369         public void testToString() {
 370                 final Object value1 = new Object();
 371                 final Object value2 = new Object();
 372                 final ObjectProperty<Object> v = new SimpleObjectProperty<Object>(value2);
 373                 
 374                 property.set(value1);
 375                 assertEquals("ObjectProperty [value: " + value1 + "]", property.toString());
 376                 
 377                 property.bind(v);
 378                 assertEquals("ObjectProperty [bound, invalid]", property.toString());
 379                 property.get();
 380                 assertEquals("ObjectProperty [bound, value: " + value2 + "]", property.toString());
 381                 v.set(value1);
 382                 assertEquals("ObjectProperty [bound, invalid]", property.toString());
 383                 property.get();
 384                 assertEquals("ObjectProperty [bound, value: " + value1 + "]", property.toString());
 385         
 386         final Object bean = new Object();
 387         final String name = "My name";
 388         final ObjectProperty<Object> v1 = new ObjectPropertyMock(bean, name);
 389         assertEquals("ObjectProperty [bean: " + bean.toString() + ", name: My name, value: " + null + "]", v1.toString());
 390         v1.set(value1);
 391         assertEquals("ObjectProperty [bean: " + bean.toString() + ", name: My name, value: " + value1 + "]", v1.toString());
 392         
 393         final ObjectProperty<Object> v2 = new ObjectPropertyMock(bean, NO_NAME_1);
 394         assertEquals("ObjectProperty [bean: " + bean.toString() + ", value: " + null + "]", v2.toString());
 395         v2.set(value1);
 396         assertEquals("ObjectProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v2.toString());
 397 
 398         final ObjectProperty<Object> v3 = new ObjectPropertyMock(bean, NO_NAME_2);
 399         assertEquals("ObjectProperty [bean: " + bean.toString() + ", value: " + null + "]", v3.toString());
 400         v3.set(value1);
 401         assertEquals("ObjectProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v3.toString());
 402 
 403         final ObjectProperty<Object> v4 = new ObjectPropertyMock(NO_BEAN, name);
 404         assertEquals("ObjectProperty [name: My name, value: " + null + "]", v4.toString());
 405         v4.set(value1);
 406         assertEquals("ObjectProperty [name: My name, value: " + value1 + "]", v4.toString());
 407         }
 408         
 409         private static class ObjectPropertyMock extends ObjectPropertyBase<Object> {
 410         
 411         private final Object bean;
 412         private final String name;
 413                 private int counter;
 414                 
 415         private ObjectPropertyMock() {
 416             this.bean = NO_BEAN;
 417             this.name = NO_NAME_1;
 418         }
 419         
 420         private ObjectPropertyMock(Object bean, String name) {
 421             this.bean = bean;
 422             this.name = name;
 423         }
 424         
 425                 @Override
 426                 protected void invalidated() {
 427                         counter++;
 428                 }
 429                 
 430                 private void check(int expected) {
 431                         assertEquals(expected, counter);
 432                         reset();
 433                 }
 434 
 435                 private void reset() {
 436                         counter = 0;
 437                 }
 438 
 439         @Override public Object getBean() { return bean; }
 440 
 441         @Override public String getName() { return name; }
 442         }
 443 
 444 }