diff --git a/FitNesseRoot/FitNesse/UserGuide/WritingAcceptanceTests/SliM/content.txt b/FitNesseRoot/FitNesse/UserGuide/WritingAcceptanceTests/SliM/content.txt index 35aabd61e..44531a69c 100644 --- a/FitNesseRoot/FitNesse/UserGuide/WritingAcceptanceTests/SliM/content.txt +++ b/FitNesseRoot/FitNesse/UserGuide/WritingAcceptanceTests/SliM/content.txt @@ -16,21 +16,21 @@ If you want a test page to be run under SLIM, you simply set the TEST_SYSTEM var !3 The Slim Tables The first cell of a slim table tells you what kind of table it is. Here are the table types so far: -| [[Decision Table][>DecisionTable]] | Supplies the inputs and outputs for decisions. This is similar to the Fit Column Fixture | -| [[Baseline Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.BaseLineDecisionTable]]|Almost identical to a >DecisionTable but more readable for very big tables with many columns as only the changed values from one line to the baseline must be specified. The fixture implementation is identical to >DecisionTable.| -| [[Dynamic Decision Table][>DynamicDecisionTable]] |Has the same syntax as a >DecisionTable, but differs in the fixture implementation. It passes the column headers as parameters to the fixture. | -| [[Hybrid Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.HybridDecisionTable]] |Combines the advantages in the fixture implementation of a Decision and a Dynamic Decision Table. Also supported by a [[Baseline Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.BaseLineDecisionTable]] | -| [[Query Table][>QueryTable]] | Supplies the expected results of a query. This is similar to the Fit Row Fixture | -| [[Subset Query Table][>SubsetQueryTable]] | Supplies a subset of the expected results of a query. | -| [[Ordered query Table][>OrderedQueryTable]] | Supplies the expected results of a query. The rows are expected to be in order. This is similar to the Fit Row Fixture | -| [[Script Table][>ScriptTable]] | A series of actions and checks. Similar to Do Fixture. | -| [[Table Table][>TableTable]] | Whatever you want it to be! | -| [[Import][>ImportTable]] | Add a path to the fixture search path. | -| [[Comment][>CommentTable]] | A table that does nothing. | -| [[Scenario Table][>ScenarioTable]] | A table that can be called from other tables. | -| [[Library Table][>LibraryTable]] | A table that installs fixtures available for all test pages | -| [[Define Table Type][>DefineTableType]] | A helper table that defines the default table type for named fixtures. | -| [[Define Alias][>DefineAlias]] | A helper table that defines alias names for fixtures. | +|[[Decision Table][>DecisionTable]] |Supplies the inputs and outputs for decisions. This is similar to the Fit Column Fixture | +|[[Baseline Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.BaseLineDecisionTable]]|Almost identical to a >DecisionTable but more readable for very big tables with many columns as only the changed values from one line to the baseline must be specified. The fixture implementation is identical to >DecisionTable.| +|[[Dynamic Decision Table][>DynamicDecisionTable]] |Has the same syntax as a >DecisionTable, but differs in the fixture implementation. It passes the column headers as parameters to the fixture. | +|[[Hybrid Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.HybridDecisionTable]] |Combines the advantages in the fixture implementation of a Decision and a Dynamic Decision Table. Also supported by a [[Baseline Decision Table][.FitNesse.SuiteAcceptanceTests.SuiteSlimTests.BaseLineDecisionTable]] | +|[[Query Table][>QueryTable]] |Supplies the expected results of a query. This is similar to the Fit Row Fixture | +|[[Subset Query Table][>SubsetQueryTable]] |Supplies a subset of the expected results of a query. | +|[[Ordered query Table][>OrderedQueryTable]] |Supplies the expected results of a query. The rows are expected to be in order. This is similar to the Fit Row Fixture | +|[[Script Table][>ScriptTable]] |A series of actions and checks. Similar to Do Fixture. | +|[[Table Table][>TableTable]] |Whatever you want it to be! | +|[[Import][>ImportTable]] |Add a path to the fixture search path. | +|[[Comment][>CommentTable]] |A table that does nothing. | +|[[Scenario Table][>ScenarioTable]] |A table that can be called from other tables. | +|[[Library Table][>LibraryTable]] |A table that installs fixtures available for all test pages | +|[[Define Table Type][>DefineTableType]] |A helper table that defines the default table type for named fixtures. | +|[[Define Alias][>DefineAlias]] |A helper table that defines alias names for fixtures. | !4 Data Types. The data in your tables is all Strings. However your fixtures don't want to be constrained to Strings. So Slim comes with several standard data type converters that will automatically convert the strings in the tables into the data types expected by your fixtures. @@ -41,28 +41,60 @@ You can also create your own custom type converters if you like. !see >CustomTypes Content returned from the SUT will be escaped by default, so your fixture can return a piece of output without the need to transform it to HTML compatible output. On the other hand, if you're returning HTML content (e.g. a ..
), FitNesse will try to detect that (based on a valid HTML start and end tag) and will render the HTML in-line. +!anchor watchlink + + +!4 Watch closer what SLIM is doing +When a SLIM test is run the the webpage will update each time a table has been fully processed.!- +-!If you want to get quicker an undate you have to set the property: ''slim.show'' + +At the top of the test page you will then see 2 additional outputs +1. A list of the last 10 instructions the SLIM server is sending to the SLIM Client and the results of the same. +2. The current table and how its cells are updated after each instruction executed. + + +In addition you can use the following two properties to customize this further. They are explained in the next section: +slim.show.size +slim.show.sleep + +Try it if you run a local installation: +http://localhost:${FITNESSE_PORT}/FitNesse.UserGuide.TwoMinuteExample?test&slim.show&slim.show.sleep=90&slim.show.size=15 + +Note instuctions are also saved in the [[Test Result XML file][.FitNesse.UserGuide.WritingAcceptanceTests.RestfulTests]]. +You have to open the XML file in an editor to see them. + + !4 Configure SLIM The Slim test system can be configured using the following properties: -| slim.port | 8085 | Base port for SLIM. | -| slim.pool.size | 10 | The size of the pool of ports to cycle through. By default the ports 8085 up to 8095 are used (''slim.port'' + ''slim.pool.size''). | -| slim.host | localhost | The host the SLIM server will be running on. This is mostly useful if you're running a remote SLIM server. | -| slim.flags | | Extra flags to provide to the SLIM server. Arguments supported by the slim service are: !- +|property |default |description | +|slim.port |8085 |Base port for SLIM. | +|slim.pool.size|10 |The size of the pool of ports to cycle through. By default the ports 8085 up to 8095 are used (''slim.port'' + ''slim.pool.size'').| +|slim.host |localhost|The host the SLIM server will be running on. This is mostly useful if you're running a remote SLIM server. | +|slim.flags | |Extra flags to provide to the SLIM server. Arguments supported by the slim service are: !- -![-v] [-i interactionClass] [-s statementTimeout] [-d] [-ssl parameterClass] | -| slim.timeout | 10 seconds | Connection timeout starting and finishing a test run. | -| slim.debug.timeout | ''slim.timeout'' | Same as ''slim.timeout'', used when the debug property is set (falls back to ''slim.timeout''). | -| manually.start.test.runner.on.debug | false | Do not launch a SLIM server if the test is ran in debug mode. | +|slim.timeout |10 seconds |Connection timeout starting and finishing a test run. | +|slim.debug.timeout |''slim.timeout''|Same as ''slim.timeout'', used when the debug property is set (falls back to ''slim.timeout'').| +|manually.start.test.runner.on.debug|false |Do not launch a SLIM server if the test is ran in debug mode. | +|slim.mode |BULK |BULK mode - By default the SLIM server sends a full table to the SLIM client and gets the results for the full table back. !- +-! SINGLE mode - Instructions are send one by one to the SLIM Client. This is required for ''slim.show'' and will be set automatically if ''slim.show'' is set !- + +-!There is no performance difference between these two modes. The SINGLE mode should make it simpler to write new ports of SLIM in the future. As a normal slim user you don't have to care about this setting.| +|slim_show||See above under: Whatch closer what Slim is doing .#watchlink !- +-!Note that slim.show will also set the ''slim.mode'' to SINGLE.| +|slim.show.size |10|Number of instructions to show | +|slim.show.sleep|0 |Waits for X milliseconds between each instruction call. This is for making nice videos of a test run. Otherwise I don't think there is a usecase for slowing down the execution of your test| Those properties can be either provided by a wiki page, on the command line (e.g. ''-Dslim.port=9000'') or in the plugins.properties file. !4 Extra Goodies that are consistent throughout all Slim tables and ports. -| [[''Exception Handling''][>ExceptionHandling]] | -| [[''Symbols in tables''][>SymbolsInTables]] | -| [[''Expressions in tables''][>ExpressionsInTables]] | -| [[''Constructor arguments''][>ConstructorArguments]] | -| [[''Value comparisons''][>ValueComparisons]] | -| [[''Graceful names''][>GracefulNames]] | +|[[''Exception Handling''][>ExceptionHandling]] | +|[[''Symbols in tables''][>SymbolsInTables]] | +|[[''Expressions in tables''][>ExpressionsInTables]] | +|[[''Constructor arguments''][>ConstructorArguments]]| +|[[''Value comparisons''][>ValueComparisons]] | +|[[''Graceful names''][>GracefulNames]] | !4 Java goodies -| [[''System Under Test''][>SystemUnderTest]] | -| [[''Interaction Aware Fixture''][>InteractionAwareFixture]] | +|[[''System Under Test''][>SystemUnderTest]] | +|[[''Interaction Aware Fixture''][>InteractionAwareFixture]]| diff --git a/src/fitnesse/reporting/JavascriptUtil.java b/src/fitnesse/reporting/JavascriptUtil.java index c0b19e2aa..84b2f5bc8 100644 --- a/src/fitnesse/reporting/JavascriptUtil.java +++ b/src/fitnesse/reporting/JavascriptUtil.java @@ -41,6 +41,13 @@ public static HtmlTag makeReplaceElementScript(String idElement, String newHtmlF return scriptTag; } + public static HtmlTag expandCurrentRow(String idElement) { + HtmlTag scriptTag = new HtmlTag("script"); + String escapedIdElement = escapeHtmlForJavaScript(idElement); + scriptTag.add("$( '#" + escapedIdElement + "' ).find( '.closed-detail' ).css( 'display', 'initial' );"); + return scriptTag; + } + public static HtmlTag makeInitErrorMetadataScript() { HtmlTag scriptTag = new HtmlTag("script"); scriptTag.add("initErrorMetadata();"); diff --git a/src/fitnesse/reporting/SuiteHtmlFormatter.java b/src/fitnesse/reporting/SuiteHtmlFormatter.java index 8f003180c..9962f763a 100644 --- a/src/fitnesse/reporting/SuiteHtmlFormatter.java +++ b/src/fitnesse/reporting/SuiteHtmlFormatter.java @@ -4,10 +4,18 @@ import fitnesse.html.HtmlTag; import fitnesse.html.HtmlUtil; +import fitnesse.testsystems.Assertion; +import fitnesse.testsystems.ExceptionResult; import fitnesse.testsystems.ExecutionResult; +import fitnesse.testsystems.Expectation; +import fitnesse.testsystems.TableCell; import fitnesse.testsystems.TestPage; +import fitnesse.testsystems.TestResult; import fitnesse.testsystems.TestSummary; import fitnesse.testsystems.TestSystem; +import fitnesse.testsystems.slim.HtmlTable; +import fitnesse.testsystems.slim.Table; +import static fitnesse.testsystems.slim.SlimTestSystem.SLIM_SHOW; import fitnesse.util.TimeMeasurement; import fitnesse.wiki.PathParser; import fitnesse.wiki.WikiPage; @@ -15,10 +23,13 @@ import java.io.Closeable; import java.io.IOException; import java.io.Writer; +import java.util.LinkedList; +import java.util.Collections; +import java.util.stream.Collectors; import static fitnesse.testsystems.ExecutionResult.getExecutionResult; -public class SuiteHtmlFormatter extends InteractiveFormatter implements Closeable { +public class SuiteHtmlFormatter extends InteractiveFormatter implements Closeable { private static final String TEST_SUMMARIES_ID = "test-summaries"; private TestSummary pageCounts = new TestSummary(); @@ -31,6 +42,10 @@ public class SuiteHtmlFormatter extends InteractiveFormatter implements Closeabl private String testSummariesId = TEST_SUMMARIES_ID; private boolean testSummariesPresent; private TimeMeasurement totalTimeMeasurement; + private LinkedList instructionsHtmlText; + private int testSystemListenerShowInstructions; + private boolean testSystemListenerShowHtmlTable; + private int testSystemListenerSleep; public SuiteHtmlFormatter(WikiPage page, boolean testSummariesPresent, Writer writer) { @@ -38,6 +53,30 @@ public SuiteHtmlFormatter(WikiPage page, boolean testSummariesPresent, Writer wr this.testSummariesPresent = testSummariesPresent; totalTimeMeasurement = new TimeMeasurement().start(); testBasePathName = PathParser.render(page.getFullPath()); + String sbys = getPage().getVariable(SLIM_SHOW); + testSystemListenerShowHtmlTable = (sbys != null); + testSystemListenerShowInstructions = 0; + if(testSystemListenerShowHtmlTable){ + testSystemListenerShowInstructions = 10; + String sbysLines = getPage().getVariable("slim.show.size"); + if (sbysLines != null) + try{ + testSystemListenerShowInstructions = Integer.parseInt(sbysLines); + }catch (NumberFormatException e){ + // ignore and keep default + } + // This is for making nice videos of a test run :) + testSystemListenerSleep = 0; + String sbysSleep = getPage().getVariable("slim.show.sleep"); + if (sbysSleep != null) + try{ + testSystemListenerSleep = Integer.parseInt(sbysSleep); + }catch (NumberFormatException e){ + // ignore and keep default + } + } + //Fill the list with empty lines to reserve the space on the screen + this.instructionsHtmlText = new LinkedList(Collections.nCopies(testSystemListenerShowInstructions,"")); } @Override @@ -90,7 +129,6 @@ public void testStarted(TestPage testPage) { super.testStarted(testPage); String fullPathName = testPage.getFullPath(); - announceStartNewTest(getRelativeName(), fullPathName); } @@ -177,6 +215,79 @@ public void testSystemStarted(TestSystem testSystem) { writeData(insertScript.html()); } } + + + + protected void showAssertionResult(Assertion assertion, String testResult, boolean overwriteLastMessage) { + if(testSystemListenerShowInstructions >0){ + try { + String instructionText; + String position; + Expectation expectation = assertion.getExpectation(); + if (expectation instanceof TableCell) { + TableCell cell = (TableCell) expectation; + position = String.format("% 3d,% 3d", cell.getRow(), cell.getCol()); + } else { + position = " "; + } + assertion.getInstruction(); + instructionText = assertion.getInstruction().toString(); + instructionText = position + ": " + instructionText + "-->" + testResult; + instructionText = HtmlUtil.escapeHTML(instructionText); + if (overwriteLastMessage){ + this.instructionsHtmlText.removeLast(); + } else { + this.instructionsHtmlText.removeFirst(); + } + this.instructionsHtmlText.addLast(instructionText); + String allInstructionsText = this.instructionsHtmlText.stream().collect(Collectors.joining("
")); + String html = "

"+allInstructionsText+"

"; + String insertScript = JavascriptUtil.makeReplaceElementScript("step-by-step-Id2", html).html(); + writeData(insertScript); + } catch (Exception e){ + String html = e.getMessage(); + } + } + if(testSystemListenerShowHtmlTable){ + try{ + Expectation expectation = assertion.getExpectation(); + if (expectation instanceof TableCell) { + TableCell cell = (TableCell) expectation; + Table t = cell.getTable(); + if (t instanceof HtmlTable) { + HtmlTable ht = (HtmlTable) t; + String html = ht.getTableNode().toHtml().toString(); + String insertScript = JavascriptUtil.makeReplaceElementScript("step-by-step-Id", html).html(); + testOutputChunk(null, insertScript); + String expandScript = JavascriptUtil.expandCurrentRow("step-by-step-Id").html(); + testOutputChunk(null, expandScript); + } + } + if (testSystemListenerSleep > 0) + Thread.sleep(testSystemListenerSleep); + } catch (Exception e){ + String em = e.getMessage(); + } + } + } + + @Override + public void testAssertionVerified(Assertion assertion, TestResult testResult) { + String resultString = testResult != null ? testResult.toString() : "VOID"; + showAssertionResult(assertion,resultString, true); + } + + @Override + public void testExceptionOccurred(Assertion assertion, ExceptionResult exceptionResult) { + String resultString = exceptionResult!= null ? exceptionResult.toString() : "EXCEPTION"; + showAssertionResult(assertion,resultString, true); + } + + @Override + public void testAssertionWillBeExecuted(Assertion assertion) { + String resultString = "in progress"; + showAssertionResult(assertion,resultString, false); + } @Override protected String makeSummaryContent() { @@ -189,9 +300,11 @@ protected String makeSummaryContent() { return summaryContent; } + protected boolean hasTestSummaries() { return testSummariesPresent; } + } diff --git a/src/fitnesse/resources/templates/testPage.vm b/src/fitnesse/resources/templates/testPage.vm index 838a9fd92..f2e8d44cb 100644 --- a/src/fitnesse/resources/templates/testPage.vm +++ b/src/fitnesse/resources/templates/testPage.vm @@ -16,6 +16,13 @@ $!headerContent.render() ## Filled with stop/output buttons +
+## Current Instruction updates here +
+
+## Current Table updates here +
+ #if ($multipleTestsRun)

Test Summaries

diff --git a/src/fitnesse/testrunner/MultipleTestsRunner.java b/src/fitnesse/testrunner/MultipleTestsRunner.java index 54f28ef70..a4446fa99 100755 --- a/src/fitnesse/testrunner/MultipleTestsRunner.java +++ b/src/fitnesse/testrunner/MultipleTestsRunner.java @@ -224,6 +224,12 @@ public void testAssertionVerified(Assertion assertion, TestResult testResult) { public void testExceptionOccurred(Assertion assertion, ExceptionResult exceptionResult) { formatters.testExceptionOccurred(assertion, exceptionResult); } + + @Override + public void testAssertionWillBeExecuted(Assertion assertion) { + formatters.testAssertionWillBeExecuted(assertion); + } + } private boolean isNotStopped() { diff --git a/src/fitnesse/testsystems/CompositeTestSystemListener.java b/src/fitnesse/testsystems/CompositeTestSystemListener.java index 58b3883c0..4a7fe05b8 100644 --- a/src/fitnesse/testsystems/CompositeTestSystemListener.java +++ b/src/fitnesse/testsystems/CompositeTestSystemListener.java @@ -60,4 +60,10 @@ public void testExceptionOccurred(Assertion assertion, ExceptionResult exception for (TestSystemListener listener : listeners) listener.testExceptionOccurred(assertion, exceptionResult); } + + @Override + public void testAssertionWillBeExecuted(Assertion assertion) { + for (TestSystemListener listener : listeners) + listener.testAssertionWillBeExecuted(assertion); + } } diff --git a/src/fitnesse/testsystems/TableCell.java b/src/fitnesse/testsystems/TableCell.java index a5f9e528d..94bddf629 100644 --- a/src/fitnesse/testsystems/TableCell.java +++ b/src/fitnesse/testsystems/TableCell.java @@ -1,5 +1,7 @@ package fitnesse.testsystems; +import fitnesse.testsystems.slim.Table; + /** * This interface can be implemented by Expectation's to provide extra information for reporting. */ @@ -8,4 +10,6 @@ public interface TableCell { int getCol(); int getRow(); + + Table getTable(); } diff --git a/src/fitnesse/testsystems/TestSystemListener.java b/src/fitnesse/testsystems/TestSystemListener.java index 3dbab98e2..a7ab0535b 100644 --- a/src/fitnesse/testsystems/TestSystemListener.java +++ b/src/fitnesse/testsystems/TestSystemListener.java @@ -43,4 +43,8 @@ default void testAssertionVerified(Assertion assertion, TestResult testResult) { default void testExceptionOccurred(Assertion assertion, ExceptionResult exceptionResult) { } + + /* This is only useful for interactive Listeners, it is called before the assertion is passed to the SUT */ + default void testAssertionWillBeExecuted(Assertion assertion) { + } } diff --git a/src/fitnesse/testsystems/slim/SlimTestSystem.java b/src/fitnesse/testsystems/slim/SlimTestSystem.java index 90a4389ae..13da49784 100755 --- a/src/fitnesse/testsystems/slim/SlimTestSystem.java +++ b/src/fitnesse/testsystems/slim/SlimTestSystem.java @@ -20,6 +20,12 @@ import static fitnesse.slim.SlimServer.*; public abstract class SlimTestSystem implements TestSystem { + // BULK - Process a full table by the Slim Client in one go + // SINGLE - Process a single instruction and give control back to the test system + // Default Mode is BULK + public static final String SLIM_MODE = "slim.mode"; + // This will force the mode SINGLE to allow a more interactive user experience + public static final String SLIM_SHOW = "slim.show"; private final SlimClient slimClient; private final CompositeTestSystemListener testSystemListener; private final String testSystemName; @@ -41,6 +47,19 @@ public SlimTestContext getTestContext() { return testContext; } + private boolean isModeSingle(){ + String sbys = getTestContext().getPageToTest().getVariable(SLIM_MODE); + if (sbys != null){ + if ("SINGLE".equals(sbys)) return true; + } + sbys = getTestContext().getPageToTest().getVariable(SLIM_SHOW); + if (sbys != null){ + return true; + } + return false; + } + + @Override public String getName() { return testSystemName; @@ -118,11 +137,13 @@ protected SlimTestContextImpl createTestContext(TestPage testPage) { protected void processTable(SlimTable table, boolean isSuiteTearDownPage) throws TestExecutionException { List assertions = table.getAssertions(); - final Map instructionResults; + Map instructionResults; if (stopTestCalled && !table.isTearDown()) { instructionResults = Collections.emptyMap(); + evaluateTables(assertions, instructionResults); } else if (ignoreAllTestsCalled && !table.isTearDown()){ instructionResults = Collections.emptyMap(); + evaluateTables(assertions, instructionResults); } else { boolean tearDownOfAlreadyStartedTest = stopTestCalled && table.isTearDown(); if(ignoreAllTestsCalled && table.isTearDown()){ @@ -130,71 +151,100 @@ protected void processTable(SlimTable table, boolean isSuiteTearDownPage) throws } if (stopSuiteCalled && !isSuiteTearDownPage && !tearDownOfAlreadyStartedTest) { instructionResults = Collections.emptyMap(); + evaluateTables(assertions, instructionResults); } else { - instructionResults = slimClient.invokeAndGetResponse(SlimAssertion.getInstructions(assertions)); + if (isModeSingle()){ + boolean IgnoreTestTable = false; + for (SlimAssertion assertion : assertions) { + List oneAssertion = new ArrayList<>(); + oneAssertion.add(assertion); + testAssertionWillBeExecuted(assertion); + instructionResults = slimClient.invokeAndGetResponse(SlimAssertion.getInstructions(oneAssertion)); + final String instructionId = assertion.getInstruction().getId(); + Object instructionResult = instructionResults.get(instructionId); + IgnoreTestTable = evaluateAssertion(instructionResult,IgnoreTestTable, assertion, instructionId); + } + } else { + instructionResults = slimClient.invokeAndGetResponse(SlimAssertion.getInstructions(assertions)); + evaluateTables(assertions, instructionResults); + } } } - evaluateTables(assertions, instructionResults); + } protected void evaluateTables(List assertions, Map instructionResults) throws SlimCommunicationException { boolean IgnoreTestTable = false; for (SlimAssertion a : assertions) { final String key = a.getInstruction().getId(); - Object returnValue = instructionResults.get(key); - - //Ignore management - if(!ignoreAllTestsCalled) { - if (returnValue != null && returnValue.toString().contains(EXCEPTION_IGNORE_ALL_TESTS_TAG)) { - ignoreAllTestsCalled = IgnoreTestTable = true; - } else if (returnValue != null && returnValue.toString().contains(EXCEPTION_IGNORE_SCRIPT_TEST_TAG)) { - IgnoreTestTable = true; - } else if (IgnoreTestTable) { - returnValue = "IGNORE_SCRIPT_TEST"; - } - } else { - returnValue = "IGNORE_SCRIPT_TEST"; + Object instructionResult = instructionResults.get(key); + IgnoreTestTable = evaluateAssertion(instructionResult, IgnoreTestTable, a, key); + } + } + + private boolean evaluateAssertion(Object InstructionResult, boolean IgnoreTestTable, SlimAssertion a, String key) + throws SlimCommunicationException { + + + //Ignore management + if(!ignoreAllTestsCalled) { + if (InstructionResult != null && InstructionResult.toString().contains(EXCEPTION_IGNORE_ALL_TESTS_TAG)) { + ignoreAllTestsCalled = IgnoreTestTable = true; + } else if (InstructionResult != null && InstructionResult.toString().contains(EXCEPTION_IGNORE_SCRIPT_TEST_TAG)) { + IgnoreTestTable = true; + } else if (IgnoreTestTable) { + InstructionResult = "IGNORE_SCRIPT_TEST"; } - //Exception management - if (returnValue != null && returnValue instanceof String && ((String) returnValue).startsWith(EXCEPTION_TAG)) { - SlimExceptionResult exceptionResult = new SlimExceptionResult(key, (String) returnValue); - if (exceptionResult.isStopTestException()) { - stopTestCalled = true; - stopSuiteCalled = PageData.SUITE_SETUP_NAME.equals(testContext.getPageToTest().getName()); - } - if (exceptionResult.isStopSuiteException()) { - stopTestCalled = stopSuiteCalled = true; - } - exceptionResult = a.getExpectation().evaluateException(exceptionResult); - if (exceptionResult != null) { - if (!exceptionResult.isCatchException()) - testExceptionOccurred(a, exceptionResult); - else - testAssertionVerified(a, exceptionResult.catchTestResult()); - } + } else { + InstructionResult = "IGNORE_SCRIPT_TEST"; + } + //Exception management + if (InstructionResult != null && InstructionResult instanceof String && ((String) InstructionResult).startsWith(EXCEPTION_TAG)) { + SlimExceptionResult exceptionResult = new SlimExceptionResult(key, (String) InstructionResult); + if (exceptionResult.isStopTestException()) { + //IgnoreTestTable = stopTestCalled = true; + stopTestCalled = true; + stopSuiteCalled = PageData.SUITE_SETUP_NAME.equals(testContext.getPageToTest().getName()); + } + if (exceptionResult.isStopSuiteException()) { + //IgnoreTestTable = stopTestCalled = stopSuiteCalled = true; + stopTestCalled = stopSuiteCalled = true; + } + exceptionResult = a.getExpectation().evaluateException(exceptionResult); + if (exceptionResult != null) { + if (!exceptionResult.isCatchException()) + testExceptionOccurred(a, exceptionResult); + else + testAssertionVerified(a, exceptionResult.catchTestResult()); } else { - //Normal results - TestResult testResult = a.getExpectation().evaluateExpectation(returnValue); - testAssertionVerified(a, testResult); - - //Retrieve variables set during expectation step - if (testResult != null) { - Map variables = testResult.getVariablesToStore(); - if (variables != null) { - List instructions = new ArrayList<>(variables.size()); - int i = 0; - for (Entry variable : variables.entrySet()) { - instructions.add(new AssignInstruction("assign_" + i++, variable.getKey(), variable.getValue())); - } - //Store variables in context - if (i > 0) { - slimClient.invokeAndGetResponse(instructions); - } + // Silently ignored exception for optional decision table functions + // see class SilentReturnExpectation + testAssertionVerified(a, null); + } + + } else { + //Normal results + TestResult testResult = a.getExpectation().evaluateExpectation(InstructionResult); + testAssertionVerified(a, testResult); + + //Retrieve variables set during expectation step + if (testResult != null) { + Map variables = testResult.getVariablesToStore(); + if (variables != null) { + List instructions = new ArrayList<>(variables.size()); + int i = 0; + for (Entry variable : variables.entrySet()) { + instructions.add(new AssignInstruction("assign_" + i++, variable.getKey(), variable.getValue())); + } + //Store variables in context + if (i > 0) { + slimClient.invokeAndGetResponse(instructions); } } } } + return IgnoreTestTable; } protected void testOutputChunk(TestPage testPage, String output) { @@ -222,6 +272,9 @@ protected void testExceptionOccurred(Assertion assertion, ExceptionResult except testSystemListener.testExceptionOccurred(assertion, exceptionResult); } + protected void testAssertionWillBeExecuted(Assertion assertion) { + testSystemListener.testAssertionWillBeExecuted(assertion); + } // Ensure testSystemStopped is called only once per test system. First call counts. protected void testSystemStopped(Throwable e) { if (testSystemIsStopped) return; diff --git a/src/fitnesse/testsystems/slim/tables/SlimTable.java b/src/fitnesse/testsystems/slim/tables/SlimTable.java index 8ddcb67db..746781212 100644 --- a/src/fitnesse/testsystems/slim/tables/SlimTable.java +++ b/src/fitnesse/testsystems/slim/tables/SlimTable.java @@ -302,6 +302,10 @@ public int getCol() { public int getRow() { return row; } + @Override + public Table getTable() { + return table; + } // Used only by TestXmlFormatter.SlimTestXmlFormatter public String getExpected() {