/* * Copyright Technophobia Ltd 2012 * * This file is part of Substeps. * * Substeps is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Substeps 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Substeps. If not, see <http://www.gnu.org/licenses/>. */ package com.technophobia.substeps.report; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; import com.technophobia.substeps.execution.Feature; import com.technophobia.substeps.execution.node.BasicScenarioNode; import com.technophobia.substeps.execution.node.ExecutionNode; import com.technophobia.substeps.execution.node.FeatureNode; import com.technophobia.substeps.execution.node.RootNode; import com.technophobia.substeps.execution.node.ScenarioNode; import com.technophobia.substeps.execution.node.StepImplementationNode; import com.technophobia.substeps.execution.node.StepNode; /** * @author ian * */ public class DefaultExecutionReportBuilderTest { private static final String STEP_NODE = "stepNode"; private static final String SCENARIO_NAME = "scenarioName"; private static final String RESULT = "result"; private static final String DESCRIPTION = "description"; private static final String FEATURE_NAME = "test feature"; private static final String NOT_RUN = "NOT_RUN"; private static final String PASSED = "PASSED"; private static final String NODE_TYPE = "nodetype"; private static final Logger LOG = Logger.getLogger(DefaultExecutionReportBuilderTest.class); @Rule public TemporaryFolder testFolder = new TemporaryFolder(); RootNode rootNode; List<ExecutionNode> featureNodes = Lists.newArrayList(); List<ExecutionNode> scenarioNodes = Lists.newArrayList(); List<ExecutionNode> stepNodes = Lists.newArrayList(); private Integer nodeIdOffset = Integer.MAX_VALUE; private String arrayCreationLine; private static final String DETAIL_PATTERN = "detail\\[(\\d+)\\]=(\\{.*\\});"; private static final String ARRAY_CREATION_LINE = "var detail = new Array();"; private Map<Integer, JsonObject> details; private DefaultExecutionReportBuilder builder; public void nonFailingMethod() { System.out.println("no fail"); } public void failingMethod() { System.out.println("uh oh"); throw new IllegalStateException("that's it, had enough"); } @Before public void createData() { builder = new DefaultExecutionReportBuilder(); builder.setOutputDirectory(testFolder.getRoot()); rootNode = createRootNode(); builder.addRootExecutionNode(rootNode); } private RootNode createRootNode() { return new RootNode("Description", Collections.singletonList(createFeature(FEATURE_NAME, "test file"))); } private FeatureNode createFeature(String name, String fileName) { final Feature feature = new Feature(name, fileName); final FeatureNode featureNode = new FeatureNode(feature, Collections.<ScenarioNode<?>> singletonList(createScenario(SCENARIO_NAME)), Collections.<String> emptySet()); featureNodes.add(featureNode); return featureNode; } private BasicScenarioNode createScenario(String scenarioName) { BasicScenarioNode scenarioNode = new BasicScenarioNode(scenarioName, null, createSteps(), Collections.<String> emptySet(), 2); scenarioNodes.add(scenarioNode); return scenarioNode; } private List<StepNode> createSteps() { Method nonFailMethod = null; Method failMethod = null; try { nonFailMethod = this.getClass().getMethod("nonFailingMethod"); failMethod = this.getClass().getMethod("failingMethod"); } catch (final Exception e) { Assert.fail(e.getMessage()); } Assert.assertNotNull(nonFailMethod); Assert.assertNotNull(failMethod); StepNode stepImpl1 = createStep(this.getClass(), nonFailMethod, STEP_NODE + "1"); StepNode stepImpl2 = createStep(this.getClass(), failMethod, STEP_NODE + "2"); StepNode stepImpl3 = createStep(this.getClass(), nonFailMethod, STEP_NODE + "3"); return Lists.newArrayList(stepImpl1, stepImpl2, stepImpl3); } private StepImplementationNode createStep(Class<?> stepClass, Method stepMethod, String stepLine) { final StepImplementationNode stepNode = new StepImplementationNode(stepClass, stepMethod, Collections.<String> emptySet(), 3); stepNode.getResult().setStarted(); stepNodes.add(stepNode); stepNode.setLine(stepLine); stepNode.getResult().setFinished(); return stepNode; } @Test public void testDetailReport() throws IOException { builder.buildReport(); decomposeReport(); Assert.assertEquals("The array creation line was not as expected", ARRAY_CREATION_LINE, arrayCreationLine); assertThereAreAsManyDetailsInTheReportAsNodesCreated(); assertRootNodeAsExpected(6 + nodeIdOffset); assertFeatureNodeAsExpected(5 + nodeIdOffset); assertScenarioNodeAsExpected(4 + nodeIdOffset); assertStepNodeAsExpected(3 + nodeIdOffset, STEP_NODE + "3"); assertStepNodeAsExpected(2 + nodeIdOffset, STEP_NODE + "2"); assertStepNodeAsExpected(1 + nodeIdOffset, STEP_NODE + "1"); } private void assertRootNodeAsExpected(int index) { JsonObject rootNode = details.get(index); Assert.assertNotNull(rootNode); assertBasics(index, rootNode, "RootNode", NOT_RUN); JsonArray children = rootNode.getAsJsonArray("children"); Assert.assertEquals(1, children.size()); JsonObject child = (JsonObject) Iterables.getOnlyElement(children); Assert.assertEquals(NOT_RUN, child.get(RESULT).getAsString()); Assert.assertEquals(FEATURE_NAME, child.get(DESCRIPTION).getAsString()); } private void assertFeatureNodeAsExpected(int index) { JsonObject featureNode = details.get(index); assertBasics(index, featureNode, "FeatureNode", NOT_RUN); Assert.assertEquals(FEATURE_NAME, featureNode.get(DESCRIPTION).getAsString()); JsonArray children = featureNode.getAsJsonArray("children"); Assert.assertEquals(1, children.size()); JsonObject child = (JsonObject) Iterables.getOnlyElement(children); Assert.assertEquals(NOT_RUN, child.get(RESULT).getAsString()); Assert.assertEquals(SCENARIO_NAME, child.get(DESCRIPTION).getAsString()); } private void assertScenarioNodeAsExpected(int index) { JsonObject scenarioNode = details.get(index); assertBasics(index, scenarioNode, "BasicScenarioNode", NOT_RUN); Assert.assertEquals(SCENARIO_NAME, scenarioNode.get(DESCRIPTION).getAsString()); JsonArray children = scenarioNode.getAsJsonArray("children"); Assert.assertEquals(stepNodes.size(), children.size()); Iterator<JsonElement> childIterator = children.iterator(); assertChildStepNode((JsonObject) childIterator.next(), "stepNode1"); assertChildStepNode((JsonObject) childIterator.next(), "stepNode2"); assertChildStepNode((JsonObject) childIterator.next(), "stepNode3"); } private void assertChildStepNode(JsonObject child, String description) { Assert.assertEquals(PASSED, child.get(RESULT).getAsString()); Assert.assertEquals(description, child.get(DESCRIPTION).getAsString()); } private void assertStepNodeAsExpected(int index, String description) { JsonObject stepNode = details.get(index); assertBasics(index, stepNode, "Step", PASSED); Assert.assertEquals(description, stepNode.get(DESCRIPTION).getAsString()); Assert.assertFalse(stepNode.has("children")); } private void assertBasics(int index, JsonObject node, String nodeType, String result) { Assert.assertEquals(nodeType, node.get(NODE_TYPE).getAsString()); Assert.assertEquals(result, node.get(RESULT).getAsString()); Assert.assertEquals(index, node.get("id").getAsInt()); } private void assertThereAreAsManyDetailsInTheReportAsNodesCreated() { int numberOfNodes = 1 + featureNodes.size() + scenarioNodes.size() + stepNodes.size(); Assert.assertEquals("There should have been a detail line for each node", numberOfNodes, details.size()); } private BufferedReader getDetailReportReader() throws IOException { File detailFile = new File(testFolder.getRoot(), DefaultExecutionReportBuilder.FEATURE_REPORT_FOLDER + File.separator + DefaultExecutionReportBuilder.JSON_DETAIL_DATA_FILENAME); return new BufferedReader(new FileReader(detailFile)); } private void decomposeReport() throws IOException { BufferedReader reportReader = null; LOG.debug("decomposeReport() entered"); try { reportReader = getDetailReportReader(); arrayCreationLine = reportReader.readLine(); Pattern pattern = Pattern.compile(DETAIL_PATTERN); JsonParser parser = new JsonParser(); details = Maps.newHashMap(); String line; while ((line = reportReader.readLine()) != null) { LOG.debug("Line found in detail report = " + line); Matcher matcher = pattern.matcher(line); Assert.assertTrue("A line in the report did not conform to the expected format, line was '" + line + "'", matcher.matches()); String index = matcher.group(1); String detail = matcher.group(2); JsonObject json = null; try { json = (JsonObject) parser.parse(detail); } catch (JsonSyntaxException jse) { jse.printStackTrace(); Assert.fail("Invalid json found '" + detail + "'"); } int indexInt = Integer.valueOf(index); nodeIdOffset = indexInt < nodeIdOffset ? indexInt - 1 : nodeIdOffset; details.put(indexInt, json); } } finally { if (reportReader != null) { reportReader.close(); } } } }