--- old/modules/base/src/test/java/com/sun/javafx/binding/SelectBindingTest.java 2015-08-31 10:22:56.253217824 -0400 +++ /dev/null 2015-08-30 16:31:40.093001923 -0400 @@ -1,655 +0,0 @@ -/* - * Copyright (c) 2010, 2014, 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 com.sun.javafx.binding; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import javafx.beans.Person; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.binding.DoubleBinding; -import javafx.beans.binding.FloatBinding; -import javafx.beans.binding.IntegerBinding; -import javafx.beans.binding.LongBinding; -import javafx.beans.binding.ObjectBinding; -import javafx.beans.binding.StringBinding; -import javafx.binding.Variable; -import javafx.collections.ObservableList; -import sun.util.logging.PlatformLogger.Level; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class SelectBindingTest { - - private static final double EPSILON_DOUBLE = 1e-12; - private static final float EPSILON_FLOAT = 1e-6f; - - public static class POJOPerson { - - private String name; - - public String getName() { - return name; - } - - public POJOPerson() { - } - - public POJOPerson(String name) { - this.name = name; - } - - } - - public static class POJONext { - - private Object next; - private PropertyChangeSupport pcs = new PropertyChangeSupport(this); - - public Object getNext() { - return next; - } - - public void setNext(Object next) { - Object old = this.next; - this.next = next; - pcs.firePropertyChange("next", old, next); - } - - public void addPropertyChangeListener(String property, PropertyChangeListener pcl) { - pcs.addPropertyChangeListener(property, pcl); - } - - public void removePropertyChangeListener(String property, PropertyChangeListener pcl) { - pcs.removePropertyChangeListener(property, pcl); - } - - } - - private Variable a; - private Variable b; - private Variable c; - private Variable d; - private StringBinding select; - private ObservableList dependencies; - - private static final ErrorLoggingUtiltity log = new ErrorLoggingUtiltity(); - - @BeforeClass - public static void setUpClass() { - log.start(); - } - - @AfterClass - public static void tearDownClass() { - log.stop(); - } - - @Before - public void setUp() throws Exception { - a = new Variable("a"); - b = new Variable("b"); - c = new Variable("c"); - d = new Variable("d"); - a.setNext(b); - b.setNext(c); - select = Bindings.selectString(a.nextProperty(), "next", "name"); - dependencies = select.getDependencies(); - } - - @Test - public void testObject() { - final Person person1 = new Person(); - final Person person2 = new Person(); - c.setNext(person1); - final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next"); - assertEquals(person1, objectBinding.get()); - c.setNext(person2); - assertEquals(person2, objectBinding.get()); - b.setNext(null); - assertEquals(null, objectBinding.get()); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJOObject() { - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - final Person person1 = new Person(); - final Person person2 = new Person(); - c.setNext(person1); - final ObjectBinding objectBinding = Bindings.select(pojoA, "next", "next", "next"); - assertEquals(person1, objectBinding.get()); - c.setNext(person2); - assertEquals(person2, objectBinding.get()); - } - - @Test - public void testPOJOObject_2() { - POJONext pojoC = new POJONext(); - b.setNext(pojoC); - final Person person1 = new Person(); - final Person person2 = new Person(); - pojoC.setNext(person1); - final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next"); - assertEquals(person1, objectBinding.get()); - pojoC.setNext(person2); - assertEquals(person2, objectBinding.get()); - } - - @Test - public void testPOJOObject_3() { - final POJOPerson person1 = new POJOPerson("P1"); - final POJOPerson person2 = new POJOPerson("P2"); - c.setNext(person1); - final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next", "name"); - assertEquals("P1", objectBinding.get()); - c.setNext(person2); - assertEquals("P2", objectBinding.get()); - b.setNext(null); - assertEquals(null, objectBinding.get()); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJOBoolean() { - - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - - final Person person = new Person(); - b.setNext(person); - final BooleanBinding binding1 = Bindings.selectBoolean(pojoA, "next", "next", "retired"); - assertEquals(false, binding1.get()); - person.setRetired(true); - assertEquals(true, binding1.get()); - } - - @Test - public void testBoolean() { - - final Person person = new Person(); - b.setNext(person); - final BooleanBinding binding1 = Bindings.selectBoolean(a.nextProperty(), "next", "retired"); - assertEquals(false, binding1.get()); - person.setRetired(true); - assertEquals(true, binding1.get()); - b.setNext(null); - assertEquals(false, binding1.get()); - log.checkFine(NullPointerException.class); - - person.setData(false); - b.setNext(person); - final BooleanBinding binding2 = Bindings.selectBoolean(a.nextProperty(), "next", "data"); - assertEquals(false, binding2.get()); - person.setData(true); - assertEquals(true, binding2.get()); - person.setData(null); - assertEquals(false, binding2.get()); - log.checkFine(NullPointerException.class); - b.setNext(null); - assertEquals(false, binding2.get()); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJODouble() { - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - - final Person person = new Person(); - person.setSomething(-Math.E); - b.setNext(person); - final DoubleBinding binding1 = Bindings.selectDouble(pojoA, "next", "next", "something"); - assertEquals(-Math.E, binding1.get(), EPSILON_DOUBLE); - person.setSomething(Math.PI); - assertEquals(Math.PI, binding1.get(), EPSILON_DOUBLE); - } - - @Test - public void testDouble() { - - final Person person = new Person(); - person.setSomething(-Math.E); - b.setNext(person); - final DoubleBinding binding1 = Bindings.selectDouble(a.nextProperty(), "next", "something"); - assertEquals(-Math.E, binding1.get(), EPSILON_DOUBLE); - person.setSomething(Math.PI); - assertEquals(Math.PI, binding1.get(), EPSILON_DOUBLE); - b.setNext(null); - assertEquals(0.0, binding1.get(), EPSILON_DOUBLE); - log.checkFine(NullPointerException.class); - - person.setData(-Math.E); - b.setNext(person); - final DoubleBinding binding2 = Bindings.selectDouble(a.nextProperty(), "next", "data"); - assertEquals(-Math.E, binding2.get(), EPSILON_DOUBLE); - person.setData(Math.PI); - assertEquals(Math.PI, binding2.get(), EPSILON_DOUBLE); - person.setData(null); - assertEquals(0.0, binding2.get(), EPSILON_DOUBLE); - log.checkFine(NullPointerException.class); - b.setNext(null); - assertEquals(0.0, binding2.get(), EPSILON_DOUBLE); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJOFloat() { - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - - final Person person = new Person(); - person.setMiles((float) -Math.E); - b.setNext(person); - final FloatBinding binding1 = Bindings.selectFloat(pojoA, "next", "next", "miles"); - assertEquals((float) -Math.E, binding1.get(), EPSILON_FLOAT); - person.setMiles((float) Math.PI); - assertEquals((float) Math.PI, binding1.get(), EPSILON_FLOAT); - } - - @Test - public void testFloat() { - - final Person person = new Person(); - person.setMiles((float) -Math.E); - b.setNext(person); - final FloatBinding binding1 = Bindings.selectFloat(a.nextProperty(), "next", "miles"); - assertEquals((float) -Math.E, binding1.get(), EPSILON_FLOAT); - person.setMiles((float) Math.PI); - assertEquals((float) Math.PI, binding1.get(), EPSILON_FLOAT); - b.setNext(null); - assertEquals(0.0f, binding1.get(), EPSILON_FLOAT); - log.checkFine(NullPointerException.class); - - person.setData((float) -Math.E); - b.setNext(person); - final FloatBinding binding2 = Bindings.selectFloat(a.nextProperty(), "next", "data"); - assertEquals((float) -Math.E, binding2.get(), EPSILON_FLOAT); - person.setData((float) Math.PI); - assertEquals((float) Math.PI, binding2.get(), EPSILON_FLOAT); - person.setData(null); - assertEquals(0.0f, binding2.get(), EPSILON_FLOAT); - log.checkFine(NullPointerException.class); - b.setNext(null); - assertEquals(0.0f, binding2.get(), EPSILON_FLOAT); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJOInteger() { - - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - - final Person person = new Person(); - person.setAge(42); - b.setNext(person); - final IntegerBinding binding1 = Bindings.selectInteger(pojoA, "next", "next", "age"); - assertEquals(42, binding1.get()); - person.setAge(-18); - assertEquals(-18, binding1.get()); - } - - @Test - public void testInteger() { - - final Person person = new Person(); - person.setAge(42); - b.setNext(person); - final IntegerBinding binding1 = Bindings.selectInteger(a.nextProperty(), "next", "age"); - assertEquals(42, binding1.get()); - person.setAge(-18); - assertEquals(-18, binding1.get()); - b.setNext(null); - assertEquals(0, binding1.get()); - log.checkFine(NullPointerException.class); - - person.setData(42); - b.setNext(person); - final IntegerBinding binding2 = Bindings.selectInteger(a.nextProperty(), "next", "data"); - assertEquals(42, binding2.get()); - person.setData(-18); - assertEquals(-18, binding2.get()); - person.setData(null); - assertEquals(0, binding2.get()); - log.checkFine(NullPointerException.class); - b.setNext(null); - assertEquals(0, binding2.get()); - log.checkFine(NullPointerException.class); - } - - @Test - public void testPOJOLong() { - POJONext pojoA = new POJONext(); - pojoA.setNext(b); - final Person person = new Person(); - person.setIncome(1234567890987654321L); - b.setNext(person); - final LongBinding binding1 = Bindings.selectLong(pojoA, "next", "next", "income"); - assertEquals(1234567890987654321L, binding1.get()); - person.setIncome(-987654321234567890L); - assertEquals(-987654321234567890L, binding1.get()); - } - - @Test - public void testLong() { - final Person person = new Person(); - person.setIncome(1234567890987654321L); - b.setNext(person); - final LongBinding binding1 = Bindings.selectLong(a.nextProperty(), "next", "income"); - assertEquals(1234567890987654321L, binding1.get()); - person.setIncome(-987654321234567890L); - assertEquals(-987654321234567890L, binding1.get()); - b.setNext(null); - assertEquals(0L, binding1.get()); - log.checkFine(NullPointerException.class); - - person.setData(1234567890987654321L); - b.setNext(person); - final LongBinding binding2 = Bindings.selectLong(a.nextProperty(), "next", "data"); - assertEquals(1234567890987654321L, binding2.get()); - person.setData(-987654321234567890L); - assertEquals(-987654321234567890L, binding2.get()); - person.setData(null); - assertEquals(0L, binding2.get()); - log.checkFine(NullPointerException.class); - b.setNext(null); - assertEquals(0L, binding2.get()); - log.checkFine(NullPointerException.class); - } - - @Test(expected = NullPointerException.class) - public void createWithRootNull() { - select = Bindings.selectString(null, "next", "name"); - } - - @Test - public void createWithNoSteps() { - select = Bindings.selectString(a.nameProperty()); - assertEquals("a", select.get()); - a.setName("b"); - assertEquals("b", select.get()); - a.setName(null); - assertNull(select.get()); - log.check(java.util.logging.Level.WARNING, NullPointerException.class); - } - - @Test(expected = NullPointerException.class) - public void createWithOneStepIsNull() { - select = Bindings.selectString(a.nextProperty(), null, "name"); - } - - @Test - public void testNullIsReturnedFromAChainWithAPropertyThatIsNotOnTheAvailableObject() { - select = Bindings.selectString(a.nextProperty(), "dummy", "name"); - assertNull(select.get()); - log.check(java.util.logging.Level.WARNING, NoSuchMethodException.class); - } - - @SuppressWarnings("unchecked") - @Test - public void testAllMembersHaveListeners() { - // As yet, there should still be no listeners registered - assertEquals(1, a.numChangedListenersForNext); - assertEquals(0, a.numChangedListenersForName); - assertEquals(0, b.numChangedListenersForNext); - assertEquals(0, b.numChangedListenersForName); - assertEquals(0, c.numChangedListenersForNext); - assertEquals(0, c.numChangedListenersForName); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - // Read the value of the select. It should be == "c" - assertEquals("c", select.get()); - // Now there should be changed listeners for a.value and - // b.value and c.name - assertEquals(1, a.numChangedListenersForNext); - assertEquals(0, a.numChangedListenersForName); - assertEquals(1, b.numChangedListenersForNext); - assertEquals(0, b.numChangedListenersForName); - assertEquals(0, c.numChangedListenersForNext); - assertEquals(1, c.numChangedListenersForName); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAValidChangeIsBrokenBySettingTheRootToNullThenTheValueIsNull() { - - assertEquals("c", select.get()); - a.setNext(null); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertNull(select.get()); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - log.checkFine(NullPointerException.class); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAnIncompleteChainIsMadeCompleteThatTheValueIsComputedCorrectly() { - - a.setNext(null); - select.get(); // force it to be validated, for fun - log.reset(); - a.setNext(b); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertEquals("c", select.get()); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - assertTrue(log.isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAValidChangeIsBrokenBySettingTheMiddleToNullThenTheValueIsNull() { - - assertEquals("c", select.get()); - b.setNext(null); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertNull(select.get()); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty()), dependencies); - log.checkFine(NullPointerException.class); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAnIncompleteChainIsMadeCompleteInTheMiddleThatTheValueIsComputedCorrectly() { - - b.setNext(null); - select.get(); - log.reset(); - b.setNext(c); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertEquals("c", select.get()); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - assertTrue(log.isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAValidChangeIsBrokenBySettingTheLastLinkToNullThenTheValueIsNull() { - log.reset(); - assertEquals("c", select.get()); - c.setName("d"); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertEquals("d", select.get()); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - assertTrue(log.isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testWhenAnIncompleteChainIsMadeCompleteAtTheEndThatTheValueIsComputedCorrectly() { - log.reset(); - c.setName("d"); - select.get(); - c.setName("c"); - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - assertEquals("c", select.get()); - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - assertTrue(log.isEmpty()); - } - - @SuppressWarnings("unchecked") - @Test - public void testSettingTheRootValueToNullInAChainShouldUnhookAllListeners() { - select.get(); - a.setNext(null); - - // All of the listeners should have been uninstalled - assertEquals(0, a.numChangedListenersForName); - assertEquals(1, a.numChangedListenersForNext); - - assertEquals(0, b.numChangedListenersForName); - assertEquals(0, b.numChangedListenersForNext); - - assertEquals(0, c.numChangedListenersForName); - assertEquals(0, c.numChangedListenersForNext); - - assertEquals(0, d.numChangedListenersForName); - assertEquals(0, d.numChangedListenersForNext); - - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - } - - /** - * This test performs 10,000 random operations on the chain of a.b.c - * (setting different values for each step, sometimes doing multiple - * assignments between get() calls, random invalidate() calls). After each - * random iteration, we check to see if the listeners installed on the a, b, - * c objects are still correct. The goal is to catch any freak situations - * where we might have installed two listeners on the same property, or - * failed to remove a listener for a property under some circumstance. - * - * Do note that the only listeners that are installed in this method are - * done by the select binding. - */ - @SuppressWarnings("unchecked") - @Test - public void stressTestRandomOperationsResultInCorrectListenersInstalled() { - - final Level logLevel = Logging.getLogger().level(); - Logging.getLogger().setLevel(Level.SEVERE); - List steps = new ArrayList(); - - Random rand = new Random(System.currentTimeMillis()); - for (int i = 0; i < 10000; i++) { - switch (rand.nextInt(20)) { - case 0: - a.setNext(null); - steps.add("Assign a.value to null"); - break; - case 1: - a.setNext(b); - steps.add("Assign a.value to b"); - break; - case 2: - b.setNext(null); - steps.add("Assign b.value to null"); - break; - case 3: - b.setNext(c); - steps.add("Assign b.value to c"); - break; - case 4: - c.setNext(null); - steps.add("Assign c.value to null"); - break; - case 5: - c.setNext(d); - steps.add("Assign c.value to d"); - break; - case 6: - c.setName(null); - steps.add("Assign c.name to null"); - break; - case 7: - c.setName("c"); - steps.add("Assign c.name to 'c'"); - break; - default: - select.get(); - steps.add("Call select.get()"); - } - - // Now validate that the listeners are as we expected - int expected = 1; - int depsCount = expected; - assertEquals(0, a.numChangedListenersForName); - if (expected != a.numChangedListenersForNext) { - printSteps(i, steps); - } - assertEquals(expected, a.numChangedListenersForNext); - - expected = select.isValid() && a.getNext() == b ? 1 : 0; - depsCount += expected; - assertEquals(0, b.numChangedListenersForName); - if (expected != b.numChangedListenersForNext) { - printSteps(i, steps); - } - assertEquals(expected, b.numChangedListenersForNext); - - expected = select.isValid() && a.getNext() == b && b.getNext() == c ? 1 : 0; - depsCount += expected; - assertEquals(0, c.numChangedListenersForNext); - if (expected != c.numChangedListenersForName) { - printSteps(i, steps); - } - assertEquals(expected, c.numChangedListenersForName); - - assertEquals(0, d.numChangedListenersForName); - assertEquals(0, d.numChangedListenersForNext); - - switch (depsCount) { - case 0: - case 1: - assertEquals(Arrays.asList(a.nextProperty()), dependencies); - break; - case 2: - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty()), dependencies); - break; - case 3: - assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); - break; - default: - fail("Should not reach here"); - } - } - Logging.getLogger().setLevel(logLevel); - } - - private void printSteps(int iteration, List steps) { - System.err.println("Failed on iteration " + iteration + " for the following observableArrayList of changes"); - for (String s : steps) { - System.err.println("\t" + s); - } - } -} --- /dev/null 2015-08-30 16:31:40.093001923 -0400 +++ new/modules/base/src/test/java/test/com/sun/javafx/binding/SelectBindingTest.java 2015-08-31 10:22:56.121217826 -0400 @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2010, 2014, 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.com.sun.javafx.binding; + +import com.sun.javafx.binding.Logging; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import test.javafx.beans.Person; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.BooleanBinding; +import javafx.beans.binding.DoubleBinding; +import javafx.beans.binding.FloatBinding; +import javafx.beans.binding.IntegerBinding; +import javafx.beans.binding.LongBinding; +import javafx.beans.binding.ObjectBinding; +import javafx.beans.binding.StringBinding; +import test.javafx.binding.Variable; +import javafx.collections.ObservableList; +import sun.util.logging.PlatformLogger.Level; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SelectBindingTest { + + private static final double EPSILON_DOUBLE = 1e-12; + private static final float EPSILON_FLOAT = 1e-6f; + + public static class POJOPerson { + + private String name; + + public String getName() { + return name; + } + + public POJOPerson() { + } + + public POJOPerson(String name) { + this.name = name; + } + + } + + public static class POJONext { + + private Object next; + private PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public Object getNext() { + return next; + } + + public void setNext(Object next) { + Object old = this.next; + this.next = next; + pcs.firePropertyChange("next", old, next); + } + + public void addPropertyChangeListener(String property, PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(property, pcl); + } + + public void removePropertyChangeListener(String property, PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(property, pcl); + } + + } + + private Variable a; + private Variable b; + private Variable c; + private Variable d; + private StringBinding select; + private ObservableList dependencies; + + private static final ErrorLoggingUtiltity log = new ErrorLoggingUtiltity(); + + @BeforeClass + public static void setUpClass() { + log.start(); + } + + @AfterClass + public static void tearDownClass() { + log.stop(); + } + + @Before + public void setUp() throws Exception { + a = new Variable("a"); + b = new Variable("b"); + c = new Variable("c"); + d = new Variable("d"); + a.setNext(b); + b.setNext(c); + select = Bindings.selectString(a.nextProperty(), "next", "name"); + dependencies = select.getDependencies(); + } + + @Test + public void testObject() { + final Person person1 = new Person(); + final Person person2 = new Person(); + c.setNext(person1); + final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next"); + assertEquals(person1, objectBinding.get()); + c.setNext(person2); + assertEquals(person2, objectBinding.get()); + b.setNext(null); + assertEquals(null, objectBinding.get()); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJOObject() { + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + final Person person1 = new Person(); + final Person person2 = new Person(); + c.setNext(person1); + final ObjectBinding objectBinding = Bindings.select(pojoA, "next", "next", "next"); + assertEquals(person1, objectBinding.get()); + c.setNext(person2); + assertEquals(person2, objectBinding.get()); + } + + @Test + public void testPOJOObject_2() { + POJONext pojoC = new POJONext(); + b.setNext(pojoC); + final Person person1 = new Person(); + final Person person2 = new Person(); + pojoC.setNext(person1); + final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next"); + assertEquals(person1, objectBinding.get()); + pojoC.setNext(person2); + assertEquals(person2, objectBinding.get()); + } + + @Test + public void testPOJOObject_3() { + final POJOPerson person1 = new POJOPerson("P1"); + final POJOPerson person2 = new POJOPerson("P2"); + c.setNext(person1); + final ObjectBinding objectBinding = Bindings.select(a.nextProperty(), "next", "next", "name"); + assertEquals("P1", objectBinding.get()); + c.setNext(person2); + assertEquals("P2", objectBinding.get()); + b.setNext(null); + assertEquals(null, objectBinding.get()); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJOBoolean() { + + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + + final Person person = new Person(); + b.setNext(person); + final BooleanBinding binding1 = Bindings.selectBoolean(pojoA, "next", "next", "retired"); + assertEquals(false, binding1.get()); + person.setRetired(true); + assertEquals(true, binding1.get()); + } + + @Test + public void testBoolean() { + + final Person person = new Person(); + b.setNext(person); + final BooleanBinding binding1 = Bindings.selectBoolean(a.nextProperty(), "next", "retired"); + assertEquals(false, binding1.get()); + person.setRetired(true); + assertEquals(true, binding1.get()); + b.setNext(null); + assertEquals(false, binding1.get()); + log.checkFine(NullPointerException.class); + + person.setData(false); + b.setNext(person); + final BooleanBinding binding2 = Bindings.selectBoolean(a.nextProperty(), "next", "data"); + assertEquals(false, binding2.get()); + person.setData(true); + assertEquals(true, binding2.get()); + person.setData(null); + assertEquals(false, binding2.get()); + log.checkFine(NullPointerException.class); + b.setNext(null); + assertEquals(false, binding2.get()); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJODouble() { + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + + final Person person = new Person(); + person.setSomething(-Math.E); + b.setNext(person); + final DoubleBinding binding1 = Bindings.selectDouble(pojoA, "next", "next", "something"); + assertEquals(-Math.E, binding1.get(), EPSILON_DOUBLE); + person.setSomething(Math.PI); + assertEquals(Math.PI, binding1.get(), EPSILON_DOUBLE); + } + + @Test + public void testDouble() { + + final Person person = new Person(); + person.setSomething(-Math.E); + b.setNext(person); + final DoubleBinding binding1 = Bindings.selectDouble(a.nextProperty(), "next", "something"); + assertEquals(-Math.E, binding1.get(), EPSILON_DOUBLE); + person.setSomething(Math.PI); + assertEquals(Math.PI, binding1.get(), EPSILON_DOUBLE); + b.setNext(null); + assertEquals(0.0, binding1.get(), EPSILON_DOUBLE); + log.checkFine(NullPointerException.class); + + person.setData(-Math.E); + b.setNext(person); + final DoubleBinding binding2 = Bindings.selectDouble(a.nextProperty(), "next", "data"); + assertEquals(-Math.E, binding2.get(), EPSILON_DOUBLE); + person.setData(Math.PI); + assertEquals(Math.PI, binding2.get(), EPSILON_DOUBLE); + person.setData(null); + assertEquals(0.0, binding2.get(), EPSILON_DOUBLE); + log.checkFine(NullPointerException.class); + b.setNext(null); + assertEquals(0.0, binding2.get(), EPSILON_DOUBLE); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJOFloat() { + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + + final Person person = new Person(); + person.setMiles((float) -Math.E); + b.setNext(person); + final FloatBinding binding1 = Bindings.selectFloat(pojoA, "next", "next", "miles"); + assertEquals((float) -Math.E, binding1.get(), EPSILON_FLOAT); + person.setMiles((float) Math.PI); + assertEquals((float) Math.PI, binding1.get(), EPSILON_FLOAT); + } + + @Test + public void testFloat() { + + final Person person = new Person(); + person.setMiles((float) -Math.E); + b.setNext(person); + final FloatBinding binding1 = Bindings.selectFloat(a.nextProperty(), "next", "miles"); + assertEquals((float) -Math.E, binding1.get(), EPSILON_FLOAT); + person.setMiles((float) Math.PI); + assertEquals((float) Math.PI, binding1.get(), EPSILON_FLOAT); + b.setNext(null); + assertEquals(0.0f, binding1.get(), EPSILON_FLOAT); + log.checkFine(NullPointerException.class); + + person.setData((float) -Math.E); + b.setNext(person); + final FloatBinding binding2 = Bindings.selectFloat(a.nextProperty(), "next", "data"); + assertEquals((float) -Math.E, binding2.get(), EPSILON_FLOAT); + person.setData((float) Math.PI); + assertEquals((float) Math.PI, binding2.get(), EPSILON_FLOAT); + person.setData(null); + assertEquals(0.0f, binding2.get(), EPSILON_FLOAT); + log.checkFine(NullPointerException.class); + b.setNext(null); + assertEquals(0.0f, binding2.get(), EPSILON_FLOAT); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJOInteger() { + + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + + final Person person = new Person(); + person.setAge(42); + b.setNext(person); + final IntegerBinding binding1 = Bindings.selectInteger(pojoA, "next", "next", "age"); + assertEquals(42, binding1.get()); + person.setAge(-18); + assertEquals(-18, binding1.get()); + } + + @Test + public void testInteger() { + + final Person person = new Person(); + person.setAge(42); + b.setNext(person); + final IntegerBinding binding1 = Bindings.selectInteger(a.nextProperty(), "next", "age"); + assertEquals(42, binding1.get()); + person.setAge(-18); + assertEquals(-18, binding1.get()); + b.setNext(null); + assertEquals(0, binding1.get()); + log.checkFine(NullPointerException.class); + + person.setData(42); + b.setNext(person); + final IntegerBinding binding2 = Bindings.selectInteger(a.nextProperty(), "next", "data"); + assertEquals(42, binding2.get()); + person.setData(-18); + assertEquals(-18, binding2.get()); + person.setData(null); + assertEquals(0, binding2.get()); + log.checkFine(NullPointerException.class); + b.setNext(null); + assertEquals(0, binding2.get()); + log.checkFine(NullPointerException.class); + } + + @Test + public void testPOJOLong() { + POJONext pojoA = new POJONext(); + pojoA.setNext(b); + final Person person = new Person(); + person.setIncome(1234567890987654321L); + b.setNext(person); + final LongBinding binding1 = Bindings.selectLong(pojoA, "next", "next", "income"); + assertEquals(1234567890987654321L, binding1.get()); + person.setIncome(-987654321234567890L); + assertEquals(-987654321234567890L, binding1.get()); + } + + @Test + public void testLong() { + final Person person = new Person(); + person.setIncome(1234567890987654321L); + b.setNext(person); + final LongBinding binding1 = Bindings.selectLong(a.nextProperty(), "next", "income"); + assertEquals(1234567890987654321L, binding1.get()); + person.setIncome(-987654321234567890L); + assertEquals(-987654321234567890L, binding1.get()); + b.setNext(null); + assertEquals(0L, binding1.get()); + log.checkFine(NullPointerException.class); + + person.setData(1234567890987654321L); + b.setNext(person); + final LongBinding binding2 = Bindings.selectLong(a.nextProperty(), "next", "data"); + assertEquals(1234567890987654321L, binding2.get()); + person.setData(-987654321234567890L); + assertEquals(-987654321234567890L, binding2.get()); + person.setData(null); + assertEquals(0L, binding2.get()); + log.checkFine(NullPointerException.class); + b.setNext(null); + assertEquals(0L, binding2.get()); + log.checkFine(NullPointerException.class); + } + + @Test(expected = NullPointerException.class) + public void createWithRootNull() { + select = Bindings.selectString(null, "next", "name"); + } + + @Test + public void createWithNoSteps() { + select = Bindings.selectString(a.nameProperty()); + assertEquals("a", select.get()); + a.setName("b"); + assertEquals("b", select.get()); + a.setName(null); + assertNull(select.get()); + log.check(java.util.logging.Level.WARNING, NullPointerException.class); + } + + @Test(expected = NullPointerException.class) + public void createWithOneStepIsNull() { + select = Bindings.selectString(a.nextProperty(), null, "name"); + } + + @Test + public void testNullIsReturnedFromAChainWithAPropertyThatIsNotOnTheAvailableObject() { + select = Bindings.selectString(a.nextProperty(), "dummy", "name"); + assertNull(select.get()); + log.check(java.util.logging.Level.WARNING, NoSuchMethodException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void testAllMembersHaveListeners() { + // As yet, there should still be no listeners registered + assertEquals(1, a.numChangedListenersForNext); + assertEquals(0, a.numChangedListenersForName); + assertEquals(0, b.numChangedListenersForNext); + assertEquals(0, b.numChangedListenersForName); + assertEquals(0, c.numChangedListenersForNext); + assertEquals(0, c.numChangedListenersForName); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + // Read the value of the select. It should be == "c" + assertEquals("c", select.get()); + // Now there should be changed listeners for a.value and + // b.value and c.name + assertEquals(1, a.numChangedListenersForNext); + assertEquals(0, a.numChangedListenersForName); + assertEquals(1, b.numChangedListenersForNext); + assertEquals(0, b.numChangedListenersForName); + assertEquals(0, c.numChangedListenersForNext); + assertEquals(1, c.numChangedListenersForName); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAValidChangeIsBrokenBySettingTheRootToNullThenTheValueIsNull() { + + assertEquals("c", select.get()); + a.setNext(null); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertNull(select.get()); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + log.checkFine(NullPointerException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAnIncompleteChainIsMadeCompleteThatTheValueIsComputedCorrectly() { + + a.setNext(null); + select.get(); // force it to be validated, for fun + log.reset(); + a.setNext(b); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertEquals("c", select.get()); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + assertTrue(log.isEmpty()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAValidChangeIsBrokenBySettingTheMiddleToNullThenTheValueIsNull() { + + assertEquals("c", select.get()); + b.setNext(null); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertNull(select.get()); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty()), dependencies); + log.checkFine(NullPointerException.class); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAnIncompleteChainIsMadeCompleteInTheMiddleThatTheValueIsComputedCorrectly() { + + b.setNext(null); + select.get(); + log.reset(); + b.setNext(c); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertEquals("c", select.get()); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + assertTrue(log.isEmpty()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAValidChangeIsBrokenBySettingTheLastLinkToNullThenTheValueIsNull() { + log.reset(); + assertEquals("c", select.get()); + c.setName("d"); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertEquals("d", select.get()); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + assertTrue(log.isEmpty()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWhenAnIncompleteChainIsMadeCompleteAtTheEndThatTheValueIsComputedCorrectly() { + log.reset(); + c.setName("d"); + select.get(); + c.setName("c"); + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + assertEquals("c", select.get()); + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + assertTrue(log.isEmpty()); + } + + @SuppressWarnings("unchecked") + @Test + public void testSettingTheRootValueToNullInAChainShouldUnhookAllListeners() { + select.get(); + a.setNext(null); + + // All of the listeners should have been uninstalled + assertEquals(0, a.numChangedListenersForName); + assertEquals(1, a.numChangedListenersForNext); + + assertEquals(0, b.numChangedListenersForName); + assertEquals(0, b.numChangedListenersForNext); + + assertEquals(0, c.numChangedListenersForName); + assertEquals(0, c.numChangedListenersForNext); + + assertEquals(0, d.numChangedListenersForName); + assertEquals(0, d.numChangedListenersForNext); + + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + } + + /** + * This test performs 10,000 random operations on the chain of a.b.c + * (setting different values for each step, sometimes doing multiple + * assignments between get() calls, random invalidate() calls). After each + * random iteration, we check to see if the listeners installed on the a, b, + * c objects are still correct. The goal is to catch any freak situations + * where we might have installed two listeners on the same property, or + * failed to remove a listener for a property under some circumstance. + * + * Do note that the only listeners that are installed in this method are + * done by the select binding. + */ + @SuppressWarnings("unchecked") + @Test + public void stressTestRandomOperationsResultInCorrectListenersInstalled() { + + final Level logLevel = Logging.getLogger().level(); + Logging.getLogger().setLevel(Level.SEVERE); + List steps = new ArrayList(); + + Random rand = new Random(System.currentTimeMillis()); + for (int i = 0; i < 10000; i++) { + switch (rand.nextInt(20)) { + case 0: + a.setNext(null); + steps.add("Assign a.value to null"); + break; + case 1: + a.setNext(b); + steps.add("Assign a.value to b"); + break; + case 2: + b.setNext(null); + steps.add("Assign b.value to null"); + break; + case 3: + b.setNext(c); + steps.add("Assign b.value to c"); + break; + case 4: + c.setNext(null); + steps.add("Assign c.value to null"); + break; + case 5: + c.setNext(d); + steps.add("Assign c.value to d"); + break; + case 6: + c.setName(null); + steps.add("Assign c.name to null"); + break; + case 7: + c.setName("c"); + steps.add("Assign c.name to 'c'"); + break; + default: + select.get(); + steps.add("Call select.get()"); + } + + // Now validate that the listeners are as we expected + int expected = 1; + int depsCount = expected; + assertEquals(0, a.numChangedListenersForName); + if (expected != a.numChangedListenersForNext) { + printSteps(i, steps); + } + assertEquals(expected, a.numChangedListenersForNext); + + expected = select.isValid() && a.getNext() == b ? 1 : 0; + depsCount += expected; + assertEquals(0, b.numChangedListenersForName); + if (expected != b.numChangedListenersForNext) { + printSteps(i, steps); + } + assertEquals(expected, b.numChangedListenersForNext); + + expected = select.isValid() && a.getNext() == b && b.getNext() == c ? 1 : 0; + depsCount += expected; + assertEquals(0, c.numChangedListenersForNext); + if (expected != c.numChangedListenersForName) { + printSteps(i, steps); + } + assertEquals(expected, c.numChangedListenersForName); + + assertEquals(0, d.numChangedListenersForName); + assertEquals(0, d.numChangedListenersForNext); + + switch (depsCount) { + case 0: + case 1: + assertEquals(Arrays.asList(a.nextProperty()), dependencies); + break; + case 2: + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty()), dependencies); + break; + case 3: + assertEquals(Arrays.asList(a.nextProperty(), b.nextProperty(), c.nameProperty()), dependencies); + break; + default: + fail("Should not reach here"); + } + } + Logging.getLogger().setLevel(logLevel); + } + + private void printSteps(int iteration, List steps) { + System.err.println("Failed on iteration " + iteration + " for the following observableArrayList of changes"); + for (String s : steps) { + System.err.println("\t" + s); + } + } +}