com.codenjoy.dojo.tetris.model.TetrisGlassTest.java Source code

Java tutorial

Introduction

Here is the source code for com.codenjoy.dojo.tetris.model.TetrisGlassTest.java

Source

package com.codenjoy.dojo.tetris.model;

/*-
 * #%L
 * Codenjoy - it's a dojo-like platform from developers to developers.
 * %%
 * Copyright (C) 2016 Codenjoy
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.codenjoy.dojo.tetris.model.*;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Arrays;
import java.util.List;

import static junit.framework.Assert.*;
import static com.codenjoy.dojo.tetris.model.TestUtils.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class TetrisGlassTest {

    public static final int CENTER_X = WIDTH / 2 - 1;
    public static final int TOP_Y = HEIGHT - 1;
    private TetrisGlass glass;
    private TetrisFigure point;
    private TetrisFigure glassWidthFigure;
    private TetrisFigure line9Width;
    @Mock
    private GlassEventListener glassEventListener;
    @Captor
    private ArgumentCaptor<Integer> removedLines;
    @Captor
    private ArgumentCaptor<Figure> droppedFigure;

    @Before
    public void setUp() throws Exception {
        glass = new TetrisGlass(WIDTH, HEIGHT, glassEventListener);
        point = new TetrisFigure();
        glassWidthFigure = new TetrisFigure(0, 0, StringUtils.repeat("#", WIDTH));
        line9Width = new TetrisFigure(0, 0, StringUtils.repeat("#", WIDTH - 1));
    }

    @Test
    public void shouldAcceptWhenEmpty() {
        assertTrue(glass.accept(new TetrisFigure(), 1, 1));
    }

    @Test
    public void shouldRejectWhenAcceptingOnDroppedPlace() {
        glass.drop(new TetrisFigure(), 0, 0);

        assertFalse(glass.accept(new TetrisFigure(), 0, 0));
    }

    @Test
    public void shouldPerformDropWhenDropRequested() {
        glass.drop(new TetrisFigure(), 0, HEIGHT);

        assertFalse(glass.accept(new TetrisFigure(), 0, 0));
    }

    @Test
    public void shouldRejectWhenFigurePartlyOutsideFromLeft() {
        assertFalse(glass.accept(new TetrisFigure(1, 0, "##"), 0, HEIGHT));
    }

    @Test
    public void shouldRejectWhenFigurePartlyOutsideFromRight() {
        assertFalse(glass.accept(new TetrisFigure(0, 0, "##"), WIDTH, HEIGHT));
    }

    @Test
    public void shouldRejectWhenFigurePartlyOutsideBottom() {
        assertFalse(glass.accept(new TetrisFigure(0, 0, "#", "#"), WIDTH, 0));
    }

    @Test
    public void shouldRejectWhenFigurePartlyOverDroppedRow() {
        TetrisFigure figure = new TetrisFigure(1, 0, "##");

        glass.drop(figure, WIDTH / 2, HEIGHT);

        assertFalse(glass.accept(figure, WIDTH / 2 + 1, 0));
        assertFalse(glass.accept(figure, WIDTH / 2, 0));
        assertFalse(glass.accept(figure, WIDTH / 2 - 1, 0));
    }

    @Test
    public void shouldAcceptWhenFigureAboveDropped() {
        glass.drop(new TetrisFigure(1, 0, "##"), WIDTH / 2, HEIGHT);

        assertTrue(glass.accept(new TetrisFigure(1, 0, "##"), WIDTH / 2, 1));
    }

    @Test
    public void shouldRejectWhenFigurePartlyOverDroppedColumn() {
        TetrisFigure figure = new TetrisFigure(0, 1, "#", "#");

        glass.drop(figure, WIDTH / 2, HEIGHT);

        assertFalse(glass.accept(figure, WIDTH / 2, 0));
        assertFalse(glass.accept(figure, WIDTH / 2, 1));
        assertTrue(glass.accept(figure, WIDTH / 2, 2));
    }

    @Test
    public void shouldRejectWhenFigureOverlapDroppedColumnByBottomSize() {
        TetrisFigure figure = new TetrisFigure(0, 0, "#", "#");

        glass.drop(figure, WIDTH / 2, HEIGHT);

        assertFalse(glass.accept(figure, WIDTH / 2, 2));
    }

    @Test
    public void shouldRejectWhenFigureIsNotSymmetric() {
        TetrisFigure figure = new TetrisFigure(1, 0, "##", " #");

        glass.drop(figure, WIDTH / 2, HEIGHT);

        assertFalse(glass.accept(point, WIDTH / 2 - 1, 1));
    }

    @Test
    public void shouldRejectWhenFigureIsNotSymmetricPositive() {
        TetrisFigure figure = new TetrisFigure(1, 0, "##", " #");

        glass.drop(figure, WIDTH / 2, HEIGHT);

        assertTrue(glass.accept(figure, WIDTH / 2 + 1, 2));
    }

    @Test
    public void shouldRejectWhenFigureDroppedToFilledGlass() {
        glass.drop(point, 0, HEIGHT);

        glass.drop(point, 0, HEIGHT);

        assertFalse(glass.accept(point, 0, 1));
    }

    @Test
    public void shouldIgnoreWhenDropOutside() {
        glass.drop(new TetrisFigure(0, 0, "##"), -1, HEIGHT - 1);

        assertTrue(glass.accept(point, 0, 0));
    }

    @Test
    public void shouldIgnoreWhenOutOfBoundsLeft() {
        glass.drop(new TetrisFigure(1, 0, "##"), 0, HEIGHT - 1);

        assertTrue(glass.isEmpty());
    }

    @Test
    public void shouldIgnoreWhenOutOfBoundsRightPartially() {
        glass.drop(new TetrisFigure(0, 0, "##"), WIDTH - 1, HEIGHT - 1);

        assertTrue(glass.isEmpty());
    }

    @Test
    public void shouldIgnoreWhenOutOfBoundsBottom() {
        glass.drop(new TetrisFigure(0, 0, "#", "#"), 0, 0);

        assertTrue(glass.isEmpty());
    }

    @Test
    public void shouldRejectWhenPartiallyOutsideOnRight() {
        assertFalse(glass.accept(new TetrisFigure(0, 0, "##"), WIDTH - 1, 0));
    }

    @Test
    public void shouldReturnPlotCoordinateSimpleFigure() {
        glass.figureAt(point, 1, 1);

        Plot plot = glass.getCurrentFigurePlots().get(0);
        assertContainsPlot(1, 1, PlotColor.BLUE, plot);
    }

    @Test
    public void shouldReturnPlotCoordinateSimpleRedFigure() {
        glass.figureAt(createLine(Figure.Type.Z, "#"), 1, 1);

        Plot plot = glass.getCurrentFigurePlots().get(0);
        assertContainsPlot(1, 1, PlotColor.RED, plot);
    }

    @Test
    public void shouldReturnPlotCoordinateHorizontalFigure() {
        glass.figureAt(new TetrisFigure(1, 0, "###"), 1, 1);

        List<Plot> plots = glass.getCurrentFigurePlots();
        TestUtils.assertContainsPlot(1 - 1, 1, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(1, 1, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(1 + 1, 1, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldReturnPlotCoordinateVerticalFigure() {
        glass.figureAt(new TetrisFigure(0, 1, "#", "#", "#"), 1, 3);

        List<Plot> plots = glass.getCurrentFigurePlots();
        TestUtils.assertContainsPlot(1, 3 + 1, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(1, 3, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(1, 3 - 1, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldReturnPlotCoordinateAsymetricFigure() {
        glass.figureAt(new TetrisFigure(1, 0, " #"), 1, 0);

        List<Plot> plots = glass.getCurrentFigurePlots();
        assertEquals(1, plots.size());
        TestUtils.assertContainsPlot(1, 0, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldReturnPlotCoordinateAsymetricFigure2() {
        glass.figureAt(new TetrisFigure(0, 0, " #"), 1, 0);

        List<Plot> plots = glass.getCurrentFigurePlots();
        assertEquals(1, plots.size());
        TestUtils.assertContainsPlot(1 + 1, 0, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldReturnEmptyArrayWhenNoFigure() {
        assertTrue(glass.getCurrentFigurePlots().isEmpty());
    }

    @Test
    public void shouldReturnPlotOfDroppedFigure() {
        glass.drop(point, 0, HEIGHT);

        List<Plot> plots = glass.getDroppedPlots();
        TestUtils.assertContainsPlot(0, 0, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldReturnPlotOfDroppedFigure2() {
        glass.drop(new TetrisFigure(1, 1, "##", "##"), 3, HEIGHT);

        List<Plot> plots = glass.getDroppedPlots();
        TestUtils.assertContainsPlot(3 - 1, 1, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(3, 1, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(3 - 1, 0, PlotColor.BLUE, plots);
        TestUtils.assertContainsPlot(3, 0, PlotColor.BLUE, plots);
    }

    @Test
    public void shouldEmptyWhenRequested() {
        glass.drop(point, 0, 0);

        glass.empty();

        assertTrue(glass.getDroppedPlots().isEmpty());
    }

    @Test
    public void shouldRemoveFilledLineAfterDrop() {
        glass.drop(glassWidthFigure, 0, 0);

        assertTrue(glass.isEmpty());
    }

    @Test
    public void shouldRemoveFilledLineWhenSeveralFilled() {
        TetrisFigure columnFigure = new TetrisFigure(0, 0, "#", "#");
        glass.drop(line9Width, 0, HEIGHT);
        glass.drop(line9Width, 0, HEIGHT);

        glass.drop(columnFigure, WIDTH - 1, HEIGHT);

        assertTrue(glass.isEmpty());
    }

    @Test
    public void shouldRemoveFilledWhenGarbageOnTop() {
        drop(line9Width, HEIGHT);

        glass.drop(point, WIDTH - 1, HEIGHT);

        assertTrue(glass.accept(glassWidthFigure, 0, HEIGHT - 1));
    }

    @Test
    public void shouldRemoveFilledLineWhenInMiddleOfGlass() {
        glass.drop(point, 0, HEIGHT);
        glass.drop(line9Width, 0, HEIGHT);

        glass.drop(new TetrisFigure(0, 0, "#", "#"), WIDTH - 1, HEIGHT);

        assertTrue(glass.accept(glassWidthFigure, 0, 1));
    }

    @Test
    public void shouldNotifyWhenLineRemoved() {
        glass.drop(glassWidthFigure, 0, HEIGHT);

        verify(glassEventListener).linesRemoved(removedLines.capture());
        assertEquals(1, removedLines.getValue().intValue());
    }

    @Test
    public void shouldNotifyWhenSeveralLinesRemoved() {
        glass.drop(line9Width, 0, HEIGHT);
        glass.drop(line9Width, 0, HEIGHT);

        glass.drop(new TetrisFigure(0, 0, "#", "#"), WIDTH - 1, HEIGHT);

        verify(glassEventListener).linesRemoved(removedLines.capture());
        assertEquals(2, removedLines.getValue().intValue());
    }

    @Test
    public void shouldNotifyScoreBoardWhenDropped() {
        glass.drop(point, 0, HEIGHT);

        verify(glassEventListener).figureDropped(droppedFigure.capture());
        assertSame(point, droppedFigure.getValue());
    }

    @Test
    public void shouldTriggerListenerWhenOverflow() {
        glass.empty();

        verify(glassEventListener).glassOverflown();
    }

    @Test
    public void shouldTriggerAllListenersWhenOverflow() {
        TetrisGlass glass = new TetrisGlass(WIDTH, HEIGHT, glassEventListener, glassEventListener);

        glass.empty();

        verify(glassEventListener, times(2)).glassOverflown();
    }

    @Test
    public void shouldNotifyAllListenersScoreBoardWhenDropped() {
        TetrisGlass glass = new TetrisGlass(WIDTH, HEIGHT, glassEventListener, glassEventListener);

        glass.drop(point, 0, HEIGHT);

        verify(glassEventListener, times(2)).figureDropped(droppedFigure.capture());
    }

    @Test
    public void shouldNotifyAllListenersScoreBoardWhenLinesRemoved() {
        TetrisGlass glass = new TetrisGlass(WIDTH, HEIGHT, glassEventListener, glassEventListener);

        glass.drop(glassWidthFigure, 0, HEIGHT);

        verify(glassEventListener, times(2)).figureDropped(droppedFigure.capture());
    }

    @Test
    public void shouldQuietWhenDropOutOfBounds() {
        glass.drop(createVerticalFigure(HEIGHT), WIDTH / 2, HEIGHT);

        try {
            glass.drop(Figure.Type.I.createNewFigure(), WIDTH / 2, HEIGHT);
            verify(glassEventListener, times(1)).figureDropped(Matchers.<Figure>any());
        } catch (Exception e) {
            fail("Was exception: " + e);
        }
    }

    @Test
    public void shouldRemainWhenDropped_FoundInIntegrationTesting() {
        TetrisFigure twoRowsFigure = new TetrisFigure(0, 0, "#", "#");
        glass.drop(twoRowsFigure, WIDTH / 2, HEIGHT);

        glass.drop(twoRowsFigure, WIDTH / 2, HEIGHT);

        assertFalse(glass.accept(point, WIDTH / 2, 2));
        assertFalse(glass.accept(point, WIDTH / 2, 3));
    }

    @Test
    public void shouldBeOccupiedWhenLongFigureDroppedOnTopOfGlass() {
        glass.drop(createVerticalFigure(HEIGHT - 2), CENTER_X, TOP_Y);
        Figure figure = Figure.Type.J.createNewFigure();
        glass.drop(figure, CENTER_X, TOP_Y);

        assertFalse(glass.accept(figure, CENTER_X, TOP_Y));
    }

    @Test
    public void shouldStoreColorsWhenRedFigure() {
        glass.drop(createLine(Figure.Type.Z, "#"), CENTER_X, TOP_Y);

        assertEquals(PlotColor.RED, glass.getDroppedPlots().get(0).getColor());
    }

    @Test
    public void shouldNotAcceptWhenDroppedYellowFigure_int_overflow() {
        glass.drop(createLine(Figure.Type.O, "#"), 0, TOP_Y);

        assertFalse(glass.accept(point, 0, 0));
    }

    @Test
    public void shouldRemoveLinesWhenDroppedDifferentColors() {
        glass.drop(createLine(Figure.Type.I, "#########"), 1, TOP_Y);
        glass.drop(createLine(Figure.Type.J, "#"), 0, TOP_Y);

        verify(glassEventListener).linesRemoved(removedLines.capture());
        assertEquals(1, removedLines.getValue().intValue());
        assertTrue(glass.accept(point, 0, 0));
    }

    @Test
    public void shouldRemoveLinesInBetweenWhenDropped() {
        glass.drop(createLine("# ########"), 0, TOP_Y);
        glass.drop(createLine("##########"), 0, TOP_Y);

        verify(glassEventListener).linesRemoved(removedLines.capture());
        assertEquals(1, removedLines.getValue().intValue());
        assertFalse(glass.accept(point, 0, 0));
        assertTrue(glass.accept(point, 1, 0));
    }

    private TetrisFigure createLine(Figure.Type type, String... lines) {
        return new TetrisFigure(0, 0, type, lines);
    }

    private TetrisFigure createLine(String... lines) {
        return createLine(Figure.Type.I, lines);
    }

    private TetrisFigure createVerticalFigure(int height) {
        String[] verticalLine = new String[height];
        Arrays.fill(verticalLine, "#");
        return new TetrisFigure(0, 0, verticalLine);
    }

    private void drop(TetrisFigure lineFigure, int times) {
        for (int i = 0; i < times; i++) {
            glass.drop(lineFigure, 0, HEIGHT);
        }
    }

    private void assertContainsPlot(final int x, final int y, final PlotColor color, Plot... plots) {
        TestUtils.assertContainsPlot(x, y, color, Arrays.asList(plots));
    }
}