package org.tessell.tests.model.properties; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.tessell.model.properties.NewProperty.integerProperty; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.tessell.gwt.user.client.ui.StubTextBox; 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.PropertyFormatter; import org.tessell.tests.model.validation.rules.AbstractRuleTest; public class FormattedPropertyTest extends AbstractRuleTest { @Test public void get() { Property<String> p = integerProperty("i", 1).formatted(intToString); assertThat(p.get(), is("1")); } @Test public void testToString() { assertThat(integerProperty("i", 1).formatted(intToString).toString(), is("i 1")); } @Test public void setStringToInt() { IntegerProperty i = integerProperty("i", 1); Property<String> p = i.formatted(intToString); p.set("2"); assertThat(i.get(), is(2)); } @Test public void setBadString() { IntegerProperty i = integerProperty("i", 1); listenTo(i); Property<String> p = i.formatted(intToString); p.set("a"); assertMessages("I is invalid"); } @Test public void setBadStringThatIsRequired() { IntegerProperty i = integerProperty("i", 1).req(); listenTo(i); Property<String> p = i.formatted(intToString); p.set("a"); assertMessages("I is invalid"); // we keep the old value, because setting to null would send up // resetting the user's last-invalid attempt in the UI assertThat(i.get(), is(1)); i.set(2); assertNoMessages(); p.set(null); assertMessages("I is required"); } @Test public void setBadStringThatIsBoundToATextBox() { IntegerProperty i = integerProperty("i", 1).req(); Binder binder = new Binder(); StubTextBox box = new StubTextBox(); binder.bind(i.asString()).to(box); listenTo(i); box.type("a"); assertThat(box.getText(), is("a")); assertMessages("I must be an integer"); assertThat(i.get(), is(1)); assertThat(box.getText(), is("a")); i.set(2); assertNoMessages(); box.type(""); assertMessages("I is required"); } @Test public void setNull() { IntegerProperty i = integerProperty("i", 1); listenTo(i); i.asString().set(null); assertThat(i.get(), is(nullValue())); assertThat(i.isValid(), is(true)); } @Test public void setEmptyString() { IntegerProperty i = integerProperty("i", 1); listenTo(i); i.asString().set(""); assertThat(i.get(), is(nullValue())); assertThat(i.isValid(), is(true)); } @Test public void setThatFailsThenIsCorrected() { IntegerProperty i = integerProperty("i", 1); listenTo(i); Property<String> p = i.formatted(intToString); p.set("a"); assertMessages("I is invalid"); p.set("2"); assertMessages(""); } @Test public void setThatFailsThenIsCorrectedInOriginalProperty() { IntegerProperty i = integerProperty("i", 1); listenTo(i); Property<String> p = i.formatted(intToString); p.set("a"); assertMessages("I is invalid"); i.set(2); assertMessages(""); } @Test public void setThatFailsHasInvalidMessageTakePrecedenceOverRequired() { IntegerProperty i = integerProperty("i", null).req(); listenTo(i); i.asString().set("asdf"); assertMessages("I must be an integer"); } @Test public void sourceChangingMakesTheFormattedValueChange() { IntegerProperty i = integerProperty("i", 1); Property<String> p = i.formatted(intToString); ChangeTracker tracker = new ChangeTracker(); p.addPropertyChangedHandler(tracker); i.set(2); assertThat(tracker.values, contains("2")); } @Test public void setInitialLeavesSourcePropertyUntouched() { IntegerProperty i = integerProperty("i", 1); Property<String> p = i.formatted(intToString); p.setInitialValue("2"); assertThat(i.getValue(), is(2)); assertThat(i.isTouched(), is(false)); } @Test public void setInitialLeavesSourcePropertyUntouchedEvenOnErrors() { // note that this behavior seems right; but it's not // driven from real world usage IntegerProperty i = integerProperty("i", 1); Property<String> p = i.formatted(intToString); p.setInitialValue("blah"); assertThat(i.getValue(), is(1)); assertThat(i.isTouched(), is(false)); } @Test public void testRecursion() { IntegerProperty i = integerProperty("i", 1); Property<String> p1 = i.formatted(intToString); Property<Integer> p2 = p1.formatted(stringToInt); assertThat(p1.get(), is("1")); assertThat(p2.get().intValue(), is(1)); p2.set(2); assertThat(p1.get(), is("2")); assertThat(i.get().intValue(), is(2)); } @Test public void testCustomNullValue() { IntegerProperty i = integerProperty("i", 1); Property<String> s = i.formatted(new PropertyFormatter<Integer, String>() { public String format(Integer a) { return a.toString(); } public Integer parse(String b) throws Exception { return new Integer(b); } public String nullValue() { return "NULL"; } }); i.set(null); assertThat(s.get(), is("NULL")); } @Test public void testSettingInitialValueWhenBound() { IntegerProperty i = integerProperty("i"); Property<String> s = i.asString(); StubTextBox textBox = new StubTextBox(); Binder b = new Binder(); b.bind(s).to(textBox); i.setInitialValue(1); assertThat(i.isTouched(), is(false)); } @Test public void testSettingValueWithTouchIsFalseWhenBound() { IntegerProperty i = integerProperty("i"); Property<String> s = i.asString(); StubTextBox textBox = new StubTextBox(); Binder b = new Binder(); b.bind(s).to(textBox); i.set(1, false); assertThat(i.isTouched(), is(false)); } private final PropertyFormatter<Integer, String> intToString = new PropertyFormatter<Integer, String>() { @Override public String format(Integer a) { return a.toString(); } @Override public Integer parse(String b) { return Integer.parseInt(b); } }; private final PropertyFormatter<String, Integer> stringToInt = new PropertyFormatter<String, Integer>() { @Override public Integer format(String a) { return new Integer(a); } @Override public String parse(Integer i) { return i.toString(); } }; private class ChangeTracker implements PropertyChangedHandler<String> { private final List<String> values = new ArrayList<String>(); @Override public void onPropertyChanged(PropertyChangedEvent<String> event) { values.add(event.getProperty().get()); } } }