1 /******************************************************************************* 2 * Copyright (c) 2007, 2018 IBM Corporation and others. 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 * IBM Corporation - initial API and implementation 13 * Matthew Hall - bugs 208858, 221351, 213145, 244098 14 * Simon Scholz <simon.scholz@vogella.com> - Bug 444829 15 ******************************************************************************/ 16 17 package org.eclipse.jface.databinding.conformance; 18 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.Collections; 22 import java.util.List; 23 24 import org.eclipse.core.databinding.observable.IObservablesListener; 25 import org.eclipse.core.databinding.observable.list.IObservableList; 26 import org.eclipse.core.databinding.observable.list.ListDiff; 27 import org.eclipse.jface.databinding.conformance.delegate.IObservableCollectionContractDelegate; 28 import org.eclipse.jface.databinding.conformance.util.ChangeEventTracker; 29 import org.eclipse.jface.databinding.conformance.util.ListChangeEventTracker; 30 import org.eclipse.jface.databinding.conformance.util.SuiteBuilder; 31 import org.junit.Assert; 32 33 import junit.framework.Test; 34 35 /** 36 * Mutability tests for IObservableList. 37 * 38 * <p> 39 * This class is experimental and can change at any time. It is recommended to 40 * not subclass or assume the test names will not change. The only API that is 41 * guaranteed to not change are the constructors. The tests will remain public 42 * and not final in order to allow for consumers to turn off a test if needed by 43 * subclassing. 44 * </p> 45 * 46 * @since 3.2 47 */ 48 public class MutableObservableListContractTest extends 49 MutableObservableCollectionContractTest { 50 private IObservableCollectionContractDelegate delegate; 51 52 private IObservableList list; 53 54 /** 55 * @param delegate 56 */ MutableObservableListContractTest( IObservableCollectionContractDelegate delegate)57 public MutableObservableListContractTest( 58 IObservableCollectionContractDelegate delegate) { 59 super(delegate); 60 this.delegate = delegate; 61 } 62 MutableObservableListContractTest(String testName, IObservableCollectionContractDelegate delegate)63 public MutableObservableListContractTest(String testName, 64 IObservableCollectionContractDelegate delegate) { 65 super(testName, delegate); 66 this.delegate = delegate; 67 } 68 69 @Override setUp()70 protected void setUp() throws Exception { 71 super.setUp(); 72 list = (IObservableList) getObservable(); 73 } 74 testAdd_ListChangeEvent()75 public void testAdd_ListChangeEvent() throws Exception { 76 final Object element = delegate.createElement(list); 77 assertListChangeEventFired(() -> list.add(element), "List.add(Object)", list, 78 Collections.singletonList(element)); 79 } 80 testAdd_ListDiffEntry()81 public void testAdd_ListDiffEntry() throws Exception { 82 Object element0 = delegate.createElement(list); 83 list.add(element0); 84 final Object element1 = delegate.createElement(list); 85 86 assertListChangeEventFired(() -> list.add(element1), "List.add(Object)", list, 87 Arrays.asList(new Object[] { element0, element1 })); 88 } 89 testAddAtIndex_ChangeEvent()90 public void testAddAtIndex_ChangeEvent() throws Exception { 91 assertChangeEventFired(() -> list.add(0, delegate.createElement(list)), "List.add(int, Object)", list); 92 } 93 testAddAtIndex_ListChangeEvent()94 public void testAddAtIndex_ListChangeEvent() throws Exception { 95 final Object element = delegate.createElement(list); 96 assertListChangeEventFired(() -> list.add(0, element), "List.add(int, Object)", list, 97 Collections.singletonList(element)); 98 } 99 testAddAtIndex_ChangeEventFiredAfterElementIsAdded()100 public void testAddAtIndex_ChangeEventFiredAfterElementIsAdded() 101 throws Exception { 102 final Object element = delegate.createElement(list); 103 104 assertContainsDuringChangeEvent(() -> list.add(0, element), "List.add(int, Collection)", list, element); 105 } 106 testAddAtIndex_ListDiffEntry()107 public void testAddAtIndex_ListDiffEntry() throws Exception { 108 Object element0 = delegate.createElement(list); 109 list.add(element0); 110 final Object element1 = delegate.createElement(list); 111 112 assertListChangeEventFired(() -> list.add(1, element1), "List.add(int, Object)", list, 113 Arrays.asList(new Object[] { element0, element1 })); 114 } 115 testAddAll_ListChangeEvent()116 public void testAddAll_ListChangeEvent() throws Exception { 117 final Object element = delegate.createElement(list); 118 assertListChangeEventFired(() -> list.addAll(Collections.singletonList(element)), "List.addAll(Collection", 119 list, Collections.singletonList(element)); 120 } 121 testAddAll_ListDiffEntry()122 public void testAddAll_ListDiffEntry() throws Exception { 123 final Object element = delegate.createElement(list); 124 125 assertListChangeEventFired(() -> list.addAll(Collections.singletonList(element)), "List.addAll(Collection)", 126 list, Collections.singletonList(element)); 127 } 128 testAddAll_ListDiffEntry2()129 public void testAddAll_ListDiffEntry2() throws Exception { 130 final Object element0 = delegate.createElement(list); 131 list.add(element0); 132 final Object element1 = delegate.createElement(list); 133 134 assertListChangeEventFired(() -> list.addAll(Collections.singletonList(element1)), "List.addAll(Collection)", 135 list, 136 Arrays.asList(new Object[] { element0, element1 })); 137 } 138 testAddAllAtIndex_ChangeEvent()139 public void testAddAllAtIndex_ChangeEvent() throws Exception { 140 assertChangeEventFired(() -> list.addAll(0, Arrays.asList(new Object[] { delegate.createElement(list) })), 141 "List.addAll(int, Collection)", list); 142 } 143 testAddAllAtIndex_ListChangeEvent()144 public void testAddAllAtIndex_ListChangeEvent() throws Exception { 145 final Object element = delegate.createElement(list); 146 assertListChangeEventFired(() -> list.addAll(0, Collections.singletonList(element)), 147 "List.addAll(int, Collection)", list, 148 Collections.singletonList(element)); 149 } 150 testAddAllAtIndex_ChangeEventFiredAfterElementIsAdded()151 public void testAddAllAtIndex_ChangeEventFiredAfterElementIsAdded() 152 throws Exception { 153 final Object element = delegate.createElement(list); 154 155 assertContainsDuringChangeEvent(() -> list.addAll(0, Arrays.asList(new Object[] { element })), 156 "List.addAll(int, Collection)", list, element); 157 } 158 testAddAllAtIndex_ListDiffEntry()159 public void testAddAllAtIndex_ListDiffEntry() throws Exception { 160 Object element0 = delegate.createElement(list); 161 list.add(element0); 162 final Object element1 = delegate.createElement(list); 163 164 assertListChangeEventFired(() -> list.addAll(1, Collections.singletonList(element1)), 165 "List.addAll(int, Collection)", list, 166 Arrays.asList(new Object[] { element0, element1 })); 167 } 168 testSet_ChangeEvent()169 public void testSet_ChangeEvent() throws Exception { 170 list.add(delegate.createElement(list)); 171 172 assertChangeEventFired(() -> list.set(0, delegate.createElement(list)), "List.set(int, Object)", list); 173 } 174 testSet_ListChangeEvent()175 public void testSet_ListChangeEvent() throws Exception { 176 final Object element0 = delegate.createElement(list); 177 list.add(element0); 178 final Object element1 = delegate.createElement(list); 179 180 assertListChangeEventFired(() -> assertSame(element0, list.set(0, element1)), "List.set(int, Object)", list, 181 Arrays.asList(new Object[] { element1 })); 182 } 183 testSet_ChangeEventFiredAfterElementIsSet()184 public void testSet_ChangeEventFiredAfterElementIsSet() throws Exception { 185 final Object element1 = delegate.createElement(list); 186 list.add(element1); 187 final Object element2 = delegate.createElement(list); 188 189 assertContainsDuringChangeEvent(() -> assertSame(element1, list.set(0, element2)), "List.set(int, Object)", 190 list, element2); 191 } 192 testSet_ListChangeEvent2()193 public void testSet_ListChangeEvent2() throws Exception { 194 Object element0 = delegate.createElement(list); 195 list.add(element0); 196 Object oldElement1 = delegate.createElement(list); 197 list.add(oldElement1); 198 final Object newElement1 = delegate.createElement(list); 199 200 assertListChangeEventFired(() -> list.set(1, newElement1), "List.set(int, Object)", list, 201 Arrays.asList(new Object[] { element0, newElement1 })); 202 } 203 testMove_ChangeEvent()204 public void testMove_ChangeEvent() throws Exception { 205 list.add(delegate.createElement(list)); 206 list.add(delegate.createElement(list)); 207 208 assertChangeEventFired(() -> list.move(0, 1), "IObservableList.move(int, int)", list); 209 } 210 testMove_NoChangeEventAtSameIndex()211 public void testMove_NoChangeEventAtSameIndex() throws Exception { 212 Object element = delegate.createElement(list); 213 list.add(element); 214 215 ListChangeEventTracker tracker = ListChangeEventTracker.observe(list); 216 217 final Object movedElement = list.move(0, 0); 218 219 assertEquals( 220 formatFail("IObservableList.move(int,int) should return the moved element"), 221 element, movedElement); 222 assertEquals( 223 formatFail("IObservableLIst.move(int,int) should not fire a change event" 224 + "when the old and new indices are the same"), 0, 225 tracker.count); 226 } 227 testMove_ListChangeEvent()228 public void testMove_ListChangeEvent() throws Exception { 229 final Object element0 = delegate.createElement(list); 230 list.add(element0); 231 final Object element1 = delegate.createElement(list); 232 list.add(element1); 233 234 assertListChangeEventFired(() -> assertSame(element0, list.move(0, 1)), "IObservableList.move(int, int)", list, 235 Arrays.asList(new Object[] { element1, element0 })); 236 } 237 testMove_ChangeEventFiredAfterElementIsMoved()238 public void testMove_ChangeEventFiredAfterElementIsMoved() throws Exception { 239 Object element0 = delegate.createElement(list); 240 Object element1 = delegate.createElement(list); 241 list.add(element0); 242 list.add(element1); 243 244 assertSame(element0, list.get(0)); 245 assertSame(element1, list.get(1)); 246 247 list.move(0, 1); 248 249 assertSame(element1, list.get(0)); 250 assertSame(element0, list.get(1)); 251 } 252 testMove_ListChangeEvent2()253 public void testMove_ListChangeEvent2() { 254 Object element0 = delegate.createElement(list); 255 list.add(element0); 256 Object element1 = delegate.createElement(list); 257 list.add(element1); 258 259 assertListChangeEventFired(() -> list.move(0, 1), "IObservableList.move(int, int)", list, 260 Arrays.asList(new Object[] { element1, element0 })); 261 } 262 testRemove_ListChangeEvent()263 public void testRemove_ListChangeEvent() throws Exception { 264 final Object element = delegate.createElement(list); 265 list.add(element); 266 267 assertListChangeEventFired(() -> list.remove(element), "List.remove(Object)", list, Collections.EMPTY_LIST); 268 } 269 testRemove_ListDiffEntry()270 public void testRemove_ListDiffEntry() throws Exception { 271 final Object element0 = delegate.createElement(list); 272 list.add(element0); 273 final Object element1 = delegate.createElement(list); 274 list.add(element1); 275 276 assertListChangeEventFired(() -> list.remove(element1), "List.remove(Object)", list, 277 Collections.singletonList(element0)); 278 } 279 testRemoveAtIndex_ChangeEvent()280 public void testRemoveAtIndex_ChangeEvent() throws Exception { 281 list.add(delegate.createElement(list)); 282 283 assertChangeEventFired(() -> list.remove(0), "List.remove(int)", list); 284 } 285 testRemoveAtIndex_ListChangeEvent()286 public void testRemoveAtIndex_ListChangeEvent() throws Exception { 287 list.add(delegate.createElement(list)); 288 289 assertListChangeEventFired(() -> list.remove(0), "List.remove(int)", list, Collections.EMPTY_LIST); 290 } 291 testRemoveAtIndex_ChangeEventFiredAfterElementIsRemoved()292 public void testRemoveAtIndex_ChangeEventFiredAfterElementIsRemoved() 293 throws Exception { 294 final Object element = delegate.createElement(list); 295 list.add(element); 296 297 assertDoesNotContainDuringChangeEvent(() -> list.remove(0), "List.remove(int)", list, element); 298 } 299 testRemoveAtIndex_ListDiffEntry()300 public void testRemoveAtIndex_ListDiffEntry() throws Exception { 301 Object element0 = delegate.createElement(list); 302 list.add(element0); 303 Object element1 = delegate.createElement(list); 304 list.add(element1); 305 306 assertListChangeEventFired(() -> list.remove(1), "List.remove(int)", list, Collections.singletonList(element0)); 307 } 308 testRemoveAll_ListChangeEvent()309 public void testRemoveAll_ListChangeEvent() throws Exception { 310 final Object element = delegate.createElement(list); 311 list.add(element); 312 313 assertListChangeEventFired(() -> list.removeAll(Collections.singletonList(element)), 314 "List.removeAll(Collection)", list, Collections.EMPTY_LIST); 315 } 316 testRemoveAll_ListDiffEntry()317 public void testRemoveAll_ListDiffEntry() throws Exception { 318 final Object element = delegate.createElement(list); 319 list.add(element); 320 321 assertListChangeEventFired(() -> list.removeAll(Collections.singletonList(element)), 322 "List.removeAll(Collection)", list, Collections.EMPTY_LIST); 323 } 324 testRemoveAll_ListDiffEntry2()325 public void testRemoveAll_ListDiffEntry2() throws Exception { 326 Object element0 = delegate.createElement(list); 327 list.add(element0); 328 final Object element1 = delegate.createElement(list); 329 list.add(element1); 330 331 assertListChangeEventFired(() -> list.removeAll(Arrays.asList(new Object[] { element1 })), 332 "List.removeAll(Collection)", list, 333 Collections.singletonList(element0)); 334 } 335 testRetainAll_ListChangeEvent()336 public void testRetainAll_ListChangeEvent() throws Exception { 337 final Object element0 = delegate.createElement(list); 338 list.add(element0); 339 list.add(delegate.createElement(list)); 340 341 assertListChangeEventFired(() -> list.retainAll(Arrays.asList(new Object[] { element0 })), 342 "List.retainAll(Collection", list, 343 Collections.singletonList(element0)); 344 } 345 testRetainAll_ListDiffEntry()346 public void testRetainAll_ListDiffEntry() throws Exception { 347 final Object element = delegate.createElement(list); 348 list.add(element); 349 list.add(delegate.createElement(list)); 350 351 assertListChangeEventFired(() -> list.retainAll(Arrays.asList(new Object[] { element })), 352 "List.retainAll(Collection)", list, 353 Collections.singletonList(element)); 354 } 355 testClear_ListChangeEvent()356 public void testClear_ListChangeEvent() throws Exception { 357 list.add(delegate.createElement(list)); 358 359 assertListChangeEventFired(() -> list.clear(), "List.clear()", list, Collections.EMPTY_LIST); 360 } 361 testClear_ListDiffEntry()362 public void testClear_ListDiffEntry() throws Exception { 363 list.add(delegate.createElement(list)); 364 365 assertListChangeEventFired(() -> list.clear(), "List.clear()", list, Collections.EMPTY_LIST); 366 } 367 testClear_ClearsList()368 public void testClear_ClearsList() { 369 Object element = delegate.createElement(list); 370 list.add(element); 371 Assert.assertEquals(Collections.singletonList(element), list); 372 list.clear(); 373 Assert.assertEquals(Collections.EMPTY_LIST, list); 374 } 375 assertListChangeEventFired(Runnable runnable, String methodName, IObservableList list, List newList)376 private void assertListChangeEventFired(Runnable runnable, 377 String methodName, IObservableList list, List newList) { 378 List oldList = new ArrayList(list); 379 380 List<IObservablesListener> queue = new ArrayList<>(); 381 ListChangeEventTracker listListener = new ListChangeEventTracker(queue); 382 ChangeEventTracker changeListener = new ChangeEventTracker(queue); 383 384 list.addListChangeListener(listListener); 385 list.addChangeListener(changeListener); 386 387 runnable.run(); 388 389 assertEquals(formatFail(methodName 390 + " should fire one ListChangeEvent."), 1, listListener.count); 391 assertEquals(formatFail(methodName 392 + "'s change event observable should be the created List."), 393 list, listListener.event.getObservable()); 394 395 assertEquals( 396 formatFail("Two notifications should have been received."), 2, 397 queue.size()); 398 assertEquals("ChangeEvent of " + methodName 399 + " should have fired before the ListChangeEvent.", 400 changeListener, queue.get(0)); 401 assertEquals("ListChangeEvent of " + methodName 402 + " should have fired after the ChangeEvent.", listListener, 403 queue.get(1)); 404 405 assertEquals(formatFail(methodName 406 + " did not leave observable list with the expected contents"), 407 newList, list); 408 409 ListDiff diff = listListener.event.diff; 410 diff.applyTo(oldList); 411 assertEquals( 412 formatFail(methodName 413 + " fired a diff which does not represent the expected list change"), 414 newList, oldList); 415 416 } 417 suite(IObservableCollectionContractDelegate delegate)418 public static Test suite(IObservableCollectionContractDelegate delegate) { 419 return new SuiteBuilder() 420 .addObservableContractTest( 421 MutableObservableListContractTest.class, delegate) 422 .addObservableContractTest(ObservableListContractTest.class, 423 delegate).build(); 424 } 425 } 426