blob: ef32a424a86848c37e341fb11d18544de1768543 [file] [log] [blame]
package org.eclipse.fx.core.property;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.fx.core.Subscription;
import org.eclipse.fx.core.Status.State;
import org.eclipse.fx.core.bindings.FXBindings;
import org.eclipse.fx.core.bindings.FXBindings.StatusBinding;
import org.junit.Assert;
import org.junit.Test;
import javafx.beans.binding.ListBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
public class FXBindingsTest {
public static class Inner {
public final StringProperty Value;
public Inner(String blub) {
this.Value = new SimpleStringProperty(blub);
}
}
public static class Outer {
public ObjectProperty<Inner> Value = new SimpleObjectProperty<>();
}
public static class Person {
private static int i;
private final StringProperty name;
private ObjectProperty<Address> address = new SimpleObjectProperty<>();
public Person() {
this.name = new SimpleStringProperty(this, "name", i++ + "");
}
public Person(String name) {
this.name = new SimpleStringProperty(this, "name", name);
}
}
public static class Address {
private StringProperty street = new SimpleStringProperty();
}
@Test
public void testBindStream() {
Outer outer = new Outer();
Inner inner = new Inner("Hello");
outer.Value.set(inner);
ObjectProperty<Outer> master = new SimpleObjectProperty<Outer>(outer);
ObjectBinding<String> m2 = FXBindings.bindStream(master).map(o -> o.Value).map(i -> i.Value).toBinding();
Assert.assertEquals("Hello", m2.get());
inner.Value.set("test1");
Assert.assertEquals("test1", m2.get());
Inner inner2 = new Inner("test2");
outer.Value.set(inner2);
Assert.assertEquals("test2", m2.get());
Outer outer2 = new Outer();
Inner inner3 = new Inner("test3");
outer2.Value.set(inner3);
master.set(outer2);
Assert.assertEquals("test3", m2.get());
ObjectProperty<Person> p = new SimpleObjectProperty<>( new Person() );
ObjectBinding<String> street = FXBindings.bindStream( p ).map( o -> o.address).map( o -> o.street).toBinding();
Property<String> streetProperty = FXBindings.bindStream( p ).map( o -> o.address).toProperty( o -> o.street);
Assert.assertNull(street.get());
Address a = new Address();
p.get().address.set(a);
Assert.assertNull(street.get());
p.get().address.get().street.set("Test");
Assert.assertEquals("Test",street.get());
Assert.assertEquals("Test",streetProperty.getValue());
streetProperty.setValue("Super geil 1");
Assert.assertEquals("Super geil 1",street.get());
Address a2 = new Address();
a2.street.set("Bla");
p.get().address.set(a2);
Assert.assertEquals("Bla",street.get());
streetProperty.setValue("Super geil 2");
Assert.assertEquals("Super geil 2",street.get());
Assert.assertEquals(a.street.get(), "Super geil 1");
Assert.assertEquals(a2.street.get(), "Super geil 2");
StringProperty uiProp = new SimpleStringProperty();
uiProp.bindBidirectional(streetProperty);
Assert.assertEquals("Super geil 2", uiProp.get());
streetProperty.setValue("ui value");
Assert.assertEquals("ui value", uiProp.get());
uiProp.set("back to model");
Assert.assertEquals("back to model", a2.street.get());
}
@Test
public void testGC() {
ObjectProperty<Person> p = new SimpleObjectProperty<>( new Person() );
ObjectBinding<String> street = FXBindings.bindStream( p ).map( o -> o.address).map( o -> o.street).toBinding();
Property<String> streetProperty = FXBindings.bindStream( p ).map( o -> o.address).toProperty( o -> o.street);
System.gc();
Assert.assertNull(street.get());
Address a = new Address();
p.get().address.set(a);
Assert.assertNull(street.get());
p.get().address.get().street.set("Test");
Assert.assertEquals("Test",street.get());
Assert.assertEquals("Test",streetProperty.getValue());
streetProperty.setValue("Super geil 1");
Assert.assertEquals("Super geil 1",street.get());
}
@Test
public void testNullRoot() {
ObjectProperty<Person> p = new SimpleObjectProperty<>( new Person() );
p.get().address.set(new Address());
p.get().address.get().street.set("Street");
Property<String> streetProperty = FXBindings.bindStream( p ).map( o -> o.address).toProperty( o -> o.street);
p.set(null);
Assert.assertNull(streetProperty.getValue());
Person p2 = new Person();
Address a2 = new Address();
a2.street.set("New Street");
p2.address.set(a2);
p.set(p2);
Assert.assertNotNull(streetProperty.getValue());
p2.address.set(null);
Assert.assertNull(streetProperty.getValue());
Address a3 = new Address();
a3.street.set("New New Street");
p2.address.set(a3);
Assert.assertNotNull(streetProperty.getValue());
}
@Test
public void testHop0() {
ObjectProperty<Person> currentPerson = new SimpleObjectProperty<>();
ObjectBinding<Person> binding = FXBindings.bindStream(currentPerson).toBinding();
Assert.assertNull(binding.get());
Person p1 = new Person();
currentPerson.set(p1);
Assert.assertSame(p1,binding.get());
Person p2 = new Person();
currentPerson.set(p2);
Assert.assertSame(p2,binding.get());
}
@Test
public void testListenerInit() {
ObjectProperty<Person> currentPerson = new SimpleObjectProperty<>();
ObjectBinding<Person> binding = FXBindings.bindStream(currentPerson).toBinding();
AtomicInteger i = new AtomicInteger();
binding.addListener( o -> {
i.incrementAndGet();
});
Assert.assertEquals(0, i.get());
Person p1 = new Person();
currentPerson.set(p1);
Assert.assertEquals(1, i.get());
}
@Test
public void testListenerInitComplex() {
ObjectProperty<Person> currentPerson = new SimpleObjectProperty<>();
ObjectBinding<Address> binding = FXBindings.bindStream(currentPerson).map( p -> p.address).toBinding();
AtomicInteger i = new AtomicInteger();
binding.addListener( o -> {
i.incrementAndGet();
});
Assert.assertEquals(0, i.get());
Person p1 = new Person();
currentPerson.set(p1);
Assert.assertEquals(1, i.get());
}
@Test
public void testMap() {
ObjectProperty<String> master = new SimpleObjectProperty<String>("Test");
ObjectBinding<String> map = FXBindings.map(master, x -> "Hallo " + x);
Assert.assertEquals("Hallo Test", map.get());
master.set("Foo");
Assert.assertEquals("Hallo Foo", map.get());
}
@Test
public void testFlatMap() {
Outer outer = new Outer();
Inner inner = new Inner("Hello");
outer.Value.set(inner);
ObjectProperty<Outer> master = new SimpleObjectProperty<Outer>(outer);
ObjectBinding<Inner> m1 = FXBindings.flatMap(master, o -> o.Value);
ObjectBinding<String> m2 = FXBindings.flatMap(m1, i -> i.Value);
Assert.assertEquals("Hello", m2.get());
inner.Value.set("test1");
Assert.assertEquals("test1", m2.get());
Inner inner2 = new Inner("test2");
outer.Value.set(inner2);
Assert.assertEquals("test2", m2.get());
Outer outer2 = new Outer();
Inner inner3 = new Inner("test3");
outer2.Value.set(inner3);
master.set(outer2);
Assert.assertEquals("test3", m2.get());
}
@Test
public void testConcat() {
ObservableList<String> l0 = FXCollections.observableArrayList();
ObservableList<String> l1 = FXCollections.observableArrayList();
ObservableList<String> l2 = FXCollections.observableArrayList();
ListBinding<String> concat = FXBindings.concat(l0, l1, l2);
Assert.assertEquals(0, concat.size());
l1.add("Hello");
Assert.assertArrayEquals(new String[] {
"Hello"
}, concat.toArray());
l2.add("World");
Assert.assertArrayEquals(new String[] {
"Hello",
"World"
}, concat.toArray());
l0.add("yay");
Assert.assertArrayEquals(new String[] {
"yay",
"Hello",
"World"
}, concat.toArray());
l0.add("!!!");
Assert.assertArrayEquals(new String[] {
"yay",
"!!!",
"Hello",
"World"
}, concat.toArray());
l0.remove("!!!");
Assert.assertArrayEquals(new String[] {
"yay",
"Hello",
"World"
}, concat.toArray());
l0.remove("yay");
Assert.assertArrayEquals(new String[] {
"Hello",
"World"
}, concat.toArray());
l2.remove("World");
Assert.assertArrayEquals(new String[] {
"Hello"
}, concat.toArray());
l1.remove("Hello");
Assert.assertEquals(0, concat.size());
}
@Test
public void testMapList() {
ObservableList<String> source = FXCollections.observableArrayList("one", "two", "three");
ListBinding<String> result = FXBindings.mapList(source, s -> s + " apples");
Assert.assertArrayEquals(new String[] {
"one apples",
"two apples",
"three apples"
}, result.toArray());
source.set(1, "99");
Assert.assertArrayEquals(new String[] {
"one apples",
"99 apples",
"three apples"
}, result.toArray());
source.add("another");
Assert.assertArrayEquals(new String[] {
"one apples",
"99 apples",
"three apples",
"another apples"
}, result.toArray());
source.remove("one");
Assert.assertArrayEquals(new String[] {
"99 apples",
"three apples",
"another apples"
}, result.toArray());
}
@Test
public void testFlatMapList() {
ObservableList<String> one = FXCollections.observableArrayList("1", "2", "3");
ObservableList<String> two = FXCollections.observableArrayList();
ObservableList<String> three = FXCollections.observableArrayList("a", "b", "c");
ObservableList<ObservableList<String>> source = FXCollections.observableArrayList(one, two, three);
ListBinding<String> flatMap = FXBindings.flatMapList(source, x->x);
Assert.assertArrayEquals(new String[] {
"1", "2", "3", "a", "b", "c"
}, flatMap.toArray());
two.add("two");
Assert.assertArrayEquals(new String[] {
"1", "2", "3", "two", "a", "b", "c"
}, flatMap.toArray());
one.set(1, "xx");
Assert.assertArrayEquals(new String[] {
"1", "xx", "3", "two", "a", "b", "c"
}, flatMap.toArray());
three.remove(1);
Assert.assertArrayEquals(new String[] {
"1", "xx", "3", "two", "a", "c"
}, flatMap.toArray());
source.remove(one);
Assert.assertArrayEquals(new String[] {
"two", "a", "c"
}, flatMap.toArray());
one.add("offline");
Assert.assertArrayEquals(new String[] {
"two", "a", "c"
}, flatMap.toArray());
source.add(one);
Assert.assertArrayEquals(new String[] {
"two", "a", "c", "1", "xx", "3", "offline"
}, flatMap.toArray());
}
@Test
public void testFlatMapListValue() {
StringProperty a = new SimpleStringProperty("a");
StringProperty b = new SimpleStringProperty("b");
StringProperty c = new SimpleStringProperty("c");
ObservableList<ObservableValue<String>> source = FXCollections.observableArrayList(a, b, c);
ListBinding<String> flatMap = FXBindings.flatMapListValue(source, x->x);
Assert.assertArrayEquals(new String[] {
"a", "b", "c"
}, flatMap.toArray());
source.remove(b);
Assert.assertArrayEquals(new String[] {
"a", "c"
}, flatMap.toArray());
b.set("B");
Assert.assertArrayEquals(new String[] {
"a", "c"
}, flatMap.toArray());
source.add(b);
Assert.assertArrayEquals(new String[] {
"a", "c", "B"
}, flatMap.toArray());
a.set("A");
Assert.assertArrayEquals(new String[] {
"A", "c", "B"
}, flatMap.toArray());
}
@Test
public void testBindingPaddedContent() {
List<String> target = new ArrayList<>();
ObservableList<Integer> sourceList = FXCollections.observableArrayList(1,2,3);
Subscription binding = FXBindings.bindContent(1, target, sourceList, o -> "Converted " + o, i -> "Pad " + i);
Assert.assertEquals(4, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 1, target.get(1));
Assert.assertEquals("Converted " + 2, target.get(2));
Assert.assertEquals("Converted " + 3, target.get(3));
// binding.setPadding(0);
// Assert.assertEquals(3, target.size());
// Assert.assertEquals("Converted " + 1, target.get(0));
// Assert.assertEquals("Converted " + 2, target.get(1));
// Assert.assertEquals("Converted " + 3, target.get(2));
//
// binding.setPadding(1);
//
// Assert.assertEquals(4, target.size());
// Assert.assertEquals("Pad " + 0, target.get(0));
// Assert.assertEquals("Converted " + 1, target.get(1));
// Assert.assertEquals("Converted " + 2, target.get(2));
// Assert.assertEquals("Converted " + 3, target.get(3));
//
// binding.setPadding(2);
//
// Assert.assertEquals(5, target.size());
// Assert.assertEquals("Pad " + 0, target.get(0));
// Assert.assertEquals("Pad " + 1, target.get(1));
// Assert.assertEquals("Converted " + 1, target.get(2));
// Assert.assertEquals("Converted " + 2, target.get(3));
// Assert.assertEquals("Converted " + 3, target.get(4));
}
@Test
public void testBindingPaddedContent_AddRemove() {
List<String> target = new ArrayList<>();
ObservableList<Integer> sourceList = FXCollections.observableArrayList(1,2,3);
Subscription binding = FXBindings.bindContent(1, target, sourceList, o -> "Converted " + o, i -> "Pad " + i);
Assert.assertEquals(4, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 1, target.get(1));
Assert.assertEquals("Converted " + 2, target.get(2));
Assert.assertEquals("Converted " + 3, target.get(3));
sourceList.add(0,0);
Assert.assertEquals(5, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 0, target.get(1));
Assert.assertEquals("Converted " + 1, target.get(2));
Assert.assertEquals("Converted " + 2, target.get(3));
Assert.assertEquals("Converted " + 3, target.get(4));
sourceList.remove(0);
Assert.assertEquals(4, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 1, target.get(1));
Assert.assertEquals("Converted " + 2, target.get(2));
Assert.assertEquals("Converted " + 3, target.get(3));
}
@Test
public void testBindingPaddedContent_Permutate() {
List<String> target = new ArrayList<>();
SortedList<Integer> sourceList = FXCollections.observableArrayList(1,2,3).sorted((i1, i2) -> {
return Integer.compare(i1, i2) * -1;
});
Subscription binding = FXBindings.bindContent(1, target, sourceList, o -> "Converted " + o, i -> "Pad " + i);
Assert.assertEquals(4, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 3, target.get(1));
Assert.assertEquals("Converted " + 2, target.get(2));
Assert.assertEquals("Converted " + 1, target.get(3));
sourceList.setComparator( ( i1, i2 ) -> Integer.compare(i1, i2) );
Assert.assertEquals(4, target.size());
Assert.assertEquals("Pad " + 0, target.get(0));
Assert.assertEquals("Converted " + 1, target.get(1));
Assert.assertEquals("Converted " + 2, target.get(2));
Assert.assertEquals("Converted " + 3, target.get(3));
}
@Test
public void testBindBidirectional() {
Property<String> s = new SimpleStringProperty("99");
Property<Integer> i = new SimpleObjectProperty<Integer>();
StatusBinding binding = FXBindings.bindBidirectional(i, s, Integer.class, String.class);
Assert.assertEquals(99, i.getValue().intValue());
Assert.assertEquals(State.OK, binding.getValue().getState());
s.setValue("100");
Assert.assertEquals(100, i.getValue().intValue());
Assert.assertEquals(State.OK, binding.getValue().getState());
s.setValue("abcd");
Assert.assertEquals(100, i.getValue().intValue());
Assert.assertEquals(State.ERROR, binding.getValue().getState());
s.setValue("101");
Assert.assertEquals(101, i.getValue().intValue());
Assert.assertEquals(State.OK, binding.getValue().getState());
}
}