1 /*
   2  * Copyright (c) 2010, 2014, 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.collections;
  27 
  28 import org.junit.Before;
  29 import org.junit.Test;
  30 
  31 import java.util.Arrays;
  32 import java.util.Collection;
  33 import java.util.Collections;
  34 import java.util.List;
  35 import javafx.collections.ListChangeListener;
  36 import javafx.collections.ObservableList;
  37 
  38 import static org.junit.Assert.*;
  39 import org.junit.Ignore;
  40 import org.junit.runner.RunWith;
  41 import org.junit.runners.Parameterized;
  42 
  43 /**
  44  * Tests for ObservableList.
  45  * 
  46  */
  47 @RunWith(Parameterized.class)
  48 public class ObservableListTest  {
  49 
  50     static final List<String> EMPTY = Collections.emptyList();
  51     final Callable<ObservableList<String>> listFactory;
  52     ObservableList<String> list;
  53     MockListObserver<String> mlo;
  54 
  55 
  56     public ObservableListTest(final Callable<ObservableList<String>> listFactory) {
  57         this.listFactory = listFactory;
  58     }
  59 
  60     @Parameterized.Parameters
  61     public static Collection createParameters() {
  62         Object[][] data = new Object[][] {
  63             { TestedObservableLists.ARRAY_LIST },
  64             { TestedObservableLists.LINKED_LIST },
  65             { TestedObservableLists.VETOABLE_LIST },
  66             { TestedObservableLists.CHECKED_OBSERVABLE_ARRAY_LIST },
  67             { TestedObservableLists.SYNCHRONIZED_OBSERVABLE_ARRAY_LIST },
  68             { TestedObservableLists.OBSERVABLE_LIST_PROPERTY }
  69          };
  70         return Arrays.asList(data);
  71     }
  72 
  73     @Before
  74     public void setUp() throws Exception {
  75         list = listFactory.call();
  76         mlo = new MockListObserver<String>();
  77         list.addListener(mlo);
  78 
  79         useListData("one", "two", "three");
  80     }
  81 
  82     /**
  83      * Modifies the list in the fixture to use the strings passed in instead of
  84      * the default strings, and re-creates the observable list and the observer.
  85      * If no strings are passed in, the result is an empty list.
  86      *
  87      * @param strings the strings to use for the list in the fixture
  88      */
  89     void useListData(String... strings) {
  90         list.clear();
  91         list.addAll(Arrays.asList(strings));
  92         mlo.clear();
  93     }
  94 
  95     // ========== observer add/remove tests ==========
  96 
  97     @Test
  98     public void testObserverAddRemove() {
  99         MockListObserver<String> mlo2 = new MockListObserver<String>();
 100         list.addListener(mlo2);
 101         list.removeListener(mlo);
 102         list.add("xyzzy");
 103         mlo.check0();
 104         mlo2.check1AddRemove(list, EMPTY, 3, 4);
 105     }
 106 
 107     @Test
 108     @Ignore
 109     public void testObserverAddTwice() {
 110         list.addListener(mlo); // add it a second time
 111         list.add("plugh");
 112         mlo.check1AddRemove(list, EMPTY, 3, 4);
 113     }
 114 
 115     @Test
 116     public void testObserverRemoveTwice() {
 117         list.removeListener(mlo);
 118         list.removeListener(mlo);
 119         list.add("plugh");
 120         mlo.check0();
 121     }
 122 
 123     // ========== list mutation tests ==========
 124 
 125     @Test
 126     public void testAddToEmpty() {
 127         useListData();
 128         list.add("asdf");
 129         mlo.check1AddRemove(list, EMPTY, 0, 1);
 130     }
 131 
 132     @Test
 133     public void testAddAtEnd() {
 134         list.add("four");
 135         mlo.check1AddRemove(list, EMPTY, 3, 4);
 136     }
 137 
 138     @Test
 139     public void testAddInMiddle() {
 140         list.add(1, "xyz");
 141         mlo.check1AddRemove(list, EMPTY, 1, 2);
 142     }
 143 
 144     @Test
 145     public void testAddSeveralToEmpty() {
 146         useListData();
 147         list.addAll(Arrays.asList("alpha", "bravo", "charlie"));
 148         mlo.check1AddRemove(list, EMPTY, 0, 3);
 149     }
 150 
 151     @Test
 152     public void testAddSeveralAtEnd() {
 153         list.addAll(Arrays.asList("four", "five"));
 154         mlo.check1AddRemove(list, EMPTY, 3, 5);
 155     }
 156 
 157     @Test
 158     public void testAddSeveralInMiddle() {
 159         list.addAll(1, Arrays.asList("a", "b"));
 160         mlo.check1AddRemove(list, EMPTY, 1, 3);
 161     }
 162 
 163     @Test
 164     public void testClearNonempty() {
 165         list.clear();
 166         mlo.check1AddRemove(list, Arrays.asList("one", "two", "three"), 0, 0);
 167     }
 168 
 169     @Test
 170     public void testRemoveByIndex() {
 171         String r = list.remove(1);
 172         mlo.check1AddRemove(list, Arrays.asList("two"), 1, 1);
 173         assertEquals("two", r);
 174     }
 175 
 176     @Test
 177     public void testRemoveObject() {
 178         useListData("one", "x", "two", "three");
 179         boolean b = list.remove("two");
 180         mlo.check1AddRemove(list, Arrays.asList("two"), 2, 2);
 181         assertTrue(b);
 182     }
 183 
 184     @Test
 185     public void testRemoveNull() {
 186         useListData("one", "two", null, "three");
 187         boolean b = list.remove(null);
 188         mlo.check1AddRemove(list, Arrays.asList((String)null), 2, 2);
 189         assertTrue(b);
 190     }
 191 
 192     @Test
 193     public void testRemoveAll() {
 194         useListData("one", "two", "three", "four", "five");
 195         list.removeAll(Arrays.asList("one", "two", "four", "six"));
 196         assertEquals(2, mlo.calls.size());
 197         mlo.checkAddRemove(0, list, Arrays.asList("one", "two"), 0, 0);
 198         mlo.checkAddRemove(1, list, Arrays.asList("four"), 1, 1);
 199     }
 200 
 201     @Test
 202     public void testRemoveAll_1() {
 203         useListData("a", "c", "d", "c");
 204         list.removeAll(Arrays.asList("c"));
 205         assertEquals(2, mlo.calls.size());
 206         mlo.checkAddRemove(0, list, Arrays.asList("c"), 1, 1);
 207         mlo.checkAddRemove(1, list, Arrays.asList("c"), 2, 2);
 208     }
 209 
 210 
 211     @Test
 212     public void testRemoveAll_2() {
 213         useListData("one", "two");
 214         list.removeAll(Arrays.asList("three", "four"));
 215         mlo.check0();
 216     }
 217         
 218     @Test
 219     public void testRemoveAll_3() {
 220         useListData("a", "c", "d", "c");
 221         list.removeAll(Arrays.asList("d"));
 222         assertEquals(1, mlo.calls.size());
 223         mlo.checkAddRemove(0, list, Arrays.asList("d"), 2, 2);
 224     }
 225     
 226     @Test
 227     public void testRemoveAll_4() {
 228         useListData("a", "c", "d", "c");
 229         list.removeAll(Arrays.asList("d", "c"));
 230         assertEquals(1, mlo.calls.size());
 231         mlo.checkAddRemove(0, list, Arrays.asList("c", "d", "c"), 1, 1);
 232     }
 233 
 234     @Test
 235     public void testRetainAll() {
 236         useListData("one", "two", "three", "four", "five");
 237         list.retainAll(Arrays.asList("two", "five", "six"));
 238         assertEquals(2, mlo.calls.size());
 239         mlo.checkAddRemove(0, list, Arrays.asList("one"), 0, 0);
 240         mlo.checkAddRemove(1, list, Arrays.asList("three", "four"), 1, 1);
 241     }
 242 
 243     @Test
 244     public void testRemoveNonexistent() {
 245         useListData("one", "two", "x", "three");
 246         boolean b = list.remove("four");
 247         mlo.check0();
 248         assertFalse(b);
 249     }
 250 
 251     @Test
 252     public void testSet() {
 253         String r = list.set(1, "fnord");
 254         mlo.check1AddRemove(list, Arrays.asList("two"), 1, 2);
 255         assertEquals("two", r);
 256     }
 257 
 258     @Test
 259     public void testObserverCanRemoveObservers() {
 260         final ListChangeListener<String> listObserver = change -> {
 261             change.getList().removeListener(mlo);
 262         };
 263         list.addListener(listObserver);
 264         list.add("x");
 265         mlo.clear();
 266         list.add("y");
 267         mlo.check0();
 268         list.removeListener(listObserver);
 269 
 270 
 271         final StringListChangeListener listener = new StringListChangeListener();
 272         list.addListener(listener);
 273         list.add("z");
 274         assertEquals(listener.counter, 1);
 275         list.add("zz");
 276         assertEquals(listener.counter, 1);
 277     }
 278     
 279     @Test
 280     public void testEqualsAndHashCode() {
 281         final List<String> other = Arrays.asList("one", "two", "three");
 282         assertTrue(list.equals(other));
 283         assertEquals(list.hashCode(), other.hashCode());
 284     }
 285 
 286 
 287     private static class StringListChangeListener implements ListChangeListener<String> {
 288 
 289         private int counter;
 290 
 291         @Override
 292         public void onChanged(final Change<? extends String> change) {
 293             change.getList().removeListener(this);
 294             ++counter;
 295         }
 296     }
 297 }