/*
* 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.");
}
}