Commit b07899a2 authored by Matthew Dawson's avatar Matthew Dawson
Browse files

Add a simple table walk test.

Make sure the table walking works as expected.  Currently tests the only
implemented part, which is the left grid breadth/depth first walking.
parent 99190899
Loading
Loading
Loading
Loading
+293 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 Matthew Dawson <matthew@mjdsystems.ca>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the distribution
 *     * Neither the name of the McMaster Centre for Software Certification nor the names
 *       of its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package ca.mcscert.jtet.tabularexpression.test;

import ca.mcscert.jtet.expression.*;
import ca.mcscert.jtet.tabularexpression.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.Parameter;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

/**
 * Test the walking methods of Table to ensure it handles 2d grids correctly.
 *
 * @author Matthew Dawson
 */
@RunWith(Parameterized.class)
public class TableWalkTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{
                {
                        new HierarchicalGridBreadthFirstScriptGenerator(),
                        "L(x GreaterThenEqual 0)\n" +
                                "E(x Equals 0)\n" +
                                "L(x LessThenEqual 0)\n" +
                                "D(x Equals 0)\n" +
                                " L(z LessThenEqual 0)\n" +
                                " E(z Equals 0)\n" +
                                " L(z GreaterThenEqual 0)\n" +
                                " D(z Equals 0)\n" +
                                "  L(z Equals 0)\n" +
                                " A\n" +
                                "A\n",
                },
                {
                        new HierarchicalGridDepthFirstScriptGenerator(),
                        "L(x GreaterThenEqual 0)\n" +
                                "OUT output -> 0\n" +
                                "E(x Equals 0)\n" +
                                "D(x Equals 0)\n" +
                                " L(z LessThenEqual 0)\n" +
                                " OUT output -> 1\n" +
                                " E(z Equals 0)\n" +
                                " D(z Equals 0)\n" +
                                "  L(z Equals 0)\n" +
                                "  OUT output -> 2\n" +
                                " A\n" +
                                " L(z GreaterThenEqual 0)\n" +
                                " OUT output -> 3\n" +
                                "A\n" +
                                "L(x LessThenEqual 0)\n" +
                                "OUT output -> 4\n",
                },
        });
    }

    @Parameter
    public walkerScriptGenerator walker;

    @Parameter(value = 1)
    public String SingleGridWalkScript;

    /**
     * Tests the ability for Table to walk a left grid only table.
     * <p>
     * This is similar to what all the generators walk for their tests.
     */
    @Test
    public void SingleLeftGridWalkTest() {
        Table table = getInitialTable();

        List<HierarchicalCell> grid = table.getLeftGrid().getSubHierarchy();
        grid.add(new HierarchicalCell("x >= 0"));
        grid.add(new HierarchicalCell("x == 0"));
        grid.add(new HierarchicalCell("x <= 0"));

        grid = grid.get(1).getSubHierarchy();
        grid.add(new HierarchicalCell("z <= 0"));
        grid.add(new HierarchicalCell("z == 0"));
        grid.add(new HierarchicalCell("z >= 0"));

        grid = grid.get(1).getSubHierarchy();
        grid.add(new HierarchicalCell("z == 0"));

        final TwoDimensionalGrid outGrid = new TwoDimensionalGrid(1, 5);
        for(int i = 0; i < outGrid.sizeY(); i++) {
            outGrid.get(0, i).setContents(String.valueOf(i));
        }
        table.getVariableOutputs().put(table.getVariables().getOutputVariables().get("output"), outGrid);

        verifyWalk(table, SingleGridWalkScript);
    }

    /**
     * This has the table walk itself with the walker, verifying its output against the given script.
     * @param table Table to walk.
     * @param walkScript The script the walker should generate.
     */
    private void verifyWalk(Table table, String walkScript) {
        walker.reset();
        if (walker instanceof HierarchicalGridBreadthFirstCheckerGenerator) {
            assertThat(table.walk((HierarchicalGridBreadthFirstCheckerGenerator) walker), is(walkScript));
        } else if (walker instanceof HierarchicalGridDepthFirstCheckerGenerator) {
            assertThat(table.walk((HierarchicalGridDepthFirstCheckerGenerator) walker), is(walkScript));
        } else {
            throw new AssertionError("Failed to walk table!");
        }
    }

    /**
     * Generate initial table data.
     * @return A ready to use table with x, y, z as input parameters and output as the only output variable.
     */
    private Table getInitialTable() {
        return new Table(null, new VariableCollection(
                new PartialVariableCollection(
                        new Variable("x", new RealType()),
                        new Variable("y", new RealType()),
                        new Variable("z", new RealType())
                ),
                new PartialVariableCollection(
                        new Variable("output", new RealType())
                )
        ));
    }

    /**
     * Breadth first script generator.
     *
     * This generates a script for the breadth first walker interface.
     */
    private static class HierarchicalGridBreadthFirstScriptGenerator implements HierarchicalGridBreadthFirstCheckerGenerator, walkerScriptGenerator {
        @Override
        public void descendIntoGridFromCell(Expression inputCellExpression) {
            script.append(indents)
                    .append("D")
                    .append(inputCellExpression)
                    .append("\n");
            indents.append(" ");
        }

        @Override
        public void ascendFromGrid() {
            indents.setLength(indents.length() - 1);
            script.append(indents)
                    .append("A")
                    .append("\n");
        }

        @Override
        public void handleLeafCell(Expression inputCellExpression) {
            script.append(indents)
                    .append("L")
                    .append(inputCellExpression)
                    .append("\n");
        }

        @Override
        public void handleEdgeCell(Expression inputCellExpression) {
            script.append(indents)
                    .append("E")
                    .append(inputCellExpression)
                    .append("\n");
        }

        @Override
        public String getFinalString() {
            return script.toString();
        }

        @Override
        public void reset() {
            script.setLength(0);
            indents.setLength(0);
        }

        final private StringBuilder script = new StringBuilder();
        final private StringBuilder indents = new StringBuilder(4);
    }


    /**
     * Depth first script generator.
     *
     * This generates a script for the depth first walker interface.
     */
    private static class HierarchicalGridDepthFirstScriptGenerator implements HierarchicalGridDepthFirstCheckerGenerator, walkerScriptGenerator {
        @Override
        public void descendIntoGridFromCell(Expression inputCellExpression) {
            script.append(indents)
                    .append("D")
                    .append(inputCellExpression)
                    .append("\n");
            indents.append(" ");
        }

        @Override
        public void ascendFromGrid() {
            indents.setLength(indents.length() - 1);
            script.append(indents)
                    .append("A")
                    .append("\n");
        }

        @Override
        public void handleLeafCell(Expression inputCellExpression, Map<Variable, Expression> outputCellsExpression) {
            script.append(indents)
                    .append("L")
                    .append(inputCellExpression)
                    .append("\n");
            for (Map.Entry<Variable, Expression> output : outputCellsExpression.entrySet()) {
                script.append(indents)
                        .append("OUT ")
                        .append(output.getKey().name())
                        .append(" -> ")
                        .append(output.getValue())
                        .append("\n");
            }

        }

        @Override
        public void handleEdgeCell(Expression inputCellExpression) {
            script.append(indents)
                    .append("E")
                    .append(inputCellExpression)
                    .append("\n");
        }

        @Override
        public String getFinalString() {
            return script.toString();
        }

        @Override
        public void reset() {
            script.setLength(0);
            indents.setLength(0);
        }

        final private StringBuilder script = new StringBuilder();
        final private StringBuilder indents = new StringBuilder(4);
    }

    /**
     * Resets a script generator, to allow it to generate a new script.
     *
     * This interface allows the script generators to reset between runs.
     */
    private interface walkerScriptGenerator {
        /**
         * Resets a generators internal state.
         */
        void reset();
    }
}