--- old/modules/base/src/test/java/javafx/beans/property/ListPropertyBaseTest.java 2015-08-31 10:23:24.745217504 -0400 +++ /dev/null 2015-08-30 16:31:40.093001923 -0400 @@ -1,825 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package javafx.beans.property; - -import java.util.Arrays; -import javafx.beans.InvalidationListenerMock; -import javafx.beans.value.ChangeListenerMock; -import javafx.beans.value.ObservableObjectValueStub; -import javafx.collections.FXCollections; -import javafx.collections.MockListObserver; -import javafx.collections.ObservableList; -import org.junit.Before; -import org.junit.Test; - -import java.util.Collections; -import java.util.List; -import javafx.beans.Observable; -import javafx.collections.Person; - -import static org.junit.Assert.*; - -public class ListPropertyBaseTest { - - private static final Object NO_BEAN = null; - private static final String NO_NAME_1 = null; - private static final String NO_NAME_2 = ""; - private static final ObservableList UNDEFINED = FXCollections.observableArrayList(); - private static final ObservableList VALUE_1a = FXCollections.observableArrayList(); - private static final ObservableList VALUE_1b = FXCollections.observableArrayList(new Object()); - private static final ObservableList VALUE_2a = FXCollections.observableArrayList(new Object(), new Object()); - private static final ObservableList VALUE_2b = FXCollections.observableArrayList(new Object(), new Object(), new Object()); - private static final List EMPTY_LIST = Collections.emptyList(); - private ListPropertyMock property; - private InvalidationListenerMock invalidationListener; - private ChangeListenerMock> changeListener; - private MockListObserver listChangeListener; - - @Before - public void setUp() throws Exception { - property = new ListPropertyMock(); - invalidationListener = new InvalidationListenerMock(); - changeListener = new ChangeListenerMock>(UNDEFINED); - listChangeListener = new MockListObserver(); - } - - private void attachInvalidationListener() { - property.addListener(invalidationListener); - property.get(); - invalidationListener.reset(); - } - - private void attachChangeListener() { - property.addListener(changeListener); - property.get(); - changeListener.reset(); - } - - private void attachListChangeListener() { - property.addListener(listChangeListener); - property.get(); - listChangeListener.clear(); - } - - @Test - public void testConstructor() { - final ListProperty p1 = new SimpleListProperty(); - assertEquals(null, p1.get()); - assertEquals(null, p1.getValue()); - assertFalse(property.isBound()); - - final ListProperty p2 = new SimpleListProperty(VALUE_1b); - assertEquals(VALUE_1b, p2.get()); - assertEquals(VALUE_1b, p2.getValue()); - assertFalse(property.isBound()); - } - - @Test - public void testEmptyProperty() { - assertEquals("empty", property.emptyProperty().getName()); - assertEquals(property, property.emptyProperty().getBean()); - assertTrue(property.emptyProperty().get()); - - property.set(VALUE_2a); - assertFalse(property.emptyProperty().get()); - property.set(VALUE_1a); - assertTrue(property.emptyProperty().get()); - } - - @Test - public void testSizeProperty() { - assertEquals("size", property.sizeProperty().getName()); - assertEquals(property, property.sizeProperty().getBean()); - assertEquals(0, property.sizeProperty().get()); - - property.set(VALUE_2a); - assertEquals(2, property.sizeProperty().get()); - property.set(VALUE_1a); - assertEquals(0, property.sizeProperty().get()); - } - - @Test - public void testInvalidationListener() { - attachInvalidationListener(); - property.set(VALUE_2a); - invalidationListener.check(property, 1); - property.removeListener(invalidationListener); - invalidationListener.reset(); - property.set(VALUE_1a); - invalidationListener.check(null, 0); - } - - @Test - public void testChangeListener() { - attachChangeListener(); - property.set(VALUE_2a); - changeListener.check(property, null, VALUE_2a, 1); - property.removeListener(changeListener); - changeListener.reset(); - property.set(VALUE_1a); - changeListener.check(null, UNDEFINED, UNDEFINED, 0); - } - - @Test - public void testListChangeListener() { - attachListChangeListener(); - property.set(VALUE_2a); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); - property.removeListener(listChangeListener); - listChangeListener.clear(); - property.set(VALUE_1a); - listChangeListener.check0(); - } - - @Test - public void testSourceList_Invalidation() { - final ObservableList source1 = FXCollections.observableArrayList(); - final ObservableList source2 = FXCollections.observableArrayList(); - final Object value1 = new Object(); - final Object value2 = new Object(); - - // constructor - property = new ListPropertyBaseTest.ListPropertyMock(source1); - property.reset(); - attachInvalidationListener(); - - // add element - source1.add(value1); - assertEquals(value1, property.get(0)); - property.check(1); - invalidationListener.check(property, 1); - - // replace element - source1.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - invalidationListener.check(property, 1); - - // remove element - source1.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - invalidationListener.check(property, 1); - - // set - property.set(source2); - property.get(); - property.reset(); - invalidationListener.reset(); - - // add element - source2.add(0, value1); - assertEquals(value1, property.get(0)); - property.check(1); - invalidationListener.check(property, 1); - - // replace element - source2.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - invalidationListener.check(property, 1); - - // remove element - source2.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - invalidationListener.check(property, 1); - } - - @Test - public void testSourceList_Change() { - final ObservableList source1 = FXCollections.observableArrayList(); - final ObservableList source2 = FXCollections.observableArrayList(); - final Object value1 = new Object(); - final Object value2 = new Object(); - - // constructor - property = new ListPropertyBaseTest.ListPropertyMock(source1); - property.reset(); - attachChangeListener(); - - // add element - source1.add(value1); - assertEquals(value1, property.get(0)); - property.check(1); - changeListener.check(property, source1, source1, 1); - - // replace element - source1.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - changeListener.check(property, source1, source1, 1); - - // remove element - source1.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - changeListener.check(property, source1, source1, 1); - - // set - property.set(source2); - property.get(); - property.reset(); - changeListener.reset(); - - // add element - source2.add(0, value1); - assertEquals(value1, property.get(0)); - property.check(1); - changeListener.check(property, source2, source2, 1); - - // replace element - source2.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - changeListener.check(property, source2, source2, 1); - - // remove element - source2.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - changeListener.check(property, source2, source2, 1); - } - - @Test - public void testSourceList_ListChange() { - final ObservableList source1 = FXCollections.observableArrayList(); - final ObservableList source2 = FXCollections.observableArrayList(); - final Object value1 = new Object(); - final Object value2 = new Object(); - - // constructor - property = new ListPropertyBaseTest.ListPropertyMock(source1); - property.reset(); - attachListChangeListener(); - - // add element - source1.add(value1); - assertEquals(value1, property.get(0)); - property.check(1); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 1); - listChangeListener.clear(); - - // replace element - source1.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - listChangeListener.check1AddRemove(property, Arrays.asList(value1), 0, 1); - listChangeListener.clear(); - - // remove element - source1.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - listChangeListener.check1AddRemove(property, Arrays.asList(value2), 0, 0); - listChangeListener.clear(); - - // set - property.set(source2); - property.get(); - property.reset(); - listChangeListener.clear(); - - // add element - source2.add(0, value1); - assertEquals(value1, property.get(0)); - property.check(1); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 1); - listChangeListener.clear(); - - // replace element - source2.set(0, value2); - assertEquals(value2, property.get(0)); - property.check(1); - listChangeListener.check1AddRemove(property, Arrays.asList(value1), 0, 1); - listChangeListener.clear(); - - // remove element - source2.remove(0); - assertTrue(property.isEmpty()); - property.check(1); - listChangeListener.check1AddRemove(property, Arrays.asList(value2), 0, 0); - listChangeListener.clear(); - } - - @Test - public void testSet_Invalidation() { - attachInvalidationListener(); - - // set value once - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - invalidationListener.check(property, 1); - - // set same value again - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - invalidationListener.check(null, 0); - - // set value twice without reading - property.set(VALUE_1a); - property.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(1); - invalidationListener.check(property, 1); - } - - @Test - public void testSet_Change() { - attachChangeListener(); - - // set value once - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - changeListener.check(property, null, VALUE_2a, 1); - - // set same value again - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - changeListener.check(null, UNDEFINED, UNDEFINED, 0); - - // set value twice without reading - property.set(VALUE_1a); - property.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - changeListener.check(property, VALUE_1a, VALUE_1b, 2); - } - - @Test - public void testSet_ListChange() { - attachListChangeListener(); - - // set value once - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); - - // set same value again - listChangeListener.clear(); - property.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - listChangeListener.check0(); - - // set value twice without reading - property.set(VALUE_1a); - listChangeListener.clear(); - property.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); - } - - @Test - public void testSetValue_Invalidation() { - attachInvalidationListener(); - - // set value once - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - invalidationListener.check(property, 1); - - // set same value again - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - invalidationListener.check(null, 0); - - // set value twice without reading - property.setValue(VALUE_1a); - property.setValue(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(1); - invalidationListener.check(property, 1); - } - - @Test - public void testSetValue_Change() { - attachChangeListener(); - - // set value once - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - changeListener.check(property, null, VALUE_2a, 1); - - // set same value again - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - changeListener.check(null, UNDEFINED, UNDEFINED, 0); - - // set value twice without reading - property.setValue(VALUE_1a); - property.setValue(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - changeListener.check(property, VALUE_1a, VALUE_1b, 2); - } - - @Test - public void testSetValue_ListChange() { - attachListChangeListener(); - - // set value once - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); - - // set same value again - listChangeListener.clear(); - property.setValue(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(0); - listChangeListener.check0(); - - // set value twice without reading - property.setValue(VALUE_1a); - listChangeListener.clear(); - property.setValue(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); - } - - @Test(expected = RuntimeException.class) - public void testSetBoundValue() { - final ListProperty v = new SimpleListProperty(VALUE_1a); - property.bind(v); - property.set(VALUE_1a); - } - - @Test - public void testBind_Invalidation() { - attachInvalidationListener(); - final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); - - property.bind(v); - assertEquals(VALUE_1a, property.get()); - assertTrue(property.isBound()); - property.check(1); - invalidationListener.check(property, 1); - - // change binding once - v.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - invalidationListener.check(property, 1); - - // change binding twice without reading - v.set(VALUE_1a); - v.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(1); - invalidationListener.check(property, 1); - - // change binding twice to same value - v.set(VALUE_1a); - v.set(VALUE_1a); - assertEquals(VALUE_1a, property.get()); - property.check(1); - invalidationListener.check(property, 1); - } - - @Test - public void testBind_Change() { - attachChangeListener(); - final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); - - property.bind(v); - assertEquals(VALUE_1a, property.get()); - assertTrue(property.isBound()); - property.check(1); - changeListener.check(property, null, VALUE_1a, 1); - - // change binding once - v.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - changeListener.check(property, VALUE_1a, VALUE_2a, 1); - - // change binding twice without reading - v.set(VALUE_1a); - v.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - changeListener.check(property, VALUE_1a, VALUE_1b, 2); - - // change binding twice to same value - v.set(VALUE_1a); - v.set(VALUE_1a); - assertEquals(VALUE_1a, property.get()); - property.check(2); - changeListener.check(property, VALUE_1b, VALUE_1a, 1); - } - - @Test - public void testBind_ListChange() { - attachListChangeListener(); - final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); - - property.bind(v); - assertEquals(VALUE_1a, property.get()); - assertTrue(property.isBound()); - property.check(1); - listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 0); - - // change binding once - listChangeListener.clear(); - v.set(VALUE_2a); - assertEquals(VALUE_2a, property.get()); - property.check(1); - listChangeListener.check1AddRemove(property, VALUE_1a, 0, 2); - - // change binding twice without reading - v.set(VALUE_1a); - listChangeListener.clear(); - v.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - property.check(2); - listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); - - // change binding twice to same value - v.set(VALUE_1a); - listChangeListener.clear(); - v.set(VALUE_1a); - assertEquals(VALUE_1a, property.get()); - property.check(2); - listChangeListener.check0(); - } - - @Test(expected = NullPointerException.class) - public void testBindToNull() { - property.bind(null); - } - - @Test - public void testRebind() { - attachInvalidationListener(); - final ListProperty v1 = new SimpleListProperty(VALUE_1a); - final ListProperty v2 = new SimpleListProperty(VALUE_2a); - property.bind(v1); - property.get(); - property.reset(); - invalidationListener.reset(); - - // rebind causes invalidation event - property.bind(v2); - assertEquals(VALUE_2a, property.get()); - assertTrue(property.isBound()); - assertEquals(1, property.counter); - invalidationListener.check(property, 1); - property.reset(); - - // change old binding - v1.set(VALUE_1b); - assertEquals(VALUE_2a, property.get()); - assertEquals(0, property.counter); - invalidationListener.check(null, 0); - property.reset(); - - // change new binding - v2.set(VALUE_2b); - assertEquals(VALUE_2b, property.get()); - assertEquals(1, property.counter); - invalidationListener.check(property, 1); - property.reset(); - - // rebind to same observable should have no effect - property.bind(v2); - assertEquals(VALUE_2b, property.get()); - assertTrue(property.isBound()); - assertEquals(0, property.counter); - invalidationListener.check(null, 0); - } - - @Test - public void testUnbind() { - attachInvalidationListener(); - final ListProperty v = new SimpleListProperty(VALUE_1a); - property.bind(v); - property.unbind(); - assertEquals(VALUE_1a, property.get()); - assertFalse(property.isBound()); - property.reset(); - invalidationListener.reset(); - - // change binding - v.set(VALUE_2a); - assertEquals(VALUE_1a, property.get()); - assertEquals(0, property.counter); - invalidationListener.check(null, 0); - property.reset(); - - // set value - property.set(VALUE_1b); - assertEquals(VALUE_1b, property.get()); - assertEquals(1, property.counter); - invalidationListener.check(property, 1); - } - - @Test - public void testAddingListenerWillAlwaysReceiveInvalidationEvent() { - final ListProperty v = new SimpleListProperty(VALUE_1a); - final InvalidationListenerMock listener2 = new InvalidationListenerMock(); - final InvalidationListenerMock listener3 = new InvalidationListenerMock(); - - // setting the property - property.set(VALUE_1a); - property.addListener(listener2); - listener2.reset(); - property.set(VALUE_1b); - listener2.check(property, 1); - - // binding the property - property.bind(v); - v.set(VALUE_2a); - property.addListener(listener3); - v.get(); - listener3.reset(); - v.set(VALUE_2b); - listener3.check(property, 1); - } - - @Test - public void testUpdate() { - ObservableList list = createPersonsList(); - ListProperty property = new SimpleListProperty<>(list); - MockListObserver mlo = new MockListObserver<>(); - property.addListener(mlo); - list.get(3).name.set("zero"); // four -> zero - ObservableList expected = FXCollections.observableArrayList( - new Person("one"), new Person("two"), new Person("three"), - new Person("zero"), new Person("five")); - mlo.check1Update(expected, 3, 4); - } - - @Test - public void testPermutation() { - ObservableList list = createPersonsList(); - ListProperty property = new SimpleListProperty<>(list); - MockListObserver mlo = new MockListObserver<>(); - property.addListener(mlo); - FXCollections.sort(list); - ObservableList expected = FXCollections.observableArrayList( - new Person("five"), new Person("four"), new Person("one"), - new Person("three"), new Person("two")); - mlo.check1Permutation(expected, new int[]{2, 4, 3, 1, 0}); - } - - @Test - public void testPermutationUpdate() { - ObservableList list = createPersonsList(); - ObservableList sorted = list.sorted((o1, o2) -> o1.compareTo(o2)); - ListProperty property = new SimpleListProperty<>(sorted); - MockListObserver mlo = new MockListObserver<>(); - property.addListener(mlo); - // add another listener to test Generic code path instead of SingleChange - property.addListener(new MockListObserver<>()); - list.get(3).name.set("zero"); // four -> zero - ObservableList expected = FXCollections.observableArrayList( - new Person("five"), new Person("one"), new Person("three"), - new Person("two"), new Person("zero")); - mlo.checkPermutation(0, expected, 0, expected.size(), new int[]{0, 4, 1, 2, 3}); - mlo.checkUpdate(1, expected, 4, 5); - } - - private ObservableList createPersonsList() { - ObservableList list = FXCollections.observableArrayList( - (Person p) -> new Observable[]{p.name}); - list.addAll( - new Person("one"), new Person("two"), new Person("three"), - new Person("four"), new Person("five")); - return list; - } - - @Test - public void testToString() { - final ObservableList value0 = null; - final ObservableList value1 = FXCollections.observableArrayList(new Object(), new Object()); - final ObservableList value2 = FXCollections.observableArrayList(); - final ListProperty v = new SimpleListProperty(value2); - - property.set(value1); - assertEquals("ListProperty [value: " + value1 + "]", property.toString()); - - property.bind(v); - assertEquals("ListProperty [bound, invalid]", property.toString()); - property.get(); - assertEquals("ListProperty [bound, value: " + value2 + "]", property.toString()); - v.set(value1); - assertEquals("ListProperty [bound, invalid]", property.toString()); - property.get(); - assertEquals("ListProperty [bound, value: " + value1 + "]", property.toString()); - - final Object bean = new Object(); - final String name = "My name"; - final ListProperty v1 = new ListPropertyMock(bean, name); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + null + "]", v1.toString()); - v1.set(value1); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value1 + "]", v1.toString()); - v1.set(value0); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); - - final ListProperty v2 = new ListPropertyMock(bean, NO_NAME_1); - assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + null + "]", v2.toString()); - v2.set(value1); - assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v2.toString()); - v1.set(value0); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); - - final ListProperty v3 = new ListPropertyMock(bean, NO_NAME_2); - assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + null + "]", v3.toString()); - v3.set(value1); - assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v3.toString()); - v1.set(value0); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); - - final ListProperty v4 = new ListPropertyMock(NO_BEAN, name); - assertEquals("ListProperty [name: My name, value: " + null + "]", v4.toString()); - v4.set(value1); - v1.set(value0); - assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); - assertEquals("ListProperty [name: My name, value: " + value1 + "]", v4.toString()); - } - - private static class ListPropertyMock extends ListPropertyBase { - - private final Object bean; - private final String name; - private int counter; - - private ListPropertyMock() { - this.bean = NO_BEAN; - this.name = NO_NAME_1; - } - - private ListPropertyMock(Object bean, String name) { - this.bean = bean; - this.name = name; - } - - private ListPropertyMock(ObservableList initialValue) { - super(initialValue); - this.bean = NO_BEAN; - this.name = NO_NAME_1; - } - - - - @Override - protected void invalidated() { - counter++; - } - - private void check(int expected) { - assertEquals(expected, counter); - reset(); - } - - private void reset() { - counter = 0; - } - - @Override - public Object getBean() { - return bean; - } - - @Override - public String getName() { - return name; - } - } -} --- /dev/null 2015-08-30 16:31:40.093001923 -0400 +++ new/modules/base/src/test/java/test/javafx/beans/property/ListPropertyBaseTest.java 2015-08-31 10:23:24.613217506 -0400 @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test.javafx.beans.property; + +import java.util.Arrays; +import test.javafx.beans.InvalidationListenerMock; +import test.javafx.beans.value.ChangeListenerMock; +import javafx.beans.value.ObservableObjectValueStub; +import javafx.collections.FXCollections; +import test.javafx.collections.MockListObserver; +import javafx.collections.ObservableList; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collections; +import java.util.List; +import javafx.beans.Observable; +import javafx.beans.property.ListProperty; +import javafx.beans.property.ListPropertyBase; +import javafx.beans.property.SimpleListProperty; +import test.javafx.collections.Person; + +import static org.junit.Assert.*; + +public class ListPropertyBaseTest { + + private static final Object NO_BEAN = null; + private static final String NO_NAME_1 = null; + private static final String NO_NAME_2 = ""; + private static final ObservableList UNDEFINED = FXCollections.observableArrayList(); + private static final ObservableList VALUE_1a = FXCollections.observableArrayList(); + private static final ObservableList VALUE_1b = FXCollections.observableArrayList(new Object()); + private static final ObservableList VALUE_2a = FXCollections.observableArrayList(new Object(), new Object()); + private static final ObservableList VALUE_2b = FXCollections.observableArrayList(new Object(), new Object(), new Object()); + private static final List EMPTY_LIST = Collections.emptyList(); + private ListPropertyMock property; + private InvalidationListenerMock invalidationListener; + private ChangeListenerMock> changeListener; + private MockListObserver listChangeListener; + + @Before + public void setUp() throws Exception { + property = new ListPropertyMock(); + invalidationListener = new InvalidationListenerMock(); + changeListener = new ChangeListenerMock>(UNDEFINED); + listChangeListener = new MockListObserver(); + } + + private void attachInvalidationListener() { + property.addListener(invalidationListener); + property.get(); + invalidationListener.reset(); + } + + private void attachChangeListener() { + property.addListener(changeListener); + property.get(); + changeListener.reset(); + } + + private void attachListChangeListener() { + property.addListener(listChangeListener); + property.get(); + listChangeListener.clear(); + } + + @Test + public void testConstructor() { + final ListProperty p1 = new SimpleListProperty(); + assertEquals(null, p1.get()); + assertEquals(null, p1.getValue()); + assertFalse(property.isBound()); + + final ListProperty p2 = new SimpleListProperty(VALUE_1b); + assertEquals(VALUE_1b, p2.get()); + assertEquals(VALUE_1b, p2.getValue()); + assertFalse(property.isBound()); + } + + @Test + public void testEmptyProperty() { + assertEquals("empty", property.emptyProperty().getName()); + assertEquals(property, property.emptyProperty().getBean()); + assertTrue(property.emptyProperty().get()); + + property.set(VALUE_2a); + assertFalse(property.emptyProperty().get()); + property.set(VALUE_1a); + assertTrue(property.emptyProperty().get()); + } + + @Test + public void testSizeProperty() { + assertEquals("size", property.sizeProperty().getName()); + assertEquals(property, property.sizeProperty().getBean()); + assertEquals(0, property.sizeProperty().get()); + + property.set(VALUE_2a); + assertEquals(2, property.sizeProperty().get()); + property.set(VALUE_1a); + assertEquals(0, property.sizeProperty().get()); + } + + @Test + public void testInvalidationListener() { + attachInvalidationListener(); + property.set(VALUE_2a); + invalidationListener.check(property, 1); + property.removeListener(invalidationListener); + invalidationListener.reset(); + property.set(VALUE_1a); + invalidationListener.check(null, 0); + } + + @Test + public void testChangeListener() { + attachChangeListener(); + property.set(VALUE_2a); + changeListener.check(property, null, VALUE_2a, 1); + property.removeListener(changeListener); + changeListener.reset(); + property.set(VALUE_1a); + changeListener.check(null, UNDEFINED, UNDEFINED, 0); + } + + @Test + public void testListChangeListener() { + attachListChangeListener(); + property.set(VALUE_2a); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); + property.removeListener(listChangeListener); + listChangeListener.clear(); + property.set(VALUE_1a); + listChangeListener.check0(); + } + + @Test + public void testSourceList_Invalidation() { + final ObservableList source1 = FXCollections.observableArrayList(); + final ObservableList source2 = FXCollections.observableArrayList(); + final Object value1 = new Object(); + final Object value2 = new Object(); + + // constructor + property = new ListPropertyBaseTest.ListPropertyMock(source1); + property.reset(); + attachInvalidationListener(); + + // add element + source1.add(value1); + assertEquals(value1, property.get(0)); + property.check(1); + invalidationListener.check(property, 1); + + // replace element + source1.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + invalidationListener.check(property, 1); + + // remove element + source1.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + invalidationListener.check(property, 1); + + // set + property.set(source2); + property.get(); + property.reset(); + invalidationListener.reset(); + + // add element + source2.add(0, value1); + assertEquals(value1, property.get(0)); + property.check(1); + invalidationListener.check(property, 1); + + // replace element + source2.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + invalidationListener.check(property, 1); + + // remove element + source2.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + invalidationListener.check(property, 1); + } + + @Test + public void testSourceList_Change() { + final ObservableList source1 = FXCollections.observableArrayList(); + final ObservableList source2 = FXCollections.observableArrayList(); + final Object value1 = new Object(); + final Object value2 = new Object(); + + // constructor + property = new ListPropertyBaseTest.ListPropertyMock(source1); + property.reset(); + attachChangeListener(); + + // add element + source1.add(value1); + assertEquals(value1, property.get(0)); + property.check(1); + changeListener.check(property, source1, source1, 1); + + // replace element + source1.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + changeListener.check(property, source1, source1, 1); + + // remove element + source1.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + changeListener.check(property, source1, source1, 1); + + // set + property.set(source2); + property.get(); + property.reset(); + changeListener.reset(); + + // add element + source2.add(0, value1); + assertEquals(value1, property.get(0)); + property.check(1); + changeListener.check(property, source2, source2, 1); + + // replace element + source2.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + changeListener.check(property, source2, source2, 1); + + // remove element + source2.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + changeListener.check(property, source2, source2, 1); + } + + @Test + public void testSourceList_ListChange() { + final ObservableList source1 = FXCollections.observableArrayList(); + final ObservableList source2 = FXCollections.observableArrayList(); + final Object value1 = new Object(); + final Object value2 = new Object(); + + // constructor + property = new ListPropertyBaseTest.ListPropertyMock(source1); + property.reset(); + attachListChangeListener(); + + // add element + source1.add(value1); + assertEquals(value1, property.get(0)); + property.check(1); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 1); + listChangeListener.clear(); + + // replace element + source1.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + listChangeListener.check1AddRemove(property, Arrays.asList(value1), 0, 1); + listChangeListener.clear(); + + // remove element + source1.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + listChangeListener.check1AddRemove(property, Arrays.asList(value2), 0, 0); + listChangeListener.clear(); + + // set + property.set(source2); + property.get(); + property.reset(); + listChangeListener.clear(); + + // add element + source2.add(0, value1); + assertEquals(value1, property.get(0)); + property.check(1); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 1); + listChangeListener.clear(); + + // replace element + source2.set(0, value2); + assertEquals(value2, property.get(0)); + property.check(1); + listChangeListener.check1AddRemove(property, Arrays.asList(value1), 0, 1); + listChangeListener.clear(); + + // remove element + source2.remove(0); + assertTrue(property.isEmpty()); + property.check(1); + listChangeListener.check1AddRemove(property, Arrays.asList(value2), 0, 0); + listChangeListener.clear(); + } + + @Test + public void testSet_Invalidation() { + attachInvalidationListener(); + + // set value once + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + invalidationListener.check(property, 1); + + // set same value again + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + invalidationListener.check(null, 0); + + // set value twice without reading + property.set(VALUE_1a); + property.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(1); + invalidationListener.check(property, 1); + } + + @Test + public void testSet_Change() { + attachChangeListener(); + + // set value once + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + changeListener.check(property, null, VALUE_2a, 1); + + // set same value again + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + changeListener.check(null, UNDEFINED, UNDEFINED, 0); + + // set value twice without reading + property.set(VALUE_1a); + property.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + changeListener.check(property, VALUE_1a, VALUE_1b, 2); + } + + @Test + public void testSet_ListChange() { + attachListChangeListener(); + + // set value once + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); + + // set same value again + listChangeListener.clear(); + property.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + listChangeListener.check0(); + + // set value twice without reading + property.set(VALUE_1a); + listChangeListener.clear(); + property.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); + } + + @Test + public void testSetValue_Invalidation() { + attachInvalidationListener(); + + // set value once + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + invalidationListener.check(property, 1); + + // set same value again + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + invalidationListener.check(null, 0); + + // set value twice without reading + property.setValue(VALUE_1a); + property.setValue(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(1); + invalidationListener.check(property, 1); + } + + @Test + public void testSetValue_Change() { + attachChangeListener(); + + // set value once + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + changeListener.check(property, null, VALUE_2a, 1); + + // set same value again + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + changeListener.check(null, UNDEFINED, UNDEFINED, 0); + + // set value twice without reading + property.setValue(VALUE_1a); + property.setValue(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + changeListener.check(property, VALUE_1a, VALUE_1b, 2); + } + + @Test + public void testSetValue_ListChange() { + attachListChangeListener(); + + // set value once + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 2); + + // set same value again + listChangeListener.clear(); + property.setValue(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(0); + listChangeListener.check0(); + + // set value twice without reading + property.setValue(VALUE_1a); + listChangeListener.clear(); + property.setValue(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); + } + + @Test(expected = RuntimeException.class) + public void testSetBoundValue() { + final ListProperty v = new SimpleListProperty(VALUE_1a); + property.bind(v); + property.set(VALUE_1a); + } + + @Test + public void testBind_Invalidation() { + attachInvalidationListener(); + final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); + + property.bind(v); + assertEquals(VALUE_1a, property.get()); + assertTrue(property.isBound()); + property.check(1); + invalidationListener.check(property, 1); + + // change binding once + v.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + invalidationListener.check(property, 1); + + // change binding twice without reading + v.set(VALUE_1a); + v.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(1); + invalidationListener.check(property, 1); + + // change binding twice to same value + v.set(VALUE_1a); + v.set(VALUE_1a); + assertEquals(VALUE_1a, property.get()); + property.check(1); + invalidationListener.check(property, 1); + } + + @Test + public void testBind_Change() { + attachChangeListener(); + final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); + + property.bind(v); + assertEquals(VALUE_1a, property.get()); + assertTrue(property.isBound()); + property.check(1); + changeListener.check(property, null, VALUE_1a, 1); + + // change binding once + v.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + changeListener.check(property, VALUE_1a, VALUE_2a, 1); + + // change binding twice without reading + v.set(VALUE_1a); + v.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + changeListener.check(property, VALUE_1a, VALUE_1b, 2); + + // change binding twice to same value + v.set(VALUE_1a); + v.set(VALUE_1a); + assertEquals(VALUE_1a, property.get()); + property.check(2); + changeListener.check(property, VALUE_1b, VALUE_1a, 1); + } + + @Test + public void testBind_ListChange() { + attachListChangeListener(); + final ObservableObjectValueStub> v = new ObservableObjectValueStub>(FXCollections.observableArrayList(VALUE_1a)); + + property.bind(v); + assertEquals(VALUE_1a, property.get()); + assertTrue(property.isBound()); + property.check(1); + listChangeListener.check1AddRemove(property, EMPTY_LIST, 0, 0); + + // change binding once + listChangeListener.clear(); + v.set(VALUE_2a); + assertEquals(VALUE_2a, property.get()); + property.check(1); + listChangeListener.check1AddRemove(property, VALUE_1a, 0, 2); + + // change binding twice without reading + v.set(VALUE_1a); + listChangeListener.clear(); + v.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + property.check(2); + listChangeListener.check1AddRemove(property, VALUE_1a, 0, 1); + + // change binding twice to same value + v.set(VALUE_1a); + listChangeListener.clear(); + v.set(VALUE_1a); + assertEquals(VALUE_1a, property.get()); + property.check(2); + listChangeListener.check0(); + } + + @Test(expected = NullPointerException.class) + public void testBindToNull() { + property.bind(null); + } + + @Test + public void testRebind() { + attachInvalidationListener(); + final ListProperty v1 = new SimpleListProperty(VALUE_1a); + final ListProperty v2 = new SimpleListProperty(VALUE_2a); + property.bind(v1); + property.get(); + property.reset(); + invalidationListener.reset(); + + // rebind causes invalidation event + property.bind(v2); + assertEquals(VALUE_2a, property.get()); + assertTrue(property.isBound()); + assertEquals(1, property.counter); + invalidationListener.check(property, 1); + property.reset(); + + // change old binding + v1.set(VALUE_1b); + assertEquals(VALUE_2a, property.get()); + assertEquals(0, property.counter); + invalidationListener.check(null, 0); + property.reset(); + + // change new binding + v2.set(VALUE_2b); + assertEquals(VALUE_2b, property.get()); + assertEquals(1, property.counter); + invalidationListener.check(property, 1); + property.reset(); + + // rebind to same observable should have no effect + property.bind(v2); + assertEquals(VALUE_2b, property.get()); + assertTrue(property.isBound()); + assertEquals(0, property.counter); + invalidationListener.check(null, 0); + } + + @Test + public void testUnbind() { + attachInvalidationListener(); + final ListProperty v = new SimpleListProperty(VALUE_1a); + property.bind(v); + property.unbind(); + assertEquals(VALUE_1a, property.get()); + assertFalse(property.isBound()); + property.reset(); + invalidationListener.reset(); + + // change binding + v.set(VALUE_2a); + assertEquals(VALUE_1a, property.get()); + assertEquals(0, property.counter); + invalidationListener.check(null, 0); + property.reset(); + + // set value + property.set(VALUE_1b); + assertEquals(VALUE_1b, property.get()); + assertEquals(1, property.counter); + invalidationListener.check(property, 1); + } + + @Test + public void testAddingListenerWillAlwaysReceiveInvalidationEvent() { + final ListProperty v = new SimpleListProperty(VALUE_1a); + final InvalidationListenerMock listener2 = new InvalidationListenerMock(); + final InvalidationListenerMock listener3 = new InvalidationListenerMock(); + + // setting the property + property.set(VALUE_1a); + property.addListener(listener2); + listener2.reset(); + property.set(VALUE_1b); + listener2.check(property, 1); + + // binding the property + property.bind(v); + v.set(VALUE_2a); + property.addListener(listener3); + v.get(); + listener3.reset(); + v.set(VALUE_2b); + listener3.check(property, 1); + } + + @Test + public void testUpdate() { + ObservableList list = createPersonsList(); + ListProperty property = new SimpleListProperty<>(list); + MockListObserver mlo = new MockListObserver<>(); + property.addListener(mlo); + list.get(3).name.set("zero"); // four -> zero + ObservableList expected = FXCollections.observableArrayList( + new Person("one"), new Person("two"), new Person("three"), + new Person("zero"), new Person("five")); + mlo.check1Update(expected, 3, 4); + } + + @Test + public void testPermutation() { + ObservableList list = createPersonsList(); + ListProperty property = new SimpleListProperty<>(list); + MockListObserver mlo = new MockListObserver<>(); + property.addListener(mlo); + FXCollections.sort(list); + ObservableList expected = FXCollections.observableArrayList( + new Person("five"), new Person("four"), new Person("one"), + new Person("three"), new Person("two")); + mlo.check1Permutation(expected, new int[]{2, 4, 3, 1, 0}); + } + + @Test + public void testPermutationUpdate() { + ObservableList list = createPersonsList(); + ObservableList sorted = list.sorted((o1, o2) -> o1.compareTo(o2)); + ListProperty property = new SimpleListProperty<>(sorted); + MockListObserver mlo = new MockListObserver<>(); + property.addListener(mlo); + // add another listener to test Generic code path instead of SingleChange + property.addListener(new MockListObserver<>()); + list.get(3).name.set("zero"); // four -> zero + ObservableList expected = FXCollections.observableArrayList( + new Person("five"), new Person("one"), new Person("three"), + new Person("two"), new Person("zero")); + mlo.checkPermutation(0, expected, 0, expected.size(), new int[]{0, 4, 1, 2, 3}); + mlo.checkUpdate(1, expected, 4, 5); + } + + private ObservableList createPersonsList() { + ObservableList list = FXCollections.observableArrayList( + (Person p) -> new Observable[]{p.name}); + list.addAll( + new Person("one"), new Person("two"), new Person("three"), + new Person("four"), new Person("five")); + return list; + } + + @Test + public void testToString() { + final ObservableList value0 = null; + final ObservableList value1 = FXCollections.observableArrayList(new Object(), new Object()); + final ObservableList value2 = FXCollections.observableArrayList(); + final ListProperty v = new SimpleListProperty(value2); + + property.set(value1); + assertEquals("ListProperty [value: " + value1 + "]", property.toString()); + + property.bind(v); + assertEquals("ListProperty [bound, invalid]", property.toString()); + property.get(); + assertEquals("ListProperty [bound, value: " + value2 + "]", property.toString()); + v.set(value1); + assertEquals("ListProperty [bound, invalid]", property.toString()); + property.get(); + assertEquals("ListProperty [bound, value: " + value1 + "]", property.toString()); + + final Object bean = new Object(); + final String name = "My name"; + final ListProperty v1 = new ListPropertyMock(bean, name); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + null + "]", v1.toString()); + v1.set(value1); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value1 + "]", v1.toString()); + v1.set(value0); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); + + final ListProperty v2 = new ListPropertyMock(bean, NO_NAME_1); + assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + null + "]", v2.toString()); + v2.set(value1); + assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v2.toString()); + v1.set(value0); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); + + final ListProperty v3 = new ListPropertyMock(bean, NO_NAME_2); + assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + null + "]", v3.toString()); + v3.set(value1); + assertEquals("ListProperty [bean: " + bean.toString() + ", value: " + value1 + "]", v3.toString()); + v1.set(value0); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); + + final ListProperty v4 = new ListPropertyMock(NO_BEAN, name); + assertEquals("ListProperty [name: My name, value: " + null + "]", v4.toString()); + v4.set(value1); + v1.set(value0); + assertEquals("ListProperty [bean: " + bean.toString() + ", name: My name, value: " + value0 + "]", v1.toString()); + assertEquals("ListProperty [name: My name, value: " + value1 + "]", v4.toString()); + } + + private static class ListPropertyMock extends ListPropertyBase { + + private final Object bean; + private final String name; + private int counter; + + private ListPropertyMock() { + this.bean = NO_BEAN; + this.name = NO_NAME_1; + } + + private ListPropertyMock(Object bean, String name) { + this.bean = bean; + this.name = name; + } + + private ListPropertyMock(ObservableList initialValue) { + super(initialValue); + this.bean = NO_BEAN; + this.name = NO_NAME_1; + } + + + + @Override + protected void invalidated() { + counter++; + } + + private void check(int expected) { + assertEquals(expected, counter); + reset(); + } + + private void reset() { + counter = 0; + } + + @Override + public Object getBean() { + return bean; + } + + @Override + public String getName() { + return name; + } + } +}