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