package org.tessell.tests.model.properties;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.tessell.model.properties.NewProperty.booleanProperty;
import static org.tessell.model.properties.NewProperty.integerProperty;
import static org.tessell.model.properties.NewProperty.stringProperty;
import org.junit.Before;
import org.junit.Test;
import org.tessell.model.dsl.Binder;
import org.tessell.model.events.PropertyChangedEvent;
import org.tessell.model.events.PropertyChangedHandler;
import org.tessell.model.properties.IntegerProperty;
import org.tessell.model.properties.Property;
import org.tessell.model.properties.StringProperty;
import org.tessell.model.validation.rules.Range;
import org.tessell.model.values.DerivedValue;
import org.tessell.tests.model.validation.rules.AbstractRuleTest;
import org.tessell.widgets.StubHasValue;
public class DerivedPropertiesTest extends AbstractRuleTest {
public static class Foo {
public StringProperty name = stringProperty("name").max(10);
}
private final Foo f = new Foo();
@Before
public void listenToName() {
listenTo(f.name);
}
@Test
public void derivedFiresChangedWhenSourceDoes() {
final CountChanged<Integer> count = new CountChanged<Integer>();
f.name.remaining().addPropertyChangedHandler(count);
assertThat(count.count, is(0));
f.name.set("foo");
assertThat(count.count, is(1));
}
@Test
public void derivedItselfDoesNotFireChangedIfPropertyAlreadySet() {
f.name.set("foo");
final CountChanged<Integer> count = new CountChanged<Integer>();
f.name.remaining().addPropertyChangedHandler(count);
assertThat(count.count, is(0));
}
@Test
public void binderDoesFireChangedIfPropertyAlreadySet() {
f.name.set("foo");
final StubHasValue<Integer> value = new StubHasValue<Integer>();
Binder b = new Binder();
b.bind(f.name.remaining()).to(value);
assertThat(value.getValue(), is(7));
}
@Test
public void derivedDoesNotReFireIfValueHasNotChanged() {
final CountChanged<Integer> count = new CountChanged<Integer>();
f.name.remaining().addPropertyChangedHandler(count);
f.name.set("foo");
assertThat(count.count, is(1));
f.name.set("bar");
assertThat(count.count, is(1)); // still 1
}
@Test(expected = IllegalStateException.class)
public void derivedPropertiesCannotBeSet() {
f.name.remaining().set(10);
}
@Test
public void derivedCanHaveRules() {
// listen to the derived property
final IntegerProperty length = f.name.length();
length.addRule(new Range("invalid range", 0, 5));
listenTo(length);
f.name.set("123456");
assertMessages("invalid range");
f.name.set("12345");
assertMessages("");
}
@Test
public void userDerivedWillGetChangeEvents() {
final StringProperty parent = stringProperty("parent", "");
final Property<Boolean> logic = booleanProperty(new DerivedValue<Boolean>() {
public Boolean get() {
return parent.get().length() > 0;
}
}).depends(parent);
final CountChanged<Boolean> c = new CountChanged<Boolean>();
logic.addPropertyChangedHandler(c);
parent.set("asdf");
assertThat(c.count, is(1));
}
@Test
public void implicitDepends() {
final IntegerProperty a = integerProperty("a", 1);
final IntegerProperty b = integerProperty(new DerivedValue<Integer>("b") {
public Integer get() {
return a.get() == null ? null : a.get() + 3;
}
});
final CountChanged<Integer> c = new CountChanged<Integer>();
b.addPropertyChangedHandler(c);
a.set(2);
assertThat(c.count, is(1));
}
@Test
public void implicitDependsWithMultipleDependencies() {
final IntegerProperty a = integerProperty("a", null);
final IntegerProperty b = integerProperty("b", null);
final IntegerProperty c = integerProperty(new DerivedValue<Integer>("c") {
public Integer get() {
return a.get() == null ? 0 : b.get() == null ? 1 : 3;
}
});
final CountChanged<Integer> count = new CountChanged<Integer>();
c.addPropertyChangedHandler(count);
a.set(2);
assertThat(count.count, is(1));
b.set(2);
assertThat(count.count, is(2));
}
private class CountChanged<P> implements PropertyChangedHandler<P> {
private int count;
@Override
public void onPropertyChanged(final PropertyChangedEvent<P> event) {
count++;
}
}
}