1 /*
   2  * Copyright (c) 2012, 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.binding;
  27 
  28 import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
  29 import javafx.beans.InvalidationListenerMock;
  30 import javafx.beans.Observable;
  31 import javafx.beans.binding.SetBinding;
  32 import javafx.beans.property.ReadOnlyBooleanProperty;
  33 import javafx.beans.property.ReadOnlyIntegerProperty;
  34 import javafx.beans.value.ChangeListenerMock;
  35 import javafx.beans.value.ObservableValueBase;
  36 import javafx.collections.FXCollections;
  37 import javafx.collections.MockSetObserver;
  38 import javafx.collections.ObservableList;
  39 import javafx.collections.ObservableSet;
  40 import org.junit.Before;
  41 import org.junit.Test;
  42 
  43 import static javafx.collections.MockSetObserver.Call;
  44 import static org.junit.Assert.*;
  45 
  46 /**
  47  */
  48 public class SetBindingTest {
  49 
  50     private final static Object DATA_1 = new Object();
  51     private final static Object DATA_2_0 = new Object();
  52     private final static Object DATA_2_1 = new Object();
  53 
  54     private ObservableStub dependency1;
  55     private ObservableStub dependency2;
  56 
  57     private SetBindingImpl binding0;
  58     private SetBindingImpl binding1;
  59     private SetBindingImpl binding2;
  60 
  61     private ObservableSet<Object> emptySet;
  62     private ObservableSet<Object> set1;
  63     private ObservableSet<Object> set2;
  64 
  65     private MockSetObserver<Object> listener;
  66 
  67     @Before
  68     public void setUp() {
  69         dependency1 = new ObservableStub();
  70         dependency2 = new ObservableStub();
  71         binding0 = new SetBindingImpl();
  72         binding1 = new SetBindingImpl(dependency1);
  73         binding2 = new SetBindingImpl(dependency1, dependency2);
  74         emptySet = FXCollections.observableSet();
  75         set1 = FXCollections.observableSet(DATA_1);
  76         set2 = FXCollections.observableSet(DATA_2_0, DATA_2_1);
  77         listener = new MockSetObserver<Object>();
  78         binding0.setValue(set2);
  79         binding1.setValue(set2);
  80         binding2.setValue(set2);
  81     }
  82 
  83     @Test
  84     public void testSizeProperty() {
  85         assertEquals(binding0, binding0.sizeProperty().getBean());
  86         assertEquals(binding1, binding1.sizeProperty().getBean());
  87         assertEquals(binding2, binding2.sizeProperty().getBean());
  88 
  89         final ReadOnlyIntegerProperty size = binding1.sizeProperty();
  90         assertEquals("size", size.getName());
  91 
  92         assertEquals(2, size.get());
  93         binding1.setValue(emptySet);
  94         dependency1.fireValueChangedEvent();
  95         assertEquals(0, size.get());
  96         binding1.setValue(null);
  97         dependency1.fireValueChangedEvent();
  98         assertEquals(0, size.get());
  99         binding1.setValue(set1);
 100         dependency1.fireValueChangedEvent();
 101         assertEquals(1, size.get());
 102     }
 103 
 104     @Test
 105     public void testEmptyProperty() {
 106         assertEquals(binding0, binding0.emptyProperty().getBean());
 107         assertEquals(binding1, binding1.emptyProperty().getBean());
 108         assertEquals(binding2, binding2.emptyProperty().getBean());
 109 
 110         final ReadOnlyBooleanProperty empty = binding1.emptyProperty();
 111         assertEquals("empty", empty.getName());
 112 
 113         assertFalse(empty.get());
 114         binding1.setValue(emptySet);
 115         dependency1.fireValueChangedEvent();
 116         assertTrue(empty.get());
 117         binding1.setValue(null);
 118         dependency1.fireValueChangedEvent();
 119         assertTrue(empty.get());
 120         binding1.setValue(set1);
 121         dependency1.fireValueChangedEvent();
 122         assertFalse(empty.get());
 123     }
 124 
 125     @Test
 126     public void testNoDependency_SetChangeListener() {
 127         binding0.getValue();
 128         binding0.addListener(listener);
 129         System.gc(); // making sure we did not not overdo weak references
 130         assertEquals(true, binding0.isValid());
 131 
 132         // calling getValue()
 133         binding0.reset();
 134         binding0.getValue();
 135         assertEquals(0, binding0.getComputeValueCounter());
 136         assertEquals(0, listener.getCallsNumber());
 137         assertEquals(true, binding0.isValid());
 138     }
 139 
 140     @Test
 141     public void testSingleDependency_SetChangeListener() {
 142         binding1.getValue();
 143         binding1.addListener(listener);
 144         System.gc(); // making sure we did not not overdo weak references
 145         assertEquals(true, binding1.isValid());
 146 
 147         // fire single change event
 148         binding1.reset();
 149         listener.clear();
 150         binding1.setValue(set1);
 151         dependency1.fireValueChangedEvent();
 152         assertEquals(1, binding1.getComputeValueCounter());
 153         listener.assertMultipleCalls(new Call[]{new Call<Object>(DATA_2_0, null), new Call<Object>(DATA_2_1, null), new Call<Object>(null, DATA_1)});
 154         assertEquals(true, binding1.isValid());
 155         listener.clear();
 156 
 157         binding1.getValue();
 158         assertEquals(0, binding1.getComputeValueCounter());
 159         assertEquals(0, listener.getCallsNumber());
 160         assertEquals(true, binding1.isValid());
 161         listener.clear();
 162 
 163         // fire single change event with same value
 164         binding1.setValue(set1);
 165         dependency1.fireValueChangedEvent();
 166         assertEquals(1, binding1.getComputeValueCounter());
 167         assertEquals(0, listener.getCallsNumber());
 168         assertEquals(true, binding1.isValid());
 169         listener.clear();
 170 
 171         binding1.getValue();
 172         assertEquals(0, binding1.getComputeValueCounter());
 173         assertEquals(0, listener.getCallsNumber());
 174         assertEquals(true, binding1.isValid());
 175         listener.clear();
 176 
 177         // fire two change events
 178         binding1.setValue(set2);
 179         dependency1.fireValueChangedEvent();
 180         listener.clear();
 181         binding1.setValue(set1);
 182         dependency1.fireValueChangedEvent();
 183         assertEquals(2, binding1.getComputeValueCounter());
 184         listener.assertMultipleCalls(new Call[]{new Call<Object>(DATA_2_0, null), new Call<Object>(DATA_2_1, null), new Call<Object>(null, DATA_1)});
 185         assertEquals(true, binding1.isValid());
 186         listener.clear();
 187 
 188         binding1.getValue();
 189         assertEquals(0, binding1.getComputeValueCounter());
 190         assertEquals(0, listener.getCallsNumber());
 191         assertEquals(true, binding1.isValid());
 192         listener.clear();
 193 
 194         // fire two change events with same value
 195         binding1.setValue(set2);
 196         dependency1.fireValueChangedEvent();
 197         binding1.setValue(set2);
 198         dependency1.fireValueChangedEvent();
 199         assertEquals(2, binding1.getComputeValueCounter());
 200         listener.assertMultipleCalls(new Call[] {new Call<Object>(DATA_1, null), new Call<Object>(null, DATA_2_0), new Call<Object>(null, DATA_2_1)});
 201         assertEquals(true, binding1.isValid());
 202         listener.clear();
 203 
 204         binding1.getValue();
 205         assertEquals(0, binding1.getComputeValueCounter());
 206         assertEquals(0, listener.getCallsNumber());
 207         assertEquals(true, binding1.isValid());
 208     }
 209 
 210     @Test
 211     public void testChangeContent_InvalidationListener() {
 212         final InvalidationListenerMock listenerMock = new InvalidationListenerMock();
 213         binding1.get();
 214         binding1.addListener(listenerMock);
 215         assertTrue(binding1.isValid());
 216 
 217         binding1.reset();
 218         listenerMock.reset();
 219         set2.add(new Object());
 220         assertEquals(0, binding1.getComputeValueCounter());
 221         listenerMock.check(binding1, 1);
 222         assertTrue(binding1.isValid());
 223     }
 224 
 225     @Test
 226     public void testChangeContent_ChangeListener() {
 227         final ChangeListenerMock listenerMock = new ChangeListenerMock(null);
 228         binding1.get();
 229         binding1.addListener(listenerMock);
 230         assertTrue(binding1.isValid());
 231 
 232         binding1.reset();
 233         listenerMock.reset();
 234         set2.add(new Object());
 235         assertEquals(0, binding1.getComputeValueCounter());
 236         listenerMock.check(binding1, set2, set2, 1);
 237         assertTrue(binding1.isValid());
 238     }
 239 
 240     @Test
 241     public void testChangeContent_SetChangeListener() {
 242         binding1.get();
 243         binding1.addListener(listener);
 244         assertTrue(binding1.isValid());
 245 
 246         final int oldSize = set2.size();
 247         final Object newObject = new Object();
 248         binding1.reset();
 249         listener.clear();
 250         set2.add(newObject);
 251         assertEquals(0, binding1.getComputeValueCounter());
 252         listener.assertAdded(MockSetObserver.Tuple.tup(newObject));
 253         assertTrue(binding1.isValid());
 254     }
 255 
 256     public static class ObservableStub extends ObservableValueBase<Object> {
 257         @Override public void fireValueChangedEvent() {super.fireValueChangedEvent();}
 258 
 259         @Override
 260         public Object getValue() {
 261             return null;
 262         }
 263     }
 264 
 265     private static class SetBindingImpl extends SetBinding<Object> {
 266 
 267         private int computeValueCounter = 0;
 268         private ObservableSet<Object> value;
 269 
 270         public void setValue(ObservableSet<Object> value) {
 271             this.value = value;
 272         }
 273 
 274         public SetBindingImpl(Observable... dep) {
 275             super.bind(dep);
 276         }
 277 
 278         public int getComputeValueCounter() {
 279             final int result = computeValueCounter;
 280             reset();
 281             return result;
 282         }
 283 
 284         public void reset() {
 285             computeValueCounter = 0;
 286         }
 287 
 288         @Override
 289         public ObservableSet<Object> computeValue() {
 290             computeValueCounter++;
 291             return value;
 292         }
 293 
 294         @Override @ReturnsUnmodifiableCollection
 295         public ObservableList<?> getDependencies() {
 296             fail("Should not reach here");
 297             return null;
 298         }
 299     }
 300 
 301 
 302 //    private class SetChangeListenerMock implements SetChangeListener<Object> {
 303 //        
 304 //        private Change<? extends Object> change;
 305 //        private int counter;
 306 //
 307 //        @Override
 308 //        public void onChanged(Change<? extends Object> change) {
 309 //            this.change = change;
 310 //            counter++;
 311 //        }
 312 //        
 313 //        private void reset() {
 314 //            change = null;
 315 //            counter = 0;
 316 //        }
 317 //
 318 //        private void checkNotCalled() {
 319 //            assertEquals(null, change);
 320 //            assertEquals(0, counter);
 321 //            reset();
 322 //        }
 323 //
 324 //        private void check(ObservableSet<Object> oldSet, ObservableSet<Object> newSet, int counter) {
 325 //            assertTrue(change.next());
 326 //            assertTrue(change.wasReplaced());
 327 //            assertEquals(oldSet, change.getRemoved());
 328 //            assertEquals(newSet, change.getSet());
 329 //            assertFalse(change.next());
 330 //            assertEquals(counter, this.counter);
 331 //            reset();
 332 //        }
 333 //
 334 //        private void check(int pos, Object newObject, int counter) {
 335 //            assertTrue(change.next());
 336 //            assertTrue(change.wasAdded());
 337 //            assertEquals(pos, change.getFrom());
 338 //            assertEquals(Collections.singletonSet(newObject), change.getAddedSubSet());
 339 //            assertFalse(change.next());
 340 //            assertEquals(counter, this.counter);
 341 //            reset();
 342 //        }
 343 //    }
 344 }