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