package fitnesse.testsystems.slim.tables; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Map; import fitnesse.html.HtmlUtil; import fitnesse.testrunner.WikiTestPage; import fitnesse.testsystems.ExecutionResult; import fitnesse.testsystems.TestResult; import fitnesse.testsystems.slim.SlimCommandRunningClient; import fitnesse.slim.converters.VoidConverter; import fitnesse.slim.instructions.CallInstruction; import fitnesse.slim.instructions.Instruction; import fitnesse.slim.instructions.MakeInstruction; import fitnesse.testsystems.slim.HtmlTableScanner; import fitnesse.testsystems.slim.SlimTestContext; import fitnesse.testsystems.slim.SlimTestContextImpl; import fitnesse.testsystems.slim.Table; import fitnesse.testsystems.slim.TableScanner; import fitnesse.wiki.WikiPage; import fitnesse.wiki.WikiPageUtil; import fitnesse.wiki.fs.InMemoryPage; import org.junit.Before; import org.junit.Test; import static java.util.Arrays.asList; import static org.junit.Assert.*; public abstract class QueryTableTestBase { private WikiPage root; private List<SlimAssertion> assertions; private String queryTableHeader; private QueryTable qt; private SlimTestContextImpl testContext; protected String headRow; @Before public void setUp() throws Exception { root = InMemoryPage.makeRoot("root"); assertions = new ArrayList<>(); queryTableHeader = "|" + tableType() + ":fixture|argument|\n" + "|n|2n|\n"; headRow = "[pass(" + tableType() + ":fixture), argument], "; } protected abstract String tableType(); protected abstract Class<? extends QueryTable> queryTableClass(); protected QueryTable makeQueryTableAndBuildInstructions(String pageContents) throws Exception { qt = makeQueryTable(pageContents); assertions.addAll(qt.getAssertions()); return qt; } private QueryTable makeQueryTable(String tableText) throws Exception { WikiPageUtil.setPageContents(root, tableText); TableScanner ts = new HtmlTableScanner(root.getHtml()); Table t = ts.getTable(0); testContext = new SlimTestContextImpl(new WikiTestPage(root)); return constructQueryTable(t); } private QueryTable constructQueryTable(Table t) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { Class<? extends QueryTable> queryTableClass = queryTableClass(); Constructor<? extends QueryTable> constructor = queryTableClass.getConstructor(Table.class, String.class, SlimTestContext.class); return constructor.newInstance(t, "id", testContext); } protected void assertQueryResults(String queryRows, List<List<List<String>>> queryResults, String table) throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + queryRows); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap(asList(asList("queryTable_id_0", "OK"), asList("queryTable_id_1", "blah"), asList("queryTable_id_2", queryResults))); evaluateResults(pseudoResults, table); } @Test public void instructionsForQueryTable() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader); List<Instruction> expectedInstructions = asList( new MakeInstruction("queryTable_id_0", "queryTable_id", "fixture", new Object[]{"argument"}), new CallInstruction("queryTable_id_1", "queryTable_id", "table", new Object[]{asList(asList("n", "2n"))}), new CallInstruction("queryTable_id_2", "queryTable_id", "query")); assertEquals(expectedInstructions, instructions()); } private List<Instruction> instructions() { return SlimAssertion.getInstructions(assertions); } @Test public void nullResultsForNullTable() throws Exception { assertQueryResults("", new ArrayList<List<List<String>>>(), "[" + headRow + "[n, 2n]" + "]" ); } @Test public void oneRowThatMatches() throws Exception { assertQueryResults("|2|4|\n", asList( asList( asList("n", "2"), asList("2n", "4"))), "[" + headRow + "[n, 2n], " + "[pass(2), pass(4)]" + "]" ); } @Test public void oneRowFirstCellMatchesSecondCellBlank() throws Exception { assertQueryResults("|2||\n", asList( asList( asList("n", "2"), asList("2n", "4"))), "[" + headRow + "[n, 2n], " + "[pass(2), ignore(4)]" + "]" ); } @Test public void oneRowThatFails() throws Exception { assertQueryResults("|2|4|\n", asList( asList( asList("n", "3"), asList("2n", "5"))), "[" + headRow + "[n, 2n], " + "[fail(e=2;missing), 4], " + "[fail(a=3;surplus), 5]" + "]" ); } @Test public void oneRowWithPartialMatch() throws Exception { assertQueryResults("|2|4|\n", asList( asList( asList("n", "2"), asList("2n", "5"))), "[" + headRow + "[n, 2n], " + "[pass(2), fail(a=5;e=4)]" + "]" ); } @Test public void twoMatchingRows() throws Exception { assertQueryResults( "|2|4|\n" + "|3|6|\n", asList( asList( asList("n", "2"), asList("2n", "4")), asList( asList("n", "3"), asList("2n", "6"))), "[" + headRow + "[n, 2n], " + "[pass(2), pass(4)], " + "[pass(3), pass(6)]" + "]" ); } @Test public void twoRowsFirstMatchesSecondDoesnt() throws Exception { assertQueryResults( "|3|6|\n" + "|99|99|\n", asList( asList( asList("n", "2"), asList("2n", "4")), asList( asList("n", "3"), asList("2n", "6"))), "[" + headRow + "[n, 2n], " + "[pass(3), pass(6)], " + "[fail(e=99;missing), 99], " + "[fail(a=2;surplus), 4]" + "]" ); } @Test public void twoRowsSecondMatchesFirstDoesnt() throws Exception { assertQueryResults( "|99|99|\n" + "|2|4|\n", asList( asList( asList("n", "2"), asList("2n", "4")), asList( asList("n", "3"), asList("2n", "6"))), "[" + headRow + "[n, 2n], " + "[fail(e=99;missing), 99], " + "[pass(2), pass(4)], " + "[fail(a=3;surplus), 6]" + "]" ); } @Test public void fieldInMatchingRowDoesntExist() throws Exception { assertQueryResults( "|3|4|\n", asList(asList(asList("n", "3"))), "[" + headRow + "[n, 2n], " + "[pass(3), fail(a=field 2n not present;e=4)]" + "]" ); assertEquals(1, testContext.getTestSummary().getRight()); assertEquals(1, testContext.getTestSummary().getWrong()); } @Test public void fieldInSurplusRowDoesntExist() throws Exception { assertQueryResults( "", asList(asList(asList("n", "3"))), "[" + headRow + "[n, 2n], " + "[fail(a=3;surplus), fail(field 2n not present)]" + "]" ); assertEquals(0, testContext.getTestSummary().getRight()); assertEquals(2, testContext.getTestSummary().getWrong()); } @Test public void variablesAreReplacedInMatch() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|2|$V|\n"); qt.setSymbol("V", "4"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", VoidConverter.VOID_TAG), asList("queryTable_id_2", asList( asList( asList("n", "2"), asList("2n", "4"))))) ); SlimAssertion.evaluateExpectations(assertions, pseudoResults); assertEquals( "[" + headRow + "[n, 2n], " + "[pass(2), pass($V->[4])]" + "]", HtmlUtil.unescapeWiki(qt.getTable().toString()) ); } @Test public void tableWithSetSymbol() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|1|$A=|\n"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_2", asList(asList(asList("n", "1"), asList("2n", "2")))) ) ); evaluateResults(pseudoResults, "[" + headRow + "[n, 2n], " + "[pass(1), ignore($A<-[2])]" + "]"); assertEquals("2", qt.getSymbol("A")); } @Test public void tableWithSetSymbolReturnVariableInResult() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|1|$A=|\n"); QueryTable.QueryTableExpectation expectation = qt.new QueryTableExpectation(); TestResult result = expectation.evaluateExpectation(asList(asList(asList("n", "1"), asList("2n", "2")))); assertNotNull(result.getVariablesToStore()); assertEquals("2", result.getVariablesToStore().get("A")); } @Test public void tableWithSetSymbolInFirstColumnReturnVariableInResult() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|$A=|2|\n"); QueryTable.QueryTableExpectation expectation = qt.new QueryTableExpectation(); TestResult result = expectation.evaluateExpectation(asList(asList(asList("n", "1"), asList("2n", "2")))); assertNotNull(result.getVariablesToStore()); assertEquals("1", result.getVariablesToStore().get("A")); } @Test public void commentColumn() throws Exception { queryTableHeader = "|" + tableType() + ":fixture|argument|\n" + "|#comment1|n|#comment2|\n"; assertQueryResults( "|first|1|comment|\n"+ "|second|2||\n" , asList( asList( asList("#comment1", "second"), asList("n", "1"), asList("#comment2", "")), asList( asList("#comment1", "first"), asList("n", "2"), asList("#comment2", "comment"))), "[" + headRow + "[#comment1, n, #comment2], " + "[first, pass(1), comment], " + "[second, pass(2), ]" + "]" ); } @Test public void variablesAreReplacedInExpected() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|2|$V|\n"); qt.setSymbol("V", "5"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", VoidConverter.VOID_TAG), asList("queryTable_id_2", asList( asList( asList("n", "2"), asList("2n", "4"))))) ); SlimAssertion.evaluateExpectations(assertions, pseudoResults); assertEquals( "[" + headRow + "[n, 2n], " + "[pass(2), fail(a=4;e=$V->[5])]" + "]", HtmlUtil.unescapeWiki(qt.getTable().toString()) ); } @Test public void variablesAreReplacedInMissing() throws Exception { makeQueryTableAndBuildInstructions(queryTableHeader + "|3|$V|\n"); qt.setSymbol("V", "5"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", VoidConverter.VOID_TAG), asList("queryTable_id_2", new ArrayList<>())) ); evaluateResults(pseudoResults, "[" + headRow + "[n, 2n], " + "[fail(e=3;missing), $V->[5]]" + "]"); } protected void evaluateResults(Map<String, Object> pseudoResults, String expectedTable) { SlimAssertion.evaluateExpectations(assertions, pseudoResults); assertEquals(expectedTable, qt.getTable().toString()); } @Test public void oneRowThatMatchesExpression() throws Exception { assertQueryResults("|<5|4|\n", asList( asList( asList("n", "2"), asList("2n", "4"))), "[" + headRow + "[n, 2n], " + "[pass(2<5), pass(4)]" + "]" ); } @Test public void anErrorShouldBeRegisteredIfQueryDoesNotReturnAList() throws Exception { makeQueryTableAndBuildInstructions("|a|\n|b|\n"); QueryTable.QueryTableExpectation expectation = qt.new QueryTableExpectation(); TestResult result = expectation.evaluateExpectation("String result"); assertEquals(ExecutionResult.ERROR, result.getExecutionResult()); assertEquals(1, testContext.getTestSummary().getExceptions()); } @Test public void ShouldBeIgnoredIfQueryResultIsNull() throws Exception { makeQueryTableAndBuildInstructions("|a|\n|b|\n"); QueryTable.QueryTableExpectation expectation = qt.new QueryTableExpectation(); TestResult result = expectation.evaluateExpectation(null); assertEquals(ExecutionResult.IGNORE, result.getExecutionResult()); } /* When one row has a higher score "from the right", it is still the row that is correct from the left that should match. */ @Test public void shouldMatchQueryFromLeftToRight() throws Exception { makeQueryTableAndBuildInstructions("|" + tableType() + ":fixture|argument|\n" + "|x|n|2n|\n" + "|1|2|4|\n" + "|2|3|6|\n"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", "blah"), asList("queryTable_id_2", asList( asList( asList("x", "1"), asList("n", "3"), asList("2n", "6")))))); evaluateResults(pseudoResults, "[" + headRow + "[x, n, 2n], " + "[pass(1), fail(a=3;e=2), fail(a=6;e=4)], " + "[fail(e=2;missing), 3, 6]" + "]"); } @Test public void shouldMatchQueryFromLeftToRightWithFirstCellEmpty() throws Exception { makeQueryTableAndBuildInstructions("|" + tableType() + ":fixture|argument|\n" + "|x|n|2n|\n" + "||2|4|\n" + "||3|6|\n"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", "blah"), asList("queryTable_id_2", asList( asList( asList("x", "1"), asList("n", "2"), asList("2n", "4")), asList( asList("x", "1"), asList("n", "3"), asList("2n", "6")))))); evaluateResults(pseudoResults, "[" + headRow + "[x, n, 2n], " + "[ignore(1), pass(2), pass(4)], " + "[ignore(1), pass(3), pass(6)]" + "]"); } @Test public void shouldMatchQueryFromLeftToRightWithSecondCellEmpty() throws Exception { makeQueryTableAndBuildInstructions("|" + tableType() + ":fixture|argument|\n" + "|x|n|2n|\n" + "|1||4|\n" + "|1||6|\n"); Map<String, Object> pseudoResults = SlimCommandRunningClient.resultToMap( asList( asList("queryTable_id_0", "OK"), asList("queryTable_id_1", "blah"), asList("queryTable_id_2", asList( asList( asList("x", "1"), asList("n", "2"), asList("2n", "4")), asList( asList("x", "1"), asList("n", "3"), asList("2n", "6")))))); evaluateResults(pseudoResults, "[" + headRow + "[x, n, 2n], " + "[pass(1), ignore(2), pass(4)], " + "[pass(1), ignore(3), pass(6)]" + "]"); } }