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 }