/* * Copyright (C) 2011 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.databinding.client.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.jboss.errai.databinding.client.IdentityConverter; import org.jboss.errai.databinding.client.TestModel; import org.jboss.errai.databinding.client.api.Convert; import org.jboss.errai.databinding.client.api.Converter; import org.jboss.errai.databinding.client.api.DataBinder; import org.jboss.errai.databinding.client.api.StateSync; import org.jboss.errai.ioc.client.test.AbstractErraiIOCTest; import org.junit.Test; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; /** * Tests functionality related to the use of {@link Converter}s for data binding. * * @author Christian Sadilek <csadilek@redhat.com> */ public class ConverterIntegrationTest extends AbstractErraiIOCTest { @Override public String getModuleName() { return "org.jboss.errai.databinding.DataBindingTestModule"; } @Override protected void gwtSetUp() throws Exception { Convert.deregisterDefaultConverters(); super.gwtSetUp(); } @Test public void testBindingSpecificConverter() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1701; } @Override public String toWidgetValue(final Integer modelValue) { return "testCustomConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age", converter).getModel(); textBox.setValue("321", true); assertEquals("Model not properly updated using custom converter", Integer.valueOf(1701), model.getAge()); model.setAge(123); assertEquals("Widget not properly updated using custom converter", "testCustomConverter", textBox.getText()); } @Test public void testBindingSpecificConverterAndNullValues() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return ("".equals(widgetValue)) ? -1 : 0; } @Override public String toWidgetValue(final Integer modelValue) { return (modelValue == null) ? "null-widget" : modelValue.toString(); } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age", converter).getModel(); // Set initial non-empty value so that value change handlers are called on the next call. textBox.setValue("1337", false); textBox.setValue(null, true); assertEquals("Model not properly updated using custom converter", Integer.valueOf(-1), model.getAge()); model.setAge(null); assertEquals("Widget not properly updated using custom converter", "null-widget", textBox.getText()); } @Test public void testBinderRetainsConverterAfterModelInstanceChange() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1701; } @Override public String toWidgetValue(final Integer modelValue) { return "testCustomConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final TextBox textBox = new TextBox(); final DataBinder<TestModel> binder = DataBinder.forType(TestModel.class).bind(textBox, "age", converter); final TestModel oldModel = binder.getModel(); binder.setModel(new TestModel()); textBox.setValue("321", true); assertEquals("Model not properly updated using custom converter", Integer.valueOf(1701), binder.getModel().getAge()); binder.getModel().setAge(123); assertEquals("Widget not properly updated using custom converter", "testCustomConverter", textBox.getText()); assertEquals("Original model should not have been updated", null, oldModel.getAge()); } @Test public void testBindingSpecificConverterForReadOnlyField() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { throw new UnsupportedOperationException("Should never be called!"); } @Override public String toWidgetValue(final Integer modelValue) { return "test"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final Label label = new Label(); final TestModel model = DataBinder.forModel(new TestModel()) .bind(label, "age", converter).getModel(); model.setAge(123); assertEquals("Widget not properly updated using custom converter", "test", label.getText()); } @Test public void testBindingWithGlobalDefaultConverter() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1701; } @Override public String toWidgetValue(final Integer modelValue) { return "testGlobalDefaultConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; Convert.registerDefaultConverter(Integer.class, String.class, converter); final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age").getModel(); textBox.setValue("321", true); assertEquals("Model not properly updated using global default converter", Integer.valueOf(1701), model.getAge()); model.setAge(123); assertEquals("Widget not properly updated using global default converter", "testGlobalDefaultConverter", textBox.getText()); } @Test public void testBindingWithGlobalDefaultConverterAndNullValues() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return ("".equals(widgetValue)) ? -1 : 0; } @Override public String toWidgetValue(final Integer modelValue) { return (modelValue == null) ? "null-widget" : modelValue.toString(); } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; Convert.registerDefaultConverter(Integer.class, String.class, converter); final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age").getModel(); // Set initial non-empty value so that value change handlers are called on the next call. textBox.setValue("1337", false); textBox.setValue(null, true); assertEquals("Model not properly updated using global default converter", Integer.valueOf(-1), model.getAge()); model.setAge(null); assertEquals("Widget not properly updated using global default converter", "null-widget", textBox.getText()); } @Test public void testBindingWithAutoRegisteredDefaultConverter() { final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "active").getModel(); textBox.setValue("123", true); assertEquals("Model not properly updated using global default converter", true, model.isActive()); model.setActive(false); assertEquals("Widget not properly updated using global default converter", "AutoRegisteredDefaultConverter", textBox.getText()); } @Test public void testOverrideGlobalDefaultConverter() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1701; } @Override public String toWidgetValue(final Integer modelValue) { return "globalDefaultConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; Convert.registerDefaultConverter(Integer.class, String.class, converter); final Converter<Integer, String> bindingConverter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1; } @Override public String toWidgetValue(final Integer modelValue) { return "bindingSpecificConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final TextBox textBox = new TextBox(); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age", bindingConverter).getModel(); textBox.setValue("321", true); assertEquals("Model not properly updated using custom converter", Integer.valueOf(1), model.getAge()); model.setAge(123); assertEquals("Widget not properly updated using custom converter", "bindingSpecificConverter", textBox.getText()); } @Test public void testInitialStateSyncWithConverter() { final Converter<Integer, String> converter = new Converter<Integer, String>() { @Override public Integer toModelValue(final String widgetValue) { return 1701; } @Override public String toWidgetValue(final Integer modelValue) { return "customConverter"; } @Override public Class<Integer> getModelType() { return Integer.class; } @Override public Class<String> getComponentType() { return String.class; } }; final TextBox textBox = new TextBox(); textBox.setValue("123"); final DataBinder<TestModel> binder = DataBinder.forType(TestModel.class).bind(textBox, "age", converter, StateSync.FROM_UI); assertEquals("Model not initialized based on widget's state", Integer.valueOf(1701), binder.getModel().getAge()); final TestModel model = new TestModel(); model.setAge(123); DataBinder.forModel(model).bind(textBox, "name", new IdentityConverter<String>(String.class) { @Override public String toWidgetValue(final String modelValue) { return "customConverter"; } }, StateSync.FROM_MODEL); assertEquals("Model not initialized based on widget's state", "customConverter", textBox.getValue()); } @Test public void testEmptyStringConversionToBigInteger() { final TextBox textBox = new TextBox(); textBox.setText("test"); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "amountInt").getModel(); textBox.setValue("", true); assertEquals("Failed to convert empty String to BigInteger", null, model.getAmountInt()); } @Test public void testEmptyStringConversionToBigDecimal() { final TextBox textBox = new TextBox(); textBox.setText("test"); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "amountDec").getModel(); textBox.setValue("", true); assertEquals("Failed to convert empty String to BigDecimal", null, model.getAmountDec()); } @Test public void testEmptyStringConversionToPrimitiveWrapper() { final TextBox textBox = new TextBox(); textBox.setText("test"); final TestModel model = DataBinder.forType(TestModel.class).bind(textBox, "age").getModel(); textBox.setValue("", true); assertEquals("Failed to convert empty String to primitive wrapper type", null, model.getAge()); } @Test public void testBindingListWithConverter() throws Exception { final TextBox textBox = new TextBox(); final DataBinder<List<String>> binder = DataBinder.forListOfType(String.class); final Converter<Collection<String>, String> converter = new Converter<Collection<String>, String>() { @SuppressWarnings("unchecked") @Override public Class<Collection<String>> getModelType() { return (Class) Collection.class; } @Override public Class<String> getComponentType() { return String.class; } @Override public Collection<String> toModelValue(final String componentValue) { final List<String> retVal = new ArrayList<>(); for (int i = 0; i < componentValue.length(); i++) { retVal.add(componentValue.substring(i, i+1)); } return retVal; } @Override public String toWidgetValue(final Collection<String> modelValue) { final StringBuilder builder = new StringBuilder(); modelValue.forEach(s -> builder.append(s)); return builder.toString(); } }; binder.bind(textBox, "this", converter); binder.getModel().add("A"); binder.getModel().add("B"); binder.getModel().add("C"); assertEquals("ABC", textBox.getValue()); textBox.setValue("CBA", true); assertEquals(Arrays.asList("C", "B", "A"), binder.getModel()); } }