/*******************************************************************************
 * Copyright (c) 2012, 2020 Original authors and others.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Original authors and others - initial API and implementation
 ******************************************************************************/
package org.eclipse.nebula.widgets.nattable.selection;

import static org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum.RIGHT;
import static org.junit.Assert.assertEquals;

import java.util.Collection;

import org.eclipse.nebula.widgets.nattable.coordinate.PositionCoordinate;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand;
import org.eclipse.nebula.widgets.nattable.test.fixture.layer.DataLayerFixture;
import org.eclipse.nebula.widgets.nattable.util.ArrayUtil;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class CellSelectionTest {

    private SelectionLayer selectionLayer;
    private MoveCellSelectionCommandHandler moveCommandHandler;

    private ITraversalStrategy AXIS_TRAVERSAL_ALL = new ITraversalStrategy() {

        @Override
        public TraversalScope getTraversalScope() {
            return TraversalScope.AXIS;
        }

        @Override
        public boolean isCycle() {
            return false;
        }

        @Override
        public int getStepCount() {
            return SelectionLayer.MOVE_ALL;
        }

        @Override
        public boolean isValidTarget(ILayerCell from, ILayerCell to) {
            return true;
        }

    };

    @Before
    public void setUp() {
        this.selectionLayer = new SelectionLayer(new DataLayerFixture(10, 10, 100, 40));
        // Selection grid origin as starting point
        this.selectionLayer.setSelectedCell(0, 0);
        this.moveCommandHandler = new MoveCellSelectionCommandHandler(this.selectionLayer);
    }

    @After
    public void cleanUp() {
        this.selectionLayer.clear();
    }

    @Test
    public void shouldHaveOriginSelected() {
        Assert.assertTrue(isLastCellInOrigin());
    }

    private boolean isLastCellInOrigin() {
        return (0 == this.selectionLayer.getLastSelectedCellPosition().columnPosition && 0 == this.selectionLayer
                .getLastSelectedCellPosition().rowPosition);
    }

    private boolean isSelectonAnchorInOrigin() {
        return (0 == this.selectionLayer.getSelectionAnchor().columnPosition && 0 == this.selectionLayer
                .getSelectionAnchor().rowPosition);
    }

    private boolean wasPreviousSelectionCleared() {
        // Make sure previous selection was cleared
        return (this.selectionLayer.getSelectedColumnPositions().length == 1 && this.selectionLayer
                .getSelectedRowCount() == 1);
    }

    private boolean wasPreviousColumnSelectionAppended() {
        // Make sure previous column selection was not cleared
        return this.selectionLayer.getSelectedColumnPositions().length > 1;
    }

    private boolean wasPreviousRowSelectionAppended() {
        // Make sure previous column selection was not cleared
        return this.selectionLayer.getSelectedRowCount() > 1;
    }

    // Tests for cell selection NTBL-224

    @Test
    public void shouldMoveTheSelectionAnchorLeftUsingLeftArrowKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);
        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        this.selectionLayer.setSelectedCell(1, 0);

        // Should move back to origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);
        Assert.assertTrue(isLastCellInOrigin());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionToTheLeftUsingLeftArrowAndShiftKeys() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);
        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        this.selectionLayer.setSelectedCell(2, 0);

        // Should move back to origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);

        // Last selected cell should now be the origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);
        Assert.assertTrue(isLastCellInOrigin());

        // Selection anchor should not have changed
        Assert.assertEquals(2, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousColumnSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorRightUsingRightArrowKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.RIGHT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);

        // Previous selection was cleared and origin should no longer be
        // selected
        Assert.assertFalse(isLastCellInOrigin());

        // The selection anchor moved right
        Assert.assertEquals(1, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionRightUsingRightArrowAndShiftKeys() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.RIGHT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.RIGHT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);

        // Since selection started at origin, then origin should be part of the
        // selected range
        Assert.assertTrue(isSelectonAnchorInOrigin());

        // Selection should now end on the cell to the right of the selection
        // anchor
        Assert.assertEquals(2, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousColumnSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorUpUsingUpArrowKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);

        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        this.selectionLayer.setSelectedCell(0, 2);

        // Should move back to origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);
        Assert.assertTrue(isLastCellInOrigin());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionUpUsingUpArrowAndShiftKeys() {
        this.selectionLayer.setSelectedCell(0, 1);
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);

        // Anchor should not have changed
        Assert.assertEquals(1, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());

        // Last selected cell should be the origin
        Assert.assertTrue(isLastCellInOrigin());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousRowSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorDownUsingDownArrowKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.DOWN, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);

        // Previous selection was cleared and origin should no longer be
        // selected
        Assert.assertFalse(isLastCellInOrigin());

        // Las selected cell is one step below origin
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(1, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionDownUsingDownArrowAndShiftKeys() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.DOWN, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, true, false);

        // Selection anchor remains at origing
        Assert.assertTrue(isSelectonAnchorInOrigin());

        // Las selected cell is one step below origin
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(1, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousRowSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelecitonAnchorToStartOfRowUsingHomeKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, this.AXIS_TRAVERSAL_ALL, false, false);

        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        // Move to middle of grid
        this.selectionLayer.setSelectedCell(2, 0);

        // Should move back to origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, this.AXIS_TRAVERSAL_ALL, false, false);
        Assert.assertTrue(isLastCellInOrigin());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionToStartOfRowUsingHomeAndShiftKeys() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, this.AXIS_TRAVERSAL_ALL, true, false);

        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        // Move to middle of grid
        this.selectionLayer.setSelectedCell(2, 0);

        // Should move back to origin
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.LEFT, this.AXIS_TRAVERSAL_ALL, true, false);
        Assert.assertTrue(isLastCellInOrigin());

        // Selection anchor should not have changed
        Assert.assertEquals(2, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousColumnSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorToEndOfRowUsingEndKey() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.RIGHT, this.AXIS_TRAVERSAL_ALL, false, false);

        // Selection anchor moved to end of grid
        Assert.assertEquals(9, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());

        // Previous selection was cleared and origin should no longer be
        // selected
        Assert.assertFalse(isLastCellInOrigin());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendTheSelectionToEndOfRowUsingEndAndShiftKeys() {
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.RIGHT, this.AXIS_TRAVERSAL_ALL, true, false);

        // Selection anchor should stay at the origin
        Assert.assertTrue(isSelectonAnchorInOrigin());

        // Last selected cell is at end of grid
        Assert.assertEquals(9, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousColumnSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorOnePageUpUsingPageUpKey() {
        ITraversalStrategy customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 6;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, customTraversal, false, false);

        // Should not have moved
        Assert.assertTrue(isLastCellInOrigin());

        // Move to middle of grid
        final int columnPosition = 2;
        final int rowPosition = 4;
        this.selectionLayer.setSelectedCell(columnPosition, rowPosition);

        customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 10;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        // Should not have moved
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, customTraversal, false, false);

        // Previous selection was cleared and origin should no longer be
        // selected
        Assert.assertFalse(isLastCellInOrigin());

        customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 60;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        // Should move back to first row event if step size is greater than
        // available number of rows
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, customTraversal, false, false);
        Assert.assertEquals(2, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendSelectionOnePageUpUsingThePageUpAndShiftKeys() {
        ITraversalStrategy customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 10;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        // Move to middle of grid
        final int columnPosition = 2;
        final int rowPosition = 4;
        this.selectionLayer.setSelectedCell(columnPosition, rowPosition);

        // Should move back to first row event if step size is greater than
        // available number of rows
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.UP, customTraversal, true, false);
        Assert.assertEquals(2, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Selection anchor should not have changed
        Assert.assertEquals(2, this.selectionLayer.getSelectionAnchor()
                .getColumnPosition());
        Assert.assertEquals(4, this.selectionLayer.getSelectionAnchor()
                .getRowPosition());

        // Cells in between should have been appended
        Assert.assertTrue(wasPreviousRowSelectionAppended());
    }

    @Test
    public void shouldMoveTheSelectionAnchorOnePageDownUsingPageDownKey() {
        ITraversalStrategy customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 6;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.DOWN, customTraversal, false, false);

        customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 60;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        // Should move to last row even if step size is greater than available
        // number of rows
        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.DOWN, customTraversal, false, false);
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(9, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousSelectionCleared());
    }

    @Test
    public void shouldExtendSelectionOnePageDownUsingPageDownAndShiftKeys() {
        ITraversalStrategy customTraversal = new ITraversalStrategy() {

            @Override
            public TraversalScope getTraversalScope() {
                return TraversalScope.AXIS;
            }

            @Override
            public boolean isCycle() {
                return false;
            }

            @Override
            public int getStepCount() {
                return 6;
            }

            @Override
            public boolean isValidTarget(ILayerCell from, ILayerCell to) {
                return true;
            }

        };

        this.moveCommandHandler.moveSelection(
                MoveDirectionEnum.DOWN, customTraversal, true, false);

        // Selection anchor should not have changed
        Assert.assertTrue(isSelectonAnchorInOrigin());

        // Last selected cell should be in the last row
        Assert.assertEquals(0, this.selectionLayer.getLastSelectedCellPosition()
                .getColumnPosition());
        Assert.assertEquals(6, this.selectionLayer.getLastSelectedCellPosition()
                .getRowPosition());

        // Previous selection was cleared
        Assert.assertTrue(wasPreviousRowSelectionAppended());
    }

    /**
     * If a range of cells is selected - clear selection and move anchor to the
     * next cell in the direction moved
     */
    @Test
    public void moveCellWhenARangeOfCellsIsSelected() throws Exception {

        new SelectColumnCommandHandler(this.selectionLayer).selectColumn(2, 0,
                false, false);
        this.moveCommandHandler.moveSelection(
                RIGHT, ITraversalStrategy.AXIS_TRAVERSAL_STRATEGY, false, false);

        assertEquals(3, this.selectionLayer.getSelectionAnchor().columnPosition);
        assertEquals(0, this.selectionLayer.getSelectionAnchor().rowPosition);
    }

    /**
     * Selected cells are (col,row): (2,3),(4,1),(1,0),(9,9)
     */
    @Test
    public void shouldReturnTheCorrectCountOfSelectedCells() {
        this.selectionLayer.clear();
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 3,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 4, 1,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 1, 0,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 9, 9,
                false, true));

        PositionCoordinate[] cells = this.selectionLayer.getSelectedCellPositions();
        Assert.assertEquals(4, cells.length);
        // (1, 0)
        Assert.assertEquals(1, cells[0].columnPosition);
        Assert.assertEquals(0, cells[0].rowPosition);
        // (2, 3)
        Assert.assertEquals(2, cells[1].columnPosition);
        Assert.assertEquals(3, cells[1].rowPosition);
        // (4, 1)
        Assert.assertEquals(4, cells[2].columnPosition);
        Assert.assertEquals(1, cells[2].rowPosition);
        // (9, 9)
        Assert.assertEquals(9, cells[3].columnPosition);
        Assert.assertEquals(9, cells[3].rowPosition);
    }

    @Test
    public void shouldReturnSixCells() {
        this.selectionLayer.clear();
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 1, 0,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 0,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 1, 1,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 1,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 1, 2,
                false, true));
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 2,
                false, true));

        Collection<PositionCoordinate> cells = ArrayUtil
                .asCollection(this.selectionLayer.getSelectedCellPositions());

        Assert.assertEquals(6, cells.size());
        // (1, 0)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                1, 0)));
        // (1, 1)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                1, 1)));
        // (1, 2)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                1, 2)));
        // (2, 0)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 0)));
        // (2, 1)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 1)));
        // (2, 2)
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 2)));
    }

    @Test
    public void onlyOneCellSelectedAtAnyTime() {
        this.selectionLayer.getSelectionModel().setMultipleSelectionAllowed(false);

        this.selectionLayer.clear();
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 1, 0,
                false, true));

        Collection<PositionCoordinate> cells = ArrayUtil
                .asCollection(this.selectionLayer.getSelectedCellPositions());
        Assert.assertEquals(1, cells.size());
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                1, 0)));

        // select another cell with control mask
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 0,
                false, true));

        cells = ArrayUtil.asCollection(this.selectionLayer
                .getSelectedCellPositions());
        Assert.assertEquals(1, cells.size());
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 0)));

        // select additional cells with shift mask
        // only the first cell should be selected afterwards
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 2, 10,
                true, false));

        cells = ArrayUtil.asCollection(this.selectionLayer
                .getSelectedCellPositions());
        Assert.assertEquals(1, cells.size());
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 0)));

        // select additional cells with shift mask
        // only the first cell should be selected afterwards
        this.selectionLayer.doCommand(new SelectCellCommand(this.selectionLayer, 10, 0,
                true, false));

        cells = ArrayUtil.asCollection(this.selectionLayer
                .getSelectedCellPositions());
        Assert.assertEquals(1, cells.size());
        Assert.assertTrue(cells.contains(new PositionCoordinate(this.selectionLayer,
                2, 0)));
    }
}
