1 /******************************************************************************* 2 * Copyright (c) 2006, 2018 Brad Reynolds. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Brad Reynolds - initial API and implementation 13 * Brad Reynolds - bug 116920 14 * Matthew Hall - bugs 208332, 213145, 255734 15 * Ovidio Mallo - bug 247741 16 ******************************************************************************/ 17 18 package org.eclipse.core.tests.databinding.observable; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 25 import org.eclipse.core.databinding.observable.AbstractObservable; 26 import org.eclipse.core.databinding.observable.IDisposeListener; 27 import org.eclipse.core.databinding.observable.IObservable; 28 import org.eclipse.core.databinding.observable.IStaleListener; 29 import org.eclipse.core.databinding.observable.ObservableTracker; 30 import org.eclipse.core.databinding.observable.Realm; 31 import org.eclipse.jface.databinding.conformance.ObservableContractTest; 32 import org.eclipse.jface.databinding.conformance.ObservableStaleContractTest; 33 import org.eclipse.jface.databinding.conformance.delegate.AbstractObservableContractDelegate; 34 import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; 35 import org.eclipse.jface.databinding.conformance.util.CurrentRealm; 36 import org.eclipse.jface.databinding.conformance.util.RealmTester; 37 import org.eclipse.jface.databinding.conformance.util.StaleEventTracker; 38 import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase; 39 import org.junit.Before; 40 import org.junit.Test; 41 42 import junit.framework.TestSuite; 43 44 /** 45 * Tests for AbstractObservable. 46 * 47 * @since 1.1 48 */ 49 public class AbstractObservableTest extends AbstractDefaultRealmTestCase { 50 private ObservableStub observable; 51 52 @Override 53 @Before setUp()54 public void setUp() throws Exception { 55 super.setUp(); 56 observable = new ObservableStub(Realm.getDefault()); 57 } 58 59 @Test testStaleListener()60 public void testStaleListener() throws Exception { 61 assertFalse(observable.hasListeners()); 62 63 StaleEventTracker listener1 = new StaleEventTracker(); 64 65 assertFalse(observable.firstListenerAdded); 66 observable.addStaleListener(listener1); 67 assertTrue(observable.firstListenerAdded); 68 observable.firstListenerAdded = false; // reset 69 70 assertTrue(observable.hasListeners()); 71 assertEquals(0, listener1.count); 72 73 observable.fireStale(); 74 75 assertEquals(1, listener1.count); 76 assertSame(observable, listener1.event.getObservable()); 77 78 // Add a second stale listener as 1 vs. 2 listener code is different. 79 StaleEventTracker listener2 = new StaleEventTracker(); 80 assertEquals(0, listener2.count); 81 observable.addStaleListener(listener2); 82 observable.fireStale(); 83 84 assertEquals(2, listener1.count); 85 assertEquals(1, listener2.count); 86 87 // Add a third stale listener as 2 vs. 3 or greater code is different. 88 StaleEventTracker listener3 = new StaleEventTracker(); 89 observable.addStaleListener(listener3); 90 assertEquals(0, listener3.count); 91 92 observable.fireStale(); 93 94 assertEquals(3, listener1.count); 95 assertEquals(2, listener2.count); 96 assertEquals(1, listener3.count); 97 98 assertFalse(observable.lastListenerRemoved); 99 observable.removeStaleListener(listener1); 100 observable.removeStaleListener(listener2); 101 observable.removeStaleListener(listener3); 102 assertTrue(observable.lastListenerRemoved); 103 104 assertFalse(observable.hasListeners()); 105 } 106 107 @Test testChangeListener()108 public void testChangeListener() throws Exception { 109 assertFalse(observable.hasListeners()); 110 111 ChangeEventTracker listener1 = new ChangeEventTracker(); 112 113 assertFalse(observable.firstListenerAdded); 114 observable.addChangeListener(listener1); 115 assertTrue(observable.firstListenerAdded); 116 observable.firstListenerAdded = false; 117 118 assertTrue(observable.hasListeners()); 119 assertEquals(0, listener1.count); 120 121 observable.fireChange(); 122 123 assertEquals(1, listener1.count); 124 assertSame(observable, listener1.event.getSource()); 125 126 // Add a second listener as the 1 vs. 2 listener code is different. 127 ChangeEventTracker listener2 = new ChangeEventTracker(); 128 observable.addChangeListener(listener2); 129 assertEquals(0, listener2.count); 130 131 observable.fireChange(); 132 assertEquals(2, listener1.count); 133 assertEquals(1, listener2.count); 134 135 // Add a third listener as the 2 vs. 3 or greater code is different. 136 ChangeEventTracker listener3 = new ChangeEventTracker(); 137 observable.addChangeListener(listener3); 138 assertEquals(0, listener3.count); 139 140 observable.fireChange(); 141 142 assertEquals(3, listener1.count); 143 assertEquals(2, listener2.count); 144 assertEquals(1, listener3.count); 145 146 assertFalse(observable.lastListenerRemoved); 147 observable.removeChangeListener(listener1); 148 observable.removeChangeListener(listener2); 149 observable.removeChangeListener(listener3); 150 assertTrue(observable.lastListenerRemoved); 151 152 assertFalse(observable.hasListeners()); 153 } 154 155 @Test testHasListenersWithChangeAndStaleListeners()156 public void testHasListenersWithChangeAndStaleListeners() throws Exception { 157 ChangeEventTracker changeListener = new ChangeEventTracker(); 158 StaleEventTracker staleListener = new StaleEventTracker(); 159 160 assertFalse(observable.hasListeners()); 161 assertFalse(observable.firstListenerAdded); 162 assertFalse(observable.lastListenerRemoved); 163 164 observable.addChangeListener(changeListener); 165 assertTrue(observable.hasListeners()); 166 assertTrue(observable.firstListenerAdded); 167 assertFalse(observable.lastListenerRemoved); 168 169 // reset 170 observable.firstListenerAdded = false; 171 observable.lastListenerRemoved = false; 172 173 observable.addStaleListener(staleListener); 174 assertTrue(observable.hasListeners()); 175 assertFalse(observable.firstListenerAdded); 176 assertFalse(observable.lastListenerRemoved); 177 178 observable.removeChangeListener(changeListener); 179 assertTrue(observable.hasListeners()); 180 assertFalse(observable.firstListenerAdded); 181 assertFalse(observable.lastListenerRemoved); 182 183 observable.removeStaleListener(staleListener); 184 assertFalse(observable.hasListeners()); 185 assertFalse(observable.firstListenerAdded); 186 assertTrue(observable.lastListenerRemoved); 187 } 188 189 @Test testFireStaleRealmChecks()190 public void testFireStaleRealmChecks() throws Exception { 191 RealmTester.setDefault(new CurrentRealm(true)); 192 193 RealmTester.exerciseCurrent(() -> { 194 observable = new ObservableStub(); 195 observable.fireStale(); 196 }); 197 } 198 199 @Test testFireChangeRealmChecks()200 public void testFireChangeRealmChecks() throws Exception { 201 RealmTester.setDefault(new CurrentRealm(true)); 202 203 RealmTester.exerciseCurrent(() -> { 204 observable = new ObservableStub(); 205 observable.fireChange(); 206 }); 207 } 208 209 @Test testAddDisposeListener_HasListenersFalse()210 public void testAddDisposeListener_HasListenersFalse() { 211 IDisposeListener disposeListener = staleEvent -> { 212 }; 213 IStaleListener staleListener = staleEvent -> { 214 }; 215 216 assertFalse(observable.hasListeners()); 217 218 observable.addDisposeListener(disposeListener); 219 assertFalse(observable.hasListeners()); 220 assertFalse(observable.firstListenerAdded); 221 assertFalse(observable.lastListenerRemoved); 222 223 observable.addStaleListener(staleListener); 224 assertTrue(observable.hasListeners()); 225 assertTrue(observable.firstListenerAdded); 226 assertFalse(observable.lastListenerRemoved); 227 228 observable.removeDisposeListener(disposeListener); 229 assertTrue(observable.hasListeners()); 230 assertTrue(observable.firstListenerAdded); 231 assertFalse(observable.lastListenerRemoved); 232 233 observable.removeStaleListener(staleListener); 234 assertFalse(observable.hasListeners()); 235 assertTrue(observable.firstListenerAdded); 236 assertTrue(observable.lastListenerRemoved); 237 } 238 addConformanceTest(TestSuite suite)239 public static void addConformanceTest(TestSuite suite) { 240 Delegate delegate = new Delegate(); 241 suite.addTest(ObservableContractTest.suite(delegate)); 242 suite.addTest(ObservableStaleContractTest.suite(delegate)); 243 } 244 245 /* package */static class Delegate extends 246 AbstractObservableContractDelegate { 247 248 @Override change(IObservable observable)249 public void change(IObservable observable) { 250 ((ObservableStub) observable).fireChange(); 251 } 252 253 @Override setStale(IObservable observable, boolean stale)254 public void setStale(IObservable observable, boolean stale) { 255 ((ObservableStub) observable).setStale(stale); 256 } 257 258 @Override createObservable(Realm realm)259 public IObservable createObservable(Realm realm) { 260 return new ObservableStub(realm); 261 } 262 } 263 264 private static class ObservableStub extends AbstractObservable { 265 private boolean stale; 266 ObservableStub()267 public ObservableStub() { 268 this(Realm.getDefault()); 269 } 270 271 /** 272 * @param realm 273 */ ObservableStub(Realm realm)274 public ObservableStub(Realm realm) { 275 super(realm); 276 } 277 278 private boolean firstListenerAdded; 279 280 private boolean lastListenerRemoved; 281 282 @Override fireStale()283 protected void fireStale() { 284 super.fireStale(); 285 } 286 287 @Override fireChange()288 protected void fireChange() { 289 super.fireChange(); 290 } 291 292 @Override isStale()293 public boolean isStale() { 294 getterCalled(); 295 return stale; 296 } 297 getterCalled()298 private void getterCalled() { 299 ObservableTracker.getterCalled(this); 300 } 301 setStale(boolean stale)302 public void setStale(boolean stale) { 303 boolean old = this.stale; 304 this.stale = stale; 305 306 if (stale && !old) { 307 fireStale(); 308 } 309 } 310 311 @Override hasListeners()312 protected boolean hasListeners() { 313 return super.hasListeners(); 314 } 315 316 @Override firstListenerAdded()317 protected void firstListenerAdded() { 318 firstListenerAdded = true; 319 } 320 321 @Override lastListenerRemoved()322 protected void lastListenerRemoved() { 323 lastListenerRemoved = true; 324 } 325 } 326 } 327