/* * Copyright (C) 2016 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 static org.jboss.errai.databinding.client.components.ListComponent.forIsWidgetComponent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.jboss.errai.databinding.client.DirectBindingListComponentModule; import org.jboss.errai.databinding.client.ListComponentContainerModule; import org.jboss.errai.databinding.client.ListComponentModule; import org.jboss.errai.databinding.client.QualifiedListComponentModule; import org.jboss.errai.databinding.client.TestModel; import org.jboss.errai.databinding.client.TestModelWidget; import org.jboss.errai.databinding.client.TestModelWithList; import org.jboss.errai.databinding.client.TestModelWithListOfTestModels; import org.jboss.errai.databinding.client.TestModelWithListWidget; import org.jboss.errai.databinding.client.api.Convert; import org.jboss.errai.databinding.client.api.DataBinder; import org.jboss.errai.databinding.client.api.StateSync; import org.jboss.errai.databinding.client.components.ListComponent; import org.jboss.errai.ioc.client.container.IOC; import org.jboss.errai.ioc.client.test.AbstractErraiIOCTest; import org.jboss.errai.marshalling.client.api.MarshallerFramework; /** * Tests binding to lists with the {@link DataBinder}. * * @author Max Barkley <mbarkley@redhat.com> */ public class ListBindingIntegrationTest extends AbstractErraiIOCTest { @Override public String getModuleName() { return "org.jboss.errai.databinding.DataBindingTestModule"; } @Override protected void gwtSetUp() throws Exception { super.gwtSetUp(); Convert.deregisterDefaultConverters(); MarshallerFramework.initializeDefaultSessionProvider(); } public void testListHandlerBindingToListProperty() throws Exception { final ListComponent<TestModel, TestModelWidget> component = forIsWidgetComponent(TestModelWidget::new, c -> {}).inDiv(); final TestModelWithListOfTestModels model = DataBinder.forType(TestModelWithListOfTestModels.class) .bind(component, "list", Convert.identityConverter(List.class)).getModel(); model.setList(new ArrayList<>()); final List<TestModel> list = model.getList(); final TestModel one = new TestModel("one"); final TestModel two = new TestModel("two"); final TestModel three = new TestModel("three"); runTestModelListAssertions(list, component, one, two, three); } public void testDeclarativeListHandlerBindingWithInjectedListComponent() throws Exception { final ListComponentModule module = IOC.getBeanManager().lookupBean(ListComponentModule.class).getInstance(); final ListComponent<TestModel, TestModelWidget> component = module.list; final TestModelWithListOfTestModels model = module.binder.getModel(); model.setList(new ArrayList<>()); final List<TestModel> list = model.getList(); final TestModel one = new TestModel("one"); final TestModel two = new TestModel("two"); final TestModel three = new TestModel("three"); list.add(one); assertFalse(component.getComponent(0).isQualified()); assertIndexOutOfBounds(component, 1); list.remove(0); assertIndexOutOfBounds(component, 0); runTestModelListAssertions(list, component, one, two, three); } public void testDeclarativeListHandlerBindingWithInjectedListDestroyerCallAfterRemove() throws Exception { final ListComponentModule module = IOC.getBeanManager().lookupBean(ListComponentModule.class).getInstance(); final ListComponent<TestModel, TestModelWidget> component = module.list; final TestModelWithListOfTestModels model = module.binder.getModel(); model.setList(new ArrayList<>()); final List<TestModel> list = model.getList(); final TestModel one = new TestModel("one"); list.add(one); TestModelWidget testBean = component.getComponent(0); assertFalse(component.getComponent(0).isQualified()); assertIndexOutOfBounds(component, 1); assertFalse(testBean.isDestroyed()); list.remove(0); assertTrue(testBean.isDestroyed()); assertIndexOutOfBounds(component, 0); } public void testDeclarativeBindingDirectlyToList() throws Exception { final DirectBindingListComponentModule module = IOC.getBeanManager() .lookupBean(DirectBindingListComponentModule.class).getInstance(); final ListComponent<TestModel, TestModelWidget> component = module.list; final List<TestModel> list = module.binder.getModel(); final TestModel one = new TestModel("one"); final TestModel two = new TestModel("two"); final TestModel three = new TestModel("three"); list.add(one); assertFalse(component.getComponent(0).isQualified()); assertIndexOutOfBounds(component, 1); list.remove(0); assertIndexOutOfBounds(component, 0); runTestModelListAssertions(list, component, one, two, three); } public void testListComponentElementTypesThroughIOC() throws Exception { final ListComponentContainerModule module = IOC.getBeanManager().lookupBean(ListComponentContainerModule.class).getInstance(); assertEquals("div", module.defaultComponent.getElement().getTagName().toLowerCase()); assertEquals("tbody", module.tableComponent.getElement().getTagName().toLowerCase()); } public void testDeclarativeQualifiedListHandlerBindingWithInjectedListComponent() throws Exception { final QualifiedListComponentModule module = IOC.getBeanManager().lookupBean(QualifiedListComponentModule.class).getInstance(); final ListComponent<TestModel, TestModelWidget> component = module.list; final TestModelWithListOfTestModels model = module.binder.getModel(); model.setList(new ArrayList<>()); final List<TestModel> list = model.getList(); final TestModel one = new TestModel("one"); list.add(one); assertTrue(component.getComponent(0).isQualified()); assertIndexOutOfBounds(component, 1); } public void testListHandlerBindingToListDirectly() throws Exception { final ListComponent<TestModel, TestModelWidget> component = forIsWidgetComponent(TestModelWidget::new, c -> {}).inDiv(); final List<TestModel> list = DataBinder.forListOfType(TestModel.class) .bind(component, "this", Convert.identityConverter(List.class)).getModel(); final TestModel one = new TestModel("one"); final TestModel two = new TestModel("two"); final TestModel three = new TestModel("three"); runTestModelListAssertions(list, component, one, two, three); } public void testListHandlerPauseAndResume() throws Exception { final ListComponent<TestModel, TestModelWidget> component = forIsWidgetComponent(TestModelWidget::new, c -> {}).inDiv(); final DataBinder<List<TestModel>> binder = DataBinder.forListOfType(TestModel.class) .bind(component, "this", Convert.identityConverter(List.class)); final TestModel one = new TestModel("one"); final TestModel two = new TestModel("two"); binder.getModel().add(one); assertEquals("Binding failed before pause called.", binder.getModel(), component.getValue()); binder.pause(); binder.getModel().add(two); assertEquals("Component was updated after binding paused.", Collections.singletonList(one), component.getValue()); binder.resume(StateSync.FROM_MODEL); assertEquals(Arrays.asList(one, two), binder.getModel()); assertEquals("Component not updated after resume.", binder.getModel(), component.getValue()); binder.pause(); binder.getModel().clear(); assertEquals("Component was updated after binding paused.", Arrays.asList(one, two), component.getValue()); binder.resume(StateSync.FROM_UI); assertEquals(Arrays.asList(one, two), component.getValue()); assertEquals(component.getValue(), binder.getModel()); } public void testListHasValueBindingToListProperty() throws Exception { final TestModelWithListWidget component = new TestModelWithListWidget(); final TestModelWithList model = DataBinder.forType(TestModelWithList.class) .bind(component, "list", Convert.identityConverter(List.class)).getModel(); model.setList(new ArrayList<>()); final List<String> list = model.getList(); runStringListAssertions(component, list, "one", "two", "three"); } public void testListHasValueBindingToListDirectly() throws Exception { final TestModelWithListWidget component = new TestModelWithListWidget(); final List<String> list = DataBinder.forListOfType(String.class) .bind(component, "this", Convert.identityConverter(String.class)).getModel(); runStringListAssertions(component, list, "one", "two", "three"); } private void runStringListAssertions(final TestModelWithListWidget component, final List<String> list, final String one, final String two, final String three) { list.add(one); assertEquals(list, component.getValue()); list.add(three); assertEquals(list, component.getValue()); list.add(1, two); assertEquals(list, component.getValue()); list.remove(2); assertEquals(list, component.getValue()); list.removeAll(Collections.singleton(two)); assertEquals(list, component.getValue()); list.addAll(Collections.singleton(three)); assertEquals(list, component.getValue()); list.addAll(1, Collections.singleton(two)); assertEquals(list, component.getValue()); list.clear(); assertEquals(list, component.getValue()); } private void runTestModelListAssertions(final List<TestModel> boundList, final ListComponent<TestModel, TestModelWidget> component, final TestModel one, final TestModel two, final TestModel three) { assertIndexOutOfBounds(component, 0); boundList.add(one); assertEquals(one, component.getComponent(0).getValue()); assertIndexOutOfBounds(component, 1); boundList.add(three); assertEquals(one, component.getComponent(0).getValue()); assertEquals(three, component.getComponent(1).getValue()); assertIndexOutOfBounds(component, 2); boundList.add(1, two); assertEquals(one, component.getComponent(0).getValue()); assertEquals(two, component.getComponent(1).getValue()); assertEquals(three, component.getComponent(2).getValue()); assertIndexOutOfBounds(component, 3); boundList.remove(2); assertEquals(one, component.getComponent(0).getValue()); assertEquals(two, component.getComponent(1).getValue()); assertIndexOutOfBounds(component, 2); boundList.removeAll(Collections.singleton(two)); assertEquals(one, component.getComponent(0).getValue()); assertIndexOutOfBounds(component, 1); boundList.addAll(Collections.singleton(three)); assertEquals(one, component.getComponent(0).getValue()); assertEquals(three, component.getComponent(1).getValue()); assertIndexOutOfBounds(component, 2); boundList.addAll(1, Collections.singleton(two)); assertEquals(one, component.getComponent(0).getValue()); assertEquals(two, component.getComponent(1).getValue()); assertEquals(three, component.getComponent(2).getValue()); assertIndexOutOfBounds(component, 3); boundList.get(0).setValue("one!"); assertEquals(one, component.getComponent(0).getValue()); assertEquals(two, component.getComponent(1).getValue()); assertEquals(three, component.getComponent(2).getValue()); assertIndexOutOfBounds(component, 3); boundList.clear(); assertIndexOutOfBounds(component, 0); } private static void assertIndexOutOfBounds(final ListComponent<TestModel, TestModelWidget> component, final int index) { try { component.getComponent(index); } catch (IndexOutOfBoundsException ex) { return; } fail("Index " + index + " was not out of bounds."); } }