package com.vaadin.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.vaadin.tests.data.bean.BeanWithEnums;
import com.vaadin.tests.data.bean.Sex;
import com.vaadin.tests.data.bean.TestEnum;
import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.MultiSelect;
import com.vaadin.ui.components.grid.MultiSelectionModelImpl;
public class GridAsMultiSelectInBinderTest
extends BinderTestBase<Binder<BeanWithEnums>, BeanWithEnums> {
public class TestEnumSetToStringConverter
implements Converter<Set<TestEnum>, String> {
@Override
public Result<String> convertToModel(Set<TestEnum> value,
ValueContext context) {
return Result.ok(value.stream().map(TestEnum::name)
.collect(Collectors.joining(",")));
}
@Override
public Set<TestEnum> convertToPresentation(String value,
ValueContext context) {
return Stream.of(value.split(","))
.filter(string -> !string.isEmpty()).map(TestEnum::valueOf)
.collect(Collectors.toSet());
}
}
private class CustomMultiSelectModel extends MultiSelectionModelImpl<Sex> {
@Override
public void updateSelection(Set<Sex> addedItems, Set<Sex> removedItems,
boolean userOriginated) {
super.updateSelection(addedItems, removedItems, userOriginated);
}
}
private Binder<AtomicReference<String>> converterBinder = new Binder<>();
private Grid<TestEnum> grid;
private MultiSelect<TestEnum> select;
@Before
public void setUp() {
binder = new Binder<>();
item = new BeanWithEnums();
grid = new Grid<>();
grid.setItems(TestEnum.values());
grid.setSelectionMode(SelectionMode.MULTI);
select = grid.asMultiSelect();
converterBinder.forField(select)
.withConverter(new TestEnumSetToStringConverter())
.bind(AtomicReference::get, AtomicReference::set);
}
@Test(expected = IllegalStateException.class)
public void boundGridInBinder_selectionModelChanged_throws() {
grid.setSelectionMode(SelectionMode.SINGLE);
select.select(TestEnum.ONE);
}
@Test
public void beanBound_bindSelectByShortcut_selectionUpdated() {
item.setEnums(Collections.singleton(TestEnum.ONE));
binder.setBean(item);
binder.bind(select, BeanWithEnums::getEnums, BeanWithEnums::setEnums);
assertEquals(Collections.singleton(TestEnum.ONE),
select.getSelectedItems());
}
@Test
public void beanBound_bindSelect_selectionUpdated() {
item.setEnums(Collections.singleton(TestEnum.TWO));
binder.setBean(item);
binder.forField(select).bind(BeanWithEnums::getEnums,
BeanWithEnums::setEnums);
assertEquals(Collections.singleton(TestEnum.TWO),
select.getSelectedItems());
}
@Test
public void selectBound_bindBeanWithoutEnums_selectedItemNotPresent() {
bindEnum();
assertTrue(select.getSelectedItems().isEmpty());
}
@Test
public void selectBound_bindBean_selectionUpdated() {
item.setEnums(Collections.singleton(TestEnum.ONE));
bindEnum();
assertEquals(Collections.singleton(TestEnum.ONE),
select.getSelectedItems());
}
@Test
public void bound_setSelection_beanValueUpdated() {
bindEnum();
select.select(TestEnum.TWO);
assertEquals(Collections.singleton(TestEnum.TWO), item.getEnums());
}
@Test
public void bound_setSelection_beanValueIsACopy() {
bindEnum();
select.select(TestEnum.TWO);
Set<TestEnum> enums = item.getEnums();
binder.setBean(new BeanWithEnums());
select.select(TestEnum.ONE);
assertEquals(Collections.singleton(TestEnum.TWO), enums);
}
@Test
public void bound_deselect_beanValueUpdatedToNull() {
item.setEnums(Collections.singleton(TestEnum.ONE));
bindEnum();
select.deselect(TestEnum.ONE);
assertTrue(item.getEnums().isEmpty());
}
@Test
public void unbound_changeSelection_beanValueNotUpdated() {
item.setEnums(Collections.singleton(TestEnum.ONE));
bindEnum();
binder.removeBean();
select.select(TestEnum.TWO);
assertEquals(Collections.singleton(TestEnum.ONE), item.getEnums());
}
@Test
public void withConverter_load_selectUpdated() {
converterBinder.readBean(new AtomicReference<>("TWO"));
assertEquals(Collections.singleton(TestEnum.TWO),
select.getSelectedItems());
}
@Test
public void withConverter_save_referenceUpdated() {
select.select(TestEnum.ONE);
select.select(TestEnum.TWO);
AtomicReference<String> reference = new AtomicReference<>("");
converterBinder.writeBeanIfValid(reference);
assertEquals("ONE,TWO", reference.get());
}
@Test
public void withValidator_validate_validatorUsed() {
binder.forField(select)
.withValidator(selection -> selection.size() % 2 == 1,
"Must select odd number of items")
.bind(BeanWithEnums::getEnums, BeanWithEnums::setEnums);
binder.setBean(item);
assertFalse(binder.validate().isOk());
select.select(TestEnum.TWO);
assertTrue(binder.validate().isOk());
}
@Test
public void addValueChangeListener_selectionUpdated_eventTriggeredForMultiSelect() {
CustomMultiSelectModel model = new CustomMultiSelectModel();
Grid<Sex> grid = new Grid<Sex>() {
{
setSelectionModel(model);
}
};
grid.setItems(Sex.values());
MultiSelect<Sex> select = grid.asMultiSelect();
List<Sex> selected = new ArrayList<>();
List<Boolean> userOriginated = new ArrayList<>();
select.addValueChangeListener(event -> {
selected.addAll(event.getValue());
userOriginated.add(event.isUserOriginated());
assertSame(grid, event.getComponent());
// cannot compare that the event source is the select since a new
// MultiSelect wrapper object has been created for the event
assertEquals(select.getValue(), event.getValue());
});
select.select(Sex.UNKNOWN);
assertEquals(Arrays.asList(Sex.UNKNOWN), selected);
model.updateSelection(new LinkedHashSet<>(Arrays.asList(Sex.MALE)),
Collections.emptySet(), true); // simulate client side selection
assertEquals(Arrays.asList(Sex.UNKNOWN, Sex.UNKNOWN, Sex.MALE),
selected);
selected.clear();
select.select(Sex.MALE); // NOOP
assertEquals(Arrays.asList(), selected);
selected.clear();
// client side deselect
model.updateSelection(Collections.emptySet(),
new LinkedHashSet<>(Arrays.asList(Sex.UNKNOWN)), true);
assertEquals(Arrays.asList(Sex.MALE), selected);
selected.clear();
select.deselect(Sex.UNKNOWN); // NOOP
assertEquals(Arrays.asList(), selected);
selected.clear();
select.deselect(Sex.FEMALE, Sex.MALE); // partly NOOP
assertEquals(Arrays.asList(), selected);
model.selectItems(Sex.FEMALE, Sex.MALE);
assertEquals(Arrays.asList(Sex.FEMALE, Sex.MALE), selected);
selected.clear();
model.updateSelection(new LinkedHashSet<>(Arrays.asList(Sex.FEMALE)),
Collections.emptySet(), true); // client side NOOP
assertEquals(Arrays.asList(), selected);
assertEquals(Arrays.asList(false, true, true, false, false),
userOriginated);
}
protected void bindEnum() {
binder.forField(select).bind(BeanWithEnums::getEnums,
BeanWithEnums::setEnums);
binder.setBean(item);
}
}