/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 de.unioninvestment.eai.portal.portlet.crud.domain.model;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonMap;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.vaadin.data.Item;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.util.sqlcontainer.RowId;
import de.unioninvestment.eai.portal.portlet.crud.config.ColumnsConfig;
import de.unioninvestment.eai.portal.portlet.crud.config.TableConfig;
import de.unioninvestment.eai.portal.portlet.crud.domain.container.GeneratedColumnsDataStreamWrapper;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.ModeChangeEvent;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.ModeChangeEventHandler;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.RowChangeEvent;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.RowChangeEventHandler;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.SelectionEvent;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.SelectionEventHandler;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.TableDoubleClickEvent;
import de.unioninvestment.eai.portal.portlet.crud.domain.events.TableDoubleClickEventHandler;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.DataContainer.ExportWithExportSettings;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.Table.DisplayMode;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.Table.DynamicColumnChanges;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.Table.Mode;
import de.unioninvestment.eai.portal.portlet.crud.domain.model.container.DataStream;
import de.unioninvestment.eai.portal.portlet.crud.domain.support.EmptyColumnGenerator;
public class TableTest {
@Mock
private Panel panelMock;
@Captor
private ArgumentCaptor<ModeChangeEvent<Table, Mode>> modeChangeEventCaptor;
@Captor
private ArgumentCaptor<ModeChangeEvent<Table, DisplayMode>> displayModeChangeEventCaptor;
@Captor
private ArgumentCaptor<SelectionEvent> selectionChangeEventCaptor;
@Captor
private ArgumentCaptor<TableDoubleClickEvent> tableDoubleClickEventCaptor;
private TableColumns tableColumns = new TableColumns(
new ArrayList<TableColumn>());
private TableConfig config = new TableConfig();
private Table table;
@Mock
private ModeChangeEventHandler<Table, Mode> modeChangeListenerMock;
@Mock
private SelectionEventHandler selectionChangeListenerMock;
@Mock
private TableDoubleClickEventHandler doubleClickEventHandler;
private Set<ContainerRowId> selectionRowId = new HashSet<ContainerRowId>();
@Mock
private RowId rowIdMock;
@Mock
private DataContainer containerMock;
@Mock
private RowChangeEventHandler rowChangeEventHandlerMock;
@Mock
private ContainerRow containerRowMock;
@Mock
private ContainerRowId containerRowIdMock;
@Mock
private Item itemMock;
@Mock
private RowEditableChecker rowEditableCheckerMock;
@Mock
private RowDeletableChecker rowDeletableCheckerMock;
@Mock
private Table.Presenter presenterMock;
@Mock
private ExportWithExportSettings exportMock;
@Mock
private Portlet portletMock;
@Mock
private ModeChangeEventHandler<Table, DisplayMode> displayModeChangeEventHandlerMock;
@Mock
private DataStream containerStreamMock;
@Mock
private Validator rowValidatorMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
config.setRowHeight(20);
table = new Table(config, tableColumns, containerMock, true, false);
table.setPresenter(presenterMock);
table.setPanel(panelMock);
when(panelMock.getPortlet()).thenReturn(portletMock);
}
@Test
public void shouldReturnEditableByConditions() {
verifyEditable(true, true, false, false, true);
verifyEditable(true, false, true, false, true);
verifyEditable(true, false, false, true, true);
verifyEditable(true, false, false, false, false);
verifyEditable(false, true, true, true, false);
}
private void verifyEditable(boolean tableEditable,
boolean containerInsertable, boolean containerUpdateable,
boolean containerDeletable, boolean expectEditable) {
when(containerMock.isInsertable()).thenReturn(containerInsertable);
when(containerMock.isUpdateable()).thenReturn(containerUpdateable);
when(containerMock.isDeleteable()).thenReturn(containerDeletable);
table = new Table(config, tableColumns, containerMock, tableEditable, false);
assertEquals(expectEditable, table.isEditable());
}
@Test
public void shouldReturnEditableCheckerResult() {
when(rowEditableCheckerMock.isEditable(containerRowMock)).thenReturn(
false);
table.setRowEditableChecker(rowEditableCheckerMock);
table.setRowDeletableChecker(rowDeletableCheckerMock);
when(containerMock.isUpdateable()).thenReturn(true);
boolean result = table.isRowEditable(containerRowMock);
verify(rowEditableCheckerMock).isEditable(containerRowMock);
assertThat(result, is(false));
}
@Test
public void shouldReturnRowIsNotEditableAsDefault() {
when(containerMock.isUpdateable()).thenReturn(true);
assertThat(table.isRowEditable(containerRowMock), is(true));
table = new Table(config, tableColumns, containerMock, false, false);
assertThat(table.isRowEditable(containerRowMock), is(false));
}
@Test
public void shouldReturnDeletableCheckerResult() {
when(containerMock.getRow(containerRowIdMock, false, true)).thenReturn(
containerRowMock);
when(rowDeletableCheckerMock.isDeletable(containerRowMock)).thenReturn(
false);
table.setRowDeletableChecker(rowDeletableCheckerMock);
boolean result = table.isRowDeletable(containerRowIdMock);
verify(rowDeletableCheckerMock).isDeletable(containerRowMock);
assertThat(result, is(false));
}
@Test
public void shouldReturnRowIsDeletableAsDefault() {
table = new Table(config, tableColumns, containerMock, false, true);
assertThat(table.isRowDeletable(containerRowIdMock), is(true));
}
@Test
public void shouldProvidePageReference() {
table.setPanel(panelMock);
assertThat(table.getPanel(), is(panelMock));
}
@Test
public void shouldIgnoreConfiguredRowHeightOnMissingColumns() {
assertThat(table.getRowHeight(), is(nullValue()));
}
@Test
public void shouldReturnConfiguredColumnHeight() {
config.setColumns(new ColumnsConfig());
assertThat(table.getRowHeight(), is(20));
}
@Test
public void shouldFireModeChangeEvent() {
table.addModeChangeEventHandler(modeChangeListenerMock);
table.changeMode(Mode.EDIT);
verify(modeChangeListenerMock).onModeChange(
modeChangeEventCaptor.capture());
assertThat(modeChangeEventCaptor.getValue().getSource(),
is((Object) table));
assertThat(modeChangeEventCaptor.getValue().getMode(),
is((Object) Mode.EDIT));
}
@Test
public void shouldNotFireModeChangeEventIfNothingChanges() {
table.addModeChangeEventHandler(modeChangeListenerMock);
table.changeMode(Mode.VIEW);
verifyZeroInteractions(modeChangeListenerMock);
}
@Test
public void shouldChangeModes() {
assertThat(table.getMode(), is(Mode.VIEW));
table.changeMode();
assertThat(table.getMode(), is(Mode.EDIT));
table.changeMode();
assertThat(table.getMode(), is(Mode.VIEW));
}
@Test
public void shouldChangeDisplayModes() {
config.setEditForm(true);
table = new Table(config, tableColumns, containerMock, true, false);
assertThat(table.getDisplayMode(), is(DisplayMode.TABLE));
table.changeDisplayMode();
assertThat(table.getDisplayMode(), is(DisplayMode.FORM));
table.changeDisplayMode();
assertThat(table.getDisplayMode(), is(DisplayMode.TABLE));
}
@Test
public void shouldFireEventOnDisplayModeChange() {
config.setEditForm(true);
table = new Table(config, tableColumns, containerMock, true, false);
table.addDisplayModeChangeEventHandler(displayModeChangeEventHandlerMock);
table.changeDisplayMode(DisplayMode.FORM);
verifyDisplayModeChangeEvent(table, DisplayMode.FORM);
}
@Test(expected = IllegalStateException.class)
public void shouldFailChangingDisplayModesIfFormEditIsNotEnabled() {
config.setEditForm(false);
table = new Table(config, tableColumns, containerMock, true, false);
table.changeDisplayMode(DisplayMode.FORM);
}
@Test
public void shouldNotFireEventWhenDisplayModeAlreadySet() {
table.addDisplayModeChangeEventHandler(displayModeChangeEventHandlerMock);
table.changeDisplayMode(DisplayMode.TABLE);
verifyZeroInteractions(displayModeChangeEventHandlerMock);
}
@Test
public void shouldFireSelectionChangeEvent() {
table.addSelectionEventHandler(selectionChangeListenerMock);
when(rowIdMock.getId()).thenReturn(new Object[]{1, 2});
selectionRowId.add(new DatabaseContainerRowId(rowIdMock, asList("ID",
"INDEX")));
table.changeSelection(selectionRowId);
verifySelectionChangeEvent(table, selectionRowId);
}
private void verifySelectionChangeEvent(Table expectedTable,
Set<ContainerRowId> expectedSelection) {
verify(selectionChangeListenerMock).onSelectionChange(
selectionChangeEventCaptor.capture());
assertThat(selectionChangeEventCaptor.getValue().getSource(),
is((Object) expectedTable));
assertThat(selectionChangeEventCaptor.getValue().getSelection(),
equalTo(expectedSelection));
}
@Test
public void shouldFireDoubleClickEventIfHandlerIsRegistered() {
table.addDoubleClickEventHandler(doubleClickEventHandler);
table.doubleClick(containerRowMock);
verifyDoubleClickEvent(table, containerRowMock);
}
private void verifyDoubleClickEvent(Table expectedTable,
ContainerRow expectedRow) {
verify(doubleClickEventHandler).onDoubleClick(
tableDoubleClickEventCaptor.capture());
assertThat(tableDoubleClickEventCaptor.getValue().getSource(),
is(expectedTable));
assertThat(tableDoubleClickEventCaptor.getValue().getRow(),
is(expectedRow));
}
@Test
public void shouldSwitchToFormViewAndChangeSelectionOnDoubleClickWithFormEditing() {
table.addDisplayModeChangeEventHandler(displayModeChangeEventHandlerMock);
table.addSelectionEventHandler(selectionChangeListenerMock);
when(containerRowMock.getId()).thenReturn(containerRowIdMock);
verifySwitchToFormViewAndSelectionChangeOnDoubleClick(Mode.VIEW, false,
false, false, false, false);
verifySwitchToFormViewAndSelectionChangeOnDoubleClick(Mode.VIEW, false,
false, false, false, false);
verifySwitchToFormViewAndSelectionChangeOnDoubleClick(Mode.VIEW, true,
true, true, false, false);
verifySwitchToFormViewAndSelectionChangeOnDoubleClick(Mode.VIEW, false,
true, false, true, true);
verifySwitchToFormViewAndSelectionChangeOnDoubleClick(Mode.EDIT, true,
true, false, true, false); // selection already changed
}
private void verifySwitchToFormViewAndSelectionChangeOnDoubleClick(
Mode mode, boolean hasDoubleClickHandler, boolean editForm,
boolean shouldFireDoubleClickEvent, boolean shouldSwitch,
boolean shouldFireSelectionChange) {
table.removeDoubleClickEventHandler(doubleClickEventHandler);
if (hasDoubleClickHandler) {
table.addDoubleClickEventHandler(doubleClickEventHandler);
}
config.setEditForm(editForm);
table.mode = mode;
table.displayMode = DisplayMode.TABLE;
reset(doubleClickEventHandler, displayModeChangeEventHandlerMock,
selectionChangeListenerMock);
table.doubleClick(containerRowMock);
if (hasDoubleClickHandler && shouldFireDoubleClickEvent) {
verifyDoubleClickEvent(table, containerRowMock);
} else if (hasDoubleClickHandler) {
verifyZeroInteractions(doubleClickEventHandler);
}
if (shouldSwitch) {
verifyDisplayModeChangeEvent(table, DisplayMode.FORM);
} else {
verifyZeroInteractions(displayModeChangeEventHandlerMock);
}
if (shouldFireSelectionChange) {
verifySelectionChangeEvent(table, singleton(containerRowIdMock));
} else {
verifyZeroInteractions(selectionChangeListenerMock);
}
}
private void verifyDisplayModeChangeEvent(Table expectedTable,
DisplayMode expectedDisplayMode) {
verify(displayModeChangeEventHandlerMock).onModeChange(
displayModeChangeEventCaptor.capture());
assertThat(displayModeChangeEventCaptor.getValue().getSource(),
is(expectedTable));
assertThat(displayModeChangeEventCaptor.getValue().getMode(),
is(expectedDisplayMode));
}
@Test
public void shouldCallRefreshOnDBContainer() {
table.refresh();
verify(containerMock).refresh();
}
@Test
public void shouldFireRowChangeEvent() {
table.addRowChangeEventHandler(rowChangeEventHandlerMock);
Map<String, Object> changedValues = singletonMap("NAME",
(Object) "VALUE");
when(containerMock.getRow(containerRowIdMock, false, false))
.thenReturn(containerRowMock);
table.rowChange(containerRowIdMock, changedValues);
ArgumentCaptor<RowChangeEvent> eventCaptor = ArgumentCaptor
.forClass(RowChangeEvent.class);
verify(rowChangeEventHandlerMock).rowChange(eventCaptor.capture());
assertThat(eventCaptor.getValue().getSource(), is(containerRowMock));
assertThat(eventCaptor.getValue().getChangedValues(), is(changedValues));
}
@Test
public void shouldDelegateAddGeneratedColumn() {
when(portletMock.allowsDisplayGeneratedContent()).thenReturn(true);
com.vaadin.ui.Table.ColumnGenerator columnGenerator = mock(com.vaadin.ui.Table.ColumnGenerator.class);
table.addGeneratedColumn("id", "name", columnGenerator);
verify(presenterMock).addGeneratedColumn("id", "name", columnGenerator);
}
@Test
public void shouldAddEmptyGeneratedColumnIfPermissionIsMissing() {
when(portletMock.allowsDisplayGeneratedContent()).thenReturn(false);
com.vaadin.ui.Table.ColumnGenerator columnGenerator = mock(com.vaadin.ui.Table.ColumnGenerator.class);
table.addGeneratedColumn("id", "name", columnGenerator);
verify(presenterMock).addGeneratedColumn(eq("id"), eq("name"),
isA(EmptyColumnGenerator.class));
}
@Test
public void shouldDelegateRemoveGeneratedColumn() {
table.removeGeneratedColumn("id");
verify(presenterMock).removeGeneratedColumn("id");
}
@Test
public void shouldDelegateGetRowByItemId() {
ContainerRow rowMock = mock(ContainerRow.class);
when(table.getRowByItemId("id")).thenReturn(rowMock);
ContainerRow rowResult = table.getRowByItemId("id");
assertThat(rowResult, is(sameInstance(rowMock)));
}
@Test
public void shouldDelegateRenderOnce() {
DynamicColumnChanges changesMock = mock(DynamicColumnChanges.class);
table.renderOnce(changesMock);
verify(presenterMock).renderOnce(changesMock);
}
@Test
public void shouldDelegateHasGeneratedColumn() {
table.hasGeneratedColumn("id");
verify(presenterMock).hasGeneratedColumn("id");
}
@Test
public void shouldDelegateClearAllGeneratedColumns() {
table.clearAllGeneratedColumns();
verify(presenterMock).clearAllGeneratedColumns();
}
@Test
public void shouldDelegateGetVisibleColumns() {
table.getVisibleColumns();
verify(presenterMock).getVisibleColumns();
}
@Test
public void shouldDelegateSetVisibleColumns() {
List<String> visibleColumns = asList("1", "2");
table.setVisibleColumns(visibleColumns);
verify(presenterMock).setVisibleColumns(visibleColumns);
}
@Test
public void shouldDelegateCreateNewRow() {
Map<String, Object> values = emptyMap();
table.createNewRow(values);
verify(presenterMock).createNewRow(values);
}
@Test
public void shouldDelegateWithExportSettings() {
table.withExportSettings(exportMock);
verify(containerMock).withExportSettings(exportMock);
}
@Test
public void shouldStartInViewModeByDefault() {
assertThat(table.getMode(), is(Mode.VIEW));
}
@Test
public void shouldStartInEditModeIfSeparateModeIsDisabled() {
when(containerMock.isInsertable()).thenReturn(true);
table = new Table(config, tableColumns, containerMock, true, true);
assertThat(table.getMode(), is(Mode.EDIT));
}
@Test
public void shouldNotStartInEditModeIfSeparateModeIsDisabledButContainerIsReadonly() {
when(containerMock.isInsertable()).thenReturn(false);
when(containerMock.isUpdateable()).thenReturn(false);
when(containerMock.isDeleteable()).thenReturn(false);
table = new Table(config, tableColumns, containerMock, true, true);
assertThat(table.getMode(), is(Mode.VIEW));
}
@Test
public void shouldStartInViewModeIfSeparateModeIsDisabledAndNotEditable() {
table = new Table(config, tableColumns, containerMock, false, true);
assertThat(table.getMode(), is(Mode.VIEW));
}
@Test
public void shouldPassThroughContainerStreamIfNoGeneratedColumns() {
table = new Table(config, null, containerMock, true, false);
when(containerMock.getStream()).thenReturn(containerStreamMock);
assertThat(table.getStream(), sameInstance(containerStreamMock));
}
@Test
public void shouldWrapContainerStreamForGeneratedColumns() {
when(containerMock.getStream()).thenReturn(containerStreamMock);
DataStream tableStream = table.getStream();
assertThat(tableStream, instanceOf(GeneratedColumnsDataStreamWrapper.class));
}
@Test
public void shouldNotValidateTheGivenRowIfItDidntChangeAndAValidatorIsRegistered() {
table.setRowValidator(rowValidatorMock);
when(containerMock.getRow(containerRowIdMock, false, true)).thenReturn(containerRowMock);
doThrow(new InvalidValueException("Test")).when(rowValidatorMock).validate(containerRowMock);
table.validateIfChanged(containerRowIdMock);
verifyZeroInteractions(rowValidatorMock);
}
@Test
public void shouldNotValidateTheGivenRowIfNoAValidatorIsRegistered() {
when(containerMock.getRow(containerRowIdMock, false, true)).thenReturn(containerRowMock);
doThrow(new InvalidValueException("Test")).when(rowValidatorMock).validate(containerRowMock);
when(containerRowMock.isModified()).thenReturn(true);
table.validateIfChanged(containerRowIdMock);
}
@Test(expected=InvalidValueException.class)
public void shouldValidateTheGivenRowIfItHasChangedAndAValidatorIsRegistered() {
table.setRowValidator(rowValidatorMock);
when(containerMock.getRow(containerRowIdMock, false, true)).thenReturn(containerRowMock);
doThrow(new InvalidValueException("Test")).when(rowValidatorMock).validate(containerRowMock);
when(containerRowMock.isModified()).thenReturn(true);
table.validateIfChanged(containerRowIdMock);
}
@Test(expected=InvalidValueException.class)
public void shouldValidateTheGivenRowIfItIsNewAndAValidatorIsRegistered() {
table.setRowValidator(rowValidatorMock);
when(containerMock.getRow(containerRowIdMock, false, true)).thenReturn(containerRowMock);
doThrow(new InvalidValueException("Test")).when(rowValidatorMock).validate(containerRowMock);
when(containerRowMock.isNewItem()).thenReturn(true);
table.validateIfChanged(containerRowIdMock);
}
}