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.value; 27 28 import javafx.beans.InvalidationListener; 29 import javafx.beans.InvalidationListenerMock; 30 import javafx.beans.Observable; 31 32 import org.junit.Before; 33 import org.junit.Test; 34 35 public class ObservableValueBaseTest { 36 37 private static final Object UNDEFINED_VALUE = new Object(); 38 private static final Object V1 = new Object(); 39 private static final Object V2 = new Object(); 40 41 private ObservableObjectValueStub<Object> valueModel; 42 private InvalidationListenerMock invalidationListener; 43 private ChangeListenerMock<Object> changeListener; 44 45 @Before 46 public void setUp() { 47 valueModel = new ObservableObjectValueStub<Object>(); 48 invalidationListener = new InvalidationListenerMock(); 49 changeListener = new ChangeListenerMock<Object>(UNDEFINED_VALUE); 50 } 51 52 @Test 53 public void testInitialState() { 54 // no exceptions etc. 55 valueModel.fireValueChangedEvent(); 56 } 57 58 @Test 59 public void testOneInvalidationListener() { 60 // adding one observer 61 valueModel.addListener(invalidationListener); 62 System.gc(); // making sure we did not not overdo weak references 63 valueModel.set(V1); 64 invalidationListener.check(valueModel, 1); 65 66 // remove observer 67 valueModel.removeListener(invalidationListener); 68 valueModel.set(V2); 69 invalidationListener.check(null, 0); 70 71 // remove observer again 72 valueModel.removeListener(invalidationListener); 73 valueModel.set(V1); 74 invalidationListener.check(null, 0); 75 } 76 77 @Test 78 public void testOneChangeListener() { 79 // adding one observer 80 valueModel.addListener(changeListener); 81 System.gc(); // making sure we did not not overdo weak references 82 valueModel.set(V1); 83 changeListener.check(valueModel, null, V1, 1); 84 85 // set same value again 86 valueModel.set(V1); 87 changeListener.check(null, UNDEFINED_VALUE, UNDEFINED_VALUE, 0); 88 89 // set null 90 valueModel.set(null); 91 changeListener.check(valueModel, V1, null, 1); 92 valueModel.set(null); 93 changeListener.check(null, UNDEFINED_VALUE, UNDEFINED_VALUE, 0); 94 95 // remove observer 96 valueModel.removeListener(changeListener); 97 valueModel.set(V2); 98 changeListener.check(null, UNDEFINED_VALUE, UNDEFINED_VALUE, 0); 99 100 // remove observer again 101 valueModel.removeListener(changeListener); 102 valueModel.set(V1); 103 changeListener.check(null, UNDEFINED_VALUE, UNDEFINED_VALUE, 0); 104 } 105 106 @Test 107 public void testTwoObservers() { 108 final InvalidationListenerMock observer2 = new InvalidationListenerMock(); 109 110 // adding two observers 111 valueModel.addListener(invalidationListener); 112 valueModel.addListener(observer2); 113 System.gc(); // making sure we did not not overdo weak references 114 valueModel.fireValueChangedEvent(); 115 invalidationListener.check(valueModel, 1); 116 observer2.check(valueModel, 1); 117 118 // remove first observer 119 invalidationListener.reset(); 120 observer2.reset(); 121 valueModel.removeListener(invalidationListener); 122 valueModel.fireValueChangedEvent(); 123 invalidationListener.check(null, 0); 124 observer2.check(valueModel, 1); 125 126 // remove second observer 127 observer2.reset(); 128 valueModel.removeListener(observer2); 129 valueModel.fireValueChangedEvent(); 130 invalidationListener.check(null, 0); 131 observer2.check(null, 0); 132 133 // remove observers in reverse order 134 observer2.reset(); 135 valueModel.removeListener(observer2); 136 valueModel.removeListener(invalidationListener); 137 valueModel.fireValueChangedEvent(); 138 invalidationListener.check(null, 0); 139 observer2.check(null, 0); 140 } 141 142 @Test 143 public void testConcurrentAdd() { 144 final InvalidationListenerMock observer2 = new AddingListenerMock(); 145 valueModel.addListener(observer2); 146 147 // fire event that adds a second observer 148 // Note: there is no assumption if observer that is being added is notified 149 valueModel.fireValueChangedEvent(); 150 observer2.check(valueModel, 1); 151 152 // fire event again, this time both observers need to be notified 153 invalidationListener.reset(); 154 observer2.reset(); 155 valueModel.fireValueChangedEvent(); 156 invalidationListener.check(valueModel, 1); 157 observer2.check(valueModel, 1); 158 } 159 160 @Test 161 public void testConcurrentRemove() { 162 final InvalidationListenerMock observer2 = new RemovingListenerMock(); 163 valueModel.addListener(observer2); 164 valueModel.addListener(invalidationListener); 165 166 // fire event that removes one observer 167 // Note: there is no assumption if observer that is being removed is notified 168 valueModel.fireValueChangedEvent(); 169 observer2.check(valueModel, 1); 170 171 // fire event again, this time only non-removed observer is notified 172 invalidationListener.reset(); 173 observer2.reset(); 174 valueModel.fireValueChangedEvent(); 175 invalidationListener.check(null, 0); 176 observer2.check(valueModel, 1); 177 } 178 179 @Test(expected=NullPointerException.class) 180 public void testAddingNull_InvalidationListener() { 181 valueModel.addListener((InvalidationListener)null); 182 } 183 184 @Test(expected=NullPointerException.class) 185 public void testAddingNull_ChangeListener() { 186 valueModel.addListener((ChangeListener<Object>)null); 187 } 188 189 @Test(expected=NullPointerException.class) 190 public void testRemovingNull_InvalidationListener() { 191 valueModel.removeListener((InvalidationListener)null); 192 } 193 194 @Test(expected=NullPointerException.class) 195 public void testRemovingNull_ChangeListener() { 196 valueModel.removeListener((ChangeListener<Object>)null); 197 } 198 199 private class AddingListenerMock extends InvalidationListenerMock { 200 @Override public void invalidated(Observable valueModel) { 201 super.invalidated(valueModel); 202 valueModel.addListener(invalidationListener); 203 } 204 } 205 206 private class RemovingListenerMock extends InvalidationListenerMock { 207 @Override public void invalidated(Observable valueModel) { 208 super.invalidated(valueModel); 209 valueModel.removeListener(invalidationListener); 210 } 211 } 212 }