//Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
//Released under the terms of the CPL Common Public License version 1.0.
package fitnesse.responders.run.slimResponder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import fitnesse.FitNesseContext;
import fitnesse.html.HtmlUtil;
import fitnesse.http.MockRequest;
import fitnesse.http.SimpleResponse;
import fitnesse.testsystems.slim.SlimCommandRunningClient;
import fitnesse.testsystems.Assertion;
import fitnesse.testsystems.ExceptionResult;
import fitnesse.testsystems.TestPage;
import fitnesse.testsystems.TestResult;
import fitnesse.testsystems.TestSummary;
import fitnesse.testsystems.TestSystem;
import fitnesse.testsystems.TestSystemListener;
import fitnesse.testsystems.slim.*;
import fitnesse.testutil.FitNesseUtil;
import fitnesse.wiki.*;
import fitnesse.wiki.fs.InMemoryPage;
import org.junit.Before;
import org.junit.Test;
public class HtmlSlimResponderTest {
private FitNesseContext context;
private MockRequest request;
protected SlimResponder responder;
private WikiPage testPage;
public String testResults;
protected SimpleResponse response;
private CustomComparatorRegistry customComparatorRegistry;
private void assertTestResultsContain(String fragment) {
String unescapedResults = unescape(testResults);
assertTrue(unescapedResults, unescapedResults.contains(fragment));
}
private void assertTestResultsDoNotContain(String fragment) {
String unescapedResults = unescape(testResults);
assertTrue(unescapedResults, !unescapedResults.contains(fragment));
}
private void getResultsForPageContents(String pageContents) throws Exception {
request.setResource("TestPage");
PageData data = testPage.getData();
data.setContent(data.getContent() + "\n" + pageContents);
testPage.commit(data);
response = (SimpleResponse) responder.makeResponse(context, request);
testResults = response.getContent();
}
@Before
public void setUp() throws Exception {
WikiPage root = InMemoryPage.makeRoot("root");
context = FitNesseUtil.makeTestContext(root);
request = new MockRequest();
customComparatorRegistry = new CustomComparatorRegistry();
responder = getSlimResponder(customComparatorRegistry);
responder.setFastTest(true);
// Enforce the test runner here, to make sure we're talking to the right
// system
testPage = WikiPageUtil.addPage(root, PathParser.parse("TestPage"),
"!define TEST_RUNNER {fitnesse.slim.SlimService}\n!path classes");
SlimClientBuilder.clearSlimPortOffset();
}
protected SlimResponder getSlimResponder(CustomComparatorRegistry customComparatorRegistry) {
return new HtmlSlimResponder(customComparatorRegistry);
}
@Test
public void tableWithoutPrefixWillBeConstructed() throws Exception {
getResultsForPageContents("|XX|\n");
//assertTestResultsContain("<td>XX <span class=\"error\">Could not invoke constructor for XX[0]</span> <span class=\"error\">The instance decisionTable_0.table. does not exist</span></td>");
assertTestResultsContain("<td>XX <span class=\"error\">Could not invoke constructor for XX[0]</span></td>");
}
@Test
public void emptyQueryTable() throws Exception {
getResultsForPageContents("|Query:x|\n");
assertTestResultsContain("Query tables must have at least two rows.");
}
@Test
public void queryFixtureHasNoQueryFunction() throws Exception {
getResultsForPageContents("!|Query:fitnesse.slim.test.TestSlim|\n"
+ "|x|y|\n");
assertTestResultsContain("Method query[0] not found in fitnesse.slim.test.TestSlim");
}
@Test
public void emptyOrderedQueryTable() throws Exception {
getResultsForPageContents("|ordered query:x|\n");
assertTestResultsContain("Query tables must have at least two rows.");
}
@Test
public void orderedQueryFixtureHasNoQueryFunction() throws Exception {
getResultsForPageContents("!|ordered query:fitnesse.slim.test.TestSlim|\n"
+ "|x|y|\n");
assertTestResultsContain("Method query[0] not found in fitnesse.slim.test.TestSlim");
}
@Test
public void emptySubsetQueryTable() throws Exception {
getResultsForPageContents("|subset query:x|\n");
assertTestResultsContain("Query tables must have at least two rows.");
}
@Test
public void subsetQueryFixtureHasNoQueryFunction() throws Exception {
getResultsForPageContents("!|subset query:fitnesse.slim.test.TestSlim|\n"
+ "|x|y|\n");
assertTestResultsContain("Method query[0] not found in fitnesse.slim.test.TestSlim");
}
@Test
public void scriptTableWithBadConstructor() throws Exception {
getResultsForPageContents("!|Script|NoSuchClass|\n");
assertTestResultsContain("<span class=\"error\">Could not invoke constructor for NoSuchClass");
}
@Test
public void emptyImportTable() throws Exception {
getResultsForPageContents("|Import|\n");
assertTestResultsContain("Import tables must have at least two rows.");
}
@Test
public void emptyTableTable() throws Exception {
getResultsForPageContents("!|Table:TableFixture|\n");
assertTestResultsContain("<span class=\"error\">Could not invoke constructor for TableFixture[0]</span>");
}
@Test
public void tableFixtureHasNoDoTableFunction() throws Exception {
getResultsForPageContents("!|Table:fitnesse.slim.test.TestSlim|\n"
+ "|a|b|\n");
assertTestResultsContain("Method doTable[1] not found in fitnesse.slim.test.TestSlim.");
}
@Test
public void simpleDecisionTable() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|returnInt?|\n" + "|7|\n");
assertTestResultsContain("<span class=\"pass\">7</span>");
}
@Test
public void decisionTableIgnoresMethodMissingForResetExecuteAndTable()
throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.DummyDecisionTable|\n"
+ "|x?|\n" + "|1|\n");
assertEquals(0, responder.getTestSummary().getExceptions());
}
@Test
public void decisionTableWithNoResetDoesNotCountExceptionsForExecute()
throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.DummyDecisionTableWithExecuteButNoReset|\n"
+ "|x?|\n" + "|1|\n");
assertEquals(0, responder.getTestSummary().getExceptions());
}
@Test
public void queryTableWithoutTableFunctionIgnoresMissingMethodException()
throws Exception {
getResultsForPageContents("!|query:fitnesse.slim.test.DummyQueryTableWithNoTableMethod|\n"
+ "|x|\n" + "|1|\n");
assertEquals(0, responder.getTestSummary().getExceptions());
}
@Test
public void decisionTableWithExecuteThatThrowsDoesShowsException()
throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.DecisionTableExecuteThrows|\n"
+ "|x?|\n" + "|1|\n");
assertEquals(1, responder.getTestSummary().getExceptions());
assertTestResultsContain("EXECUTE_THROWS");
}
@Test
public void tableWithException() throws Exception {
getResultsForPageContents("!|DT:NoSuchClass|\n" + "|returnInt?|\n"
+ "|7|\n");
assertTestResultsContain("<span class=\"error\">Could not invoke constructor for NoSuchClass");
}
@Test
public void tableWithBadConstructorHasException() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|badArgument|\n"
+ "|returnConstructorArgument?|\n" + "|3|\n");
TableScanner ts = new HtmlTableScanner(testPage.getHtml());
ts.getTable(0);
assertTestResultsContain("Could not invoke constructor");
}
@Test
public void tableWithBadVariableHasException() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|noSuchVar|\n" + "|3|\n");
assertTestResultsContain("<span class=\"error\">Method setNoSuchVar[1] not found in fitnesse.slim.test.TestSlim");
}
@Test
public void tableWithStopTestMessageException() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|throwStopTestExceptionWithMessage?|\n" + "| once |\n"
+ "| twice |\n");
assertTestResultsContain("<td>once <span class=\"fail\">Stop Test</span></td>");
assertTestResultsContain("<td>twice <span class=\"ignore\">Test not run</span>");
}
@Test
public void tableWithMessageException() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|throwExceptionWithMessage?|\n" + "| once |\n");
assertTestResultsContain("<td>once <span class=\"error\">Test message</span></td>");
}
@Test
public void tableWithStopTestExceptionThrown() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|throwNormal?| throwStopping? |\n"
+ "| first | second |\n"
+ "| should fail1| true |\n" + "\n\n"
+ "!|DT:fitnesse.slim.test.ThrowException|\n" + "|throwNormal?|\n"
+ "| should fail2|\n");
assertTestResultsContain("<tr class=\"exception closed\">");
assertTestResultsContain("<td class=\"fail\">first</td>");
assertTestResultsContain("<td class=\"fail\">second</td>");
assertTestResultsContain("<tr class=\"exception-detail closed-detail\">");
assertTestResultsContain("<td>should fail1 <span class=\"ignore\">Test not run</span></td>");
assertTestResultsContain("<td>should fail2 <span class=\"ignore\">Test not run</span></td>");
}
@Test
public void tableWithSymbolSubstitution() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|string|getStringArg?|\n" + "|Bob|$V=|\n" + "|$V|$V|\n");
TableScanner ts = getScannedResults();
Table dt = ts.getTable(0);
assertEquals("$V<-[Bob]", unescape(dt.getCellContents(1, 2)));
assertEquals("$V->[Bob]", unescape(dt.getCellContents(0, 3)));
}
protected TableScanner getScannedResults() throws Exception {
return new HtmlTableScanner(testResults);
}
private String unescape(String x) {
return HtmlUtil.unescapeWiki(HtmlUtil.unescapeHTML(x));
}
@Test
public void substituteSymbolIntoExpression() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|string|getStringArg?|\n" + "|3|$A=|\n" + "|2|<$A|\n" + "|5|$B=|\n"
+ "|4|$A<_<$B|\n");
TableScanner ts = getScannedResults();
Table dt = ts.getTable(0);
assertEquals("<span class=\"pass\">2<$A->[3]</span>",
unescape(dt.getCellContents(1, 3)));
assertEquals("<span class=\"pass\">$A->[3]<4<$B->[5]</span>",
unescape(dt.getCellContents(1, 5)));
}
@Test
public void tableWithExpression() throws Exception {
getResultsForPageContents("!|DT:fitnesse.slim.test.TestSlim|\n"
+ "|string|getStringArg?|\n" + "|${=3+4=}|7|\n");
TableScanner ts = getScannedResults();
Table dt = ts.getTable(0);
assertEquals("<span class=\"pass\">7</span>", dt.getCellContents(1, 2));
}
@Test
public void noSuchConverter() throws Exception {
getResultsForPageContents("|!-DT:fitnesse.slim.test.TestSlim-!|\n"
+ "|noSuchConverter|noSuchConverter?|\n" + "|x|x|\n");
TableScanner ts = getScannedResults();
Table dt = ts.getTable(0);
assertEquals(
"x <span class=\"error\">No converter for fitnesse.slim.test.TestSlim$NoSuchConverter.</span>",
dt.getCellContents(0, 2));
}
@Test
public void returnedListsBecomeStrings() throws Exception {
getResultsForPageContents("!|script|\n"
+ "|start|fitnesse.slim.test.TestSlim|\n" + "|one list|1,2|\n"
+ "|check|get list arg|[1, 2]|\n");
assertTestResultsContain("<td><span class=\"pass\">[1, 2]</span></td>");
}
@Test
public void nullStringReturned() throws Exception {
getResultsForPageContents("!|fitnesse.slim.test.TestSlim|\n"
+ "|nullString?|\n" + "|null|\n");
assertTestResultsContain("<td><span class=\"pass\">null</span></td>");
}
@Test
public void reportableExceptionsAreReported() throws Exception {
getResultsForPageContents("!|fitnesse.slim.test.ExecuteThrowsReportableException|\n"
+ "|x|\n" + "|1|\n");
assertTestResultsContain("A Reportable Exception");
}
@Test
public void versionMismatchIsNotReported() throws Exception {
getResultsForPageContents("");
assertTestResultsDoNotContain("Slim Protocol Version Error");
}
@Test
// TODO: Setting a constant here. We should use dependency inversion
// for the minimum require slim version to get this under test
// properly
// Had to fix this with the introduction of JUnit 4.11 since the
// ordering is different.
public void versionMismatchIsReported() throws Exception {
double oldVersionNumber = SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION;
SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION = 1000.0; // I doubt will ever get
// here.
try {
getResultsForPageContents("");
assertTestResultsContain("Slim Protocol Version Error");
} finally {
SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION = oldVersionNumber;
}
}
@Test
public void checkTestClassPrecededByDefine() throws Exception {
getResultsForPageContents("!define PI {3.141592}\n" + "!path classes\n"
+ "!path fitnesse.jar\n" + "|fitnesse.testutil.PassFixture|\n");
assertTestResultsContain("PassFixture");
}
@Test
public void emptyScenarioTable() throws Exception {
getResultsForPageContents("|Scenario|\n");
assertTestResultsContain("Scenario tables must have a name.");
}
@Test
public void scenarioTableIsRegistered() throws Exception {
getResultsForPageContents("|Scenario|myScenario|\n");
assertTrue("scenario should be registered", responder.testSystem.getTestContext()
.getScenarios().iterator().next().getScenarioName().equals("myScenario"));
}
@Test
public void customComparatorReturnsPass() throws Exception {
customComparatorRegistry.addCustomComparator("equalsIgnoreCase", new EqualsIgnoreCaseComparator());
getResultsForPageContents("!|script|\n"
+ "|start|fitnesse.slim.test.TestSlim|\n"
+ "|check|return string|equalsIgnoreCase:STRING|\n");
assertTestResultsContain("<td><span class=\"pass\">STRING matches string</span></td>");
}
@Test
public void customComparatorReturnsFail() throws Exception {
customComparatorRegistry.addCustomComparator("equalsIgnoreCase", new EqualsIgnoreCaseComparator());
getResultsForPageContents("!|script|\n"
+ "|start|fitnesse.slim.test.TestSlim|\n"
+ "|check|return string|equalsIgnoreCase:STRINGS|\n");
assertTestResultsContain("<td><span class=\"fail\">STRINGS doesn't match string</span></td>");
}
@Test
public void customComparatorReturnsMessage() throws Exception {
customComparatorRegistry.addCustomComparator("exceptionMessage", new ExceptionMessageComparator());
getResultsForPageContents("!|script|\n"
+ "|start|fitnesse.slim.test.TestSlim|\n"
+ "|check|return string|exceptionMessage:STRINGS|\n");
assertTestResultsContain("<td><span class=\"fail\">STRINGS doesn't match string:\nexception message</span></td>");
}
class EqualsIgnoreCaseComparator implements CustomComparator {
@Override
public boolean matches(String actual, String expected) {
return expected.equalsIgnoreCase(actual);
}
}
class ExceptionMessageComparator implements CustomComparator {
@Override
public boolean matches(String actual, String expected) {
throw new RuntimeException("exception message");
}
}
}