diff --git a/README.md b/README.md index fbe67bab..9ecedee8 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Requirements * Replaced Apache config with [Typesafe Config](https://github.com/typesafehub/config) - similar functionality but provides better nesting of properties, variable substitution * Added System property switch to use original properties files over new .conf files (`-Dsubsteps.use.dot.properties=true`) * Enable any parameters to be substituted with values from config - user ${config.expression}. Delimitters can be specified and Charset conversion too, see core-api reference.conf for details +* Enabled arguments to be evaluated at runtime against objects in the execution context 1.0.3 ----- diff --git a/api/src/main/java/com/technophobia/substeps/runner/ExecutionContext.java b/api/src/main/java/com/technophobia/substeps/runner/ExecutionContext.java index b0d291d1..9a6a8f88 100644 --- a/api/src/main/java/com/technophobia/substeps/runner/ExecutionContext.java +++ b/api/src/main/java/com/technophobia/substeps/runner/ExecutionContext.java @@ -18,8 +18,12 @@ */ package com.technophobia.substeps.runner; +import com.google.common.collect.Sets; import com.technophobia.substeps.model.Scope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -32,6 +36,8 @@ */ public final class ExecutionContext { + private static final Logger log = LoggerFactory.getLogger(ExecutionContext.class); + private static final ThreadLocal executionContextThreadLocal = new ThreadLocal() { @Override protected ExecutionContext initialValue() { @@ -78,4 +84,28 @@ private Object getInternal(final Scope scope, final String key) { public static void clear(final Scope scope) { executionContextThreadLocal.get().scopedData.remove(scope); } + + public static Map flatten(){ + + // return a single Map with the items in the narrowest scope remaining + + ExecutionContext ec = executionContextThreadLocal.get(); + + Map newMaster = new HashMap(); + for (Scope scope : Scope.values()){ + + Map scopedMap = ec.scopedData.get(scope); + if (scopedMap != null) { + Sets.SetView intersection = Sets.intersection(newMaster.keySet(), scopedMap.keySet()); + + if (!intersection.isEmpty()) { + StringBuilder buf = new StringBuilder(); + intersection.stream().forEach(s -> log.warn("existing key value " + s + " is being overwritten flattening the ExecutionContext")); + } + + newMaster.putAll(scopedMap); + } + } + return newMaster; + } } diff --git a/core/pom.xml b/core/pom.xml index fffb451c..6d900aa8 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -67,12 +67,7 @@ velocity velocity 1.5 - - - - - - + org.apache.commons @@ -97,6 +92,12 @@ ${json4s.version} + + org.apache.commons + commons-jexl3 + 3.0 + + junit diff --git a/core/src/main/java/com/technophobia/substeps/model/Util.java b/core/src/main/java/com/technophobia/substeps/model/Arguments.java similarity index 64% rename from core/src/main/java/com/technophobia/substeps/model/Util.java rename to core/src/main/java/com/technophobia/substeps/model/Arguments.java index fe62417b..eec14b17 100644 --- a/core/src/main/java/com/technophobia/substeps/model/Util.java +++ b/core/src/main/java/com/technophobia/substeps/model/Arguments.java @@ -21,7 +21,9 @@ import com.technophobia.substeps.model.exception.SubstepsRuntimeException; import com.technophobia.substeps.model.parameter.Converter; import com.technophobia.substeps.model.parameter.ConverterFactory; +import com.technophobia.substeps.runner.ExecutionContext; import com.typesafe.config.Config; +import org.apache.commons.jexl3.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,8 +37,8 @@ /** * @author ian */ -public final class Util { - private static final Logger log = LoggerFactory.getLogger(Util.class); +public final class Arguments { + private static final Logger log = LoggerFactory.getLogger(Arguments.class); private static final boolean substituteParameters = Configuration.INSTANCE.getConfig().getBoolean("parameter.substitution.enabled"); private static final String startDelimiter = Configuration.INSTANCE.getConfig().getString("parameter.substitution.start"); @@ -46,33 +48,64 @@ public final class Util { private static final String normalizeFrom = Configuration.INSTANCE.getConfig().getString("parameter.substitution.normalize.from"); private static final String normalizeTo = Configuration.INSTANCE.getConfig().getString("parameter.substitution.normalize.to"); + private static final JexlEngine jexl = new JexlBuilder().cache(512).strict(false).silent(false).create(); - private Util() { + private Arguments() { // no op } + public static Object evaluateExpression(String expressionWithDelimiters){ - public static String substituteValues(String src) { + // TODO - check that the expression doesn't contain any of the bad words + // or and eq ne lt gt le ge div mod not null true false new var return + // any of those words need to be qutoed or [' '] + // http://commons.apache.org/proper/commons-jexl/reference/syntax.html + + // try evaluating this expression against the executionContext + + // TODO check flag to see whether we can evaluate things from the ec + + if (expressionWithDelimiters != null && substituteParameters && expressionWithDelimiters.startsWith(startDelimiter)) { + String expression = StringUtils.stripStart(StringUtils.stripEnd(expressionWithDelimiters, endDelimiter), startDelimiter); + + JexlContext context = new MapContext(ExecutionContext.flatten()); + JexlExpression e = jexl.createExpression(expression); + + return e.evaluate(context); + } + else { + return expressionWithDelimiters; + } + } + + public static String substituteValues(String src) { if (src != null && substituteParameters && src.startsWith(startDelimiter)){ String key = StringUtils.stripStart(StringUtils.stripEnd(src, endDelimiter), startDelimiter); - String substitute = Configuration.INSTANCE.getString(key); - if (substitute == null){ - throw new SubstepsRuntimeException("Failed to resolve property " + src + " to be substituted "); - } - String normalizedValue = substitute; - - if (normalizeValues) { - // This part will support the conversion of properties files containing accented characters - try { - normalizedValue = new String(substitute.getBytes(normalizeFrom), normalizeTo); - } catch (UnsupportedEncodingException e) { - log.error("error substituting accented characters", e); + + String normalizedValue = src; + + if (Configuration.INSTANCE.getConfig().hasPath(key)){ + String substitute = Configuration.INSTANCE.getString(key); + + if (substitute == null){ + throw new SubstepsRuntimeException("Failed to resolve property " + src + " to be substituted "); + } + normalizedValue = substitute; + if (normalizeValues) { + // This part will support the conversion of properties files containing accented characters + try { + normalizedValue = new String(substitute.getBytes(normalizeFrom), normalizeTo); + } catch (UnsupportedEncodingException e) { + log.error("error substituting accented characters", e); + } } } + + return normalizedValue; } return src; @@ -83,7 +116,7 @@ public static String substituteValues(String src) { // - could they be combined ?? public static String[] getArgs(final String patternString, final String sourceString, final String[] keywordPrecedence, Config cfg) { - log.debug("Util getArgs String[] with pattern: " + patternString + " and sourceStr: " + log.debug("Arguments getArgs String[] with pattern: " + patternString + " and sourceStr: " + sourceString); String[] rtn = null; @@ -148,7 +181,7 @@ public static String[] getArgs(final String patternString, final String sourceSt public static List getArgs(final String patternString, final String sourceString, final Class[] parameterTypes, final Class>[] converterTypes) { - log.debug("Util getArgs List with pattern: " + patternString + " and sourceStr: " + log.debug("Arguments getArgs List with pattern: " + patternString + " and sourceStr: " + sourceString); List argsList = null; @@ -170,8 +203,20 @@ public static List getArgs(final String patternString, final String sour argsList = new ArrayList(); } String substituted = substituteValues(arg); - argsList.add(getObjectArg(substituted, parameterTypes[argIdx], converterTypes[argIdx])); +// if (substituted.equals(arg)){ +// // no change, lets try against the context +// Object result = evaluateExpression(arg); +// if (result != null){ +// argsList.add(result); +// } +// else { +// argsList.add(getObjectArg(substituted, parameterTypes[argIdx], converterTypes[argIdx])); +// } +// } +// else { + argsList.add(getObjectArg(substituted, parameterTypes[argIdx], converterTypes[argIdx])); +// } } argIdx++; } diff --git a/core/src/main/java/com/technophobia/substeps/model/ParentStep.java b/core/src/main/java/com/technophobia/substeps/model/ParentStep.java index 052dda7b..e62259ca 100644 --- a/core/src/main/java/com/technophobia/substeps/model/ParentStep.java +++ b/core/src/main/java/com/technophobia/substeps/model/ParentStep.java @@ -74,7 +74,7 @@ public List getSteps() { public void initialiseParamValues(final Step step) { final HashMap map = new HashMap(); - final String[] paramValues = Util.getArgs(this.parent.getPattern(), + final String[] paramValues = Arguments.getArgs(this.parent.getPattern(), step.getLine(), null, Configuration.INSTANCE.getConfig()); if (paramValues != null) { @@ -97,7 +97,7 @@ public void initialiseParamValues(final int lineNumber, final String line, Strin log.debug("initialiseParamValues with line: " + line); - final String[] paramValues = Util.getArgs(this.parent.getPattern(), + final String[] paramValues = Arguments.getArgs(this.parent.getPattern(), line, keywordPrecedence, Configuration.INSTANCE.getConfig()); if (paramValues != null) { diff --git a/core/src/main/java/com/technophobia/substeps/runner/builder/SubstepNodeBuilder.java b/core/src/main/java/com/technophobia/substeps/runner/builder/SubstepNodeBuilder.java index f29fea27..2612c371 100644 --- a/core/src/main/java/com/technophobia/substeps/runner/builder/SubstepNodeBuilder.java +++ b/core/src/main/java/com/technophobia/substeps/runner/builder/SubstepNodeBuilder.java @@ -343,7 +343,7 @@ private Object[] getStepMethodArguments(final String stepParameter, final Map argsList = Util.getArgs(stepImplementationPattern, substitutedStepParam, parameterTypes, + List argsList = Arguments.getArgs(stepImplementationPattern, substitutedStepParam, parameterTypes, converterTypes); if (inlineTable != null) { diff --git a/core/src/main/java/com/technophobia/substeps/runner/node/StepImplementationNodeRunner.java b/core/src/main/java/com/technophobia/substeps/runner/node/StepImplementationNodeRunner.java index 8bbe9f92..9bea9d2f 100644 --- a/core/src/main/java/com/technophobia/substeps/runner/node/StepImplementationNodeRunner.java +++ b/core/src/main/java/com/technophobia/substeps/runner/node/StepImplementationNodeRunner.java @@ -20,14 +20,29 @@ import com.technophobia.substeps.execution.node.RootNodeExecutionContext; import com.technophobia.substeps.execution.node.StepImplementationNode; -import com.technophobia.substeps.model.Scope; +import com.technophobia.substeps.model.*; +import com.technophobia.substeps.model.parameter.Converter; +import com.technophobia.substeps.runner.ExecutionNodeRunner; import com.technophobia.substeps.runner.ProvidesScreenshot; import com.technophobia.substeps.runner.SubstepExecutionFailure; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class StepImplementationNodeRunner extends AbstractNodeRunner { + private static final Logger log = LoggerFactory.getLogger(StepImplementationNodeRunner.class); + + + @Override protected boolean execute(StepImplementationNode node, RootNodeExecutionContext context) { @@ -35,8 +50,28 @@ protected boolean execute(StepImplementationNode node, RootNodeExecutionContext try { + // run through any args - if there's any expressions in there, evaluate them now + Object[] evaluatedArgs = null; + + if (node.getMethodArgs() != null && node.getMethodArgs().length > 0) { + List evaluatedArgsList = new ArrayList<>(); + for (Object o : node.getMethodArgs()) { + + if (o instanceof String) { + + Object result = Arguments.evaluateExpression((String) o); + evaluatedArgsList.add(result); + + } else { + evaluatedArgsList.add(o); + } + } + evaluatedArgs = evaluatedArgsList.toArray(); + } + + context.getMethodExecutor().executeMethod(node.getTargetClass(), node.getTargetMethod(), - node.getMethodArgs()); + evaluatedArgs); context.setTestsHaveRun(); success = true; diff --git a/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java b/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java index ef69241f..289ab795 100644 --- a/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java +++ b/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java @@ -24,7 +24,7 @@ import com.technophobia.substeps.execution.Feature; import com.technophobia.substeps.execution.ImplementationCache; import com.technophobia.substeps.execution.node.*; -import com.technophobia.substeps.model.Util; +import com.technophobia.substeps.model.Arguments; import com.technophobia.substeps.model.exception.SubstepsConfigurationException; import com.technophobia.substeps.model.exception.UnimplementedStepException; import com.technophobia.substeps.runner.setupteardown.Annotations.BeforeAllFeatures; @@ -713,10 +713,10 @@ public void testArgSubstituion() { final String patternString = "Given a substep that takes one parameter \"([^\"]*)\""; final String[] keywordPrecedence = new String[]{"Given", "And"}; - String[] args1 = Util.getArgs(patternString, srcString1, keywordPrecedence, cfg); + String[] args1 = Arguments.getArgs(patternString, srcString1, keywordPrecedence, cfg); - String[] args2 = Util.getArgs(patternString, srcString2, keywordPrecedence, cfg); + String[] args2 = Arguments.getArgs(patternString, srcString2, keywordPrecedence, cfg); Assert.assertNotNull(args2); Assert.assertThat(args2[0], is("src2")); @@ -724,7 +724,7 @@ public void testArgSubstituion() { Assert.assertNotNull(args1); Assert.assertThat(args1[0], is("src1")); - String[] args3 = Util.getArgs(patternString, srcString3, keywordPrecedence, cfg); + String[] args3 = Arguments.getArgs(patternString, srcString3, keywordPrecedence, cfg); Assert.assertNotNull(args3); Assert.assertThat(args3[0], is("bob")); diff --git a/core/src/test/java/com/technophobia/substeps/runner/ParsingTests.java b/core/src/test/java/com/technophobia/substeps/runner/ParsingTests.java index fc65d2ca..5fe7cf70 100755 --- a/core/src/test/java/com/technophobia/substeps/runner/ParsingTests.java +++ b/core/src/test/java/com/technophobia/substeps/runner/ParsingTests.java @@ -20,6 +20,7 @@ package com.technophobia.substeps.runner; import com.technophobia.substeps.model.ParentStep; +import com.technophobia.substeps.model.Scope; import com.technophobia.substeps.model.Step; import org.junit.Assert; import org.junit.Test; @@ -36,6 +37,8 @@ * @author ian */ public class ParsingTests { + + @Test public void testRegEx() { final String stepParameter = "bob "; @@ -199,7 +202,7 @@ public void testParentParameterChaining() { final ParentStep parentStep = new ParentStep(aParentSubStep); parentStep.initialiseParamValues(topLevelStepReDefinedInSubSteps); - // String[] paramValues = Util.getArgs(this.parent.pattern, step.param); + // String[] paramValues = Arguments.getArgs(this.parent.pattern, step.param); final Map paramValueMap = parentStep.getParamValueMap().getParameters(); Assert.assertNotNull(paramValueMap); diff --git a/core/src/test/scala/com/technophobia/substeps/model/ArgumentsTest.scala b/core/src/test/scala/com/technophobia/substeps/model/ArgumentsTest.scala new file mode 100644 index 00000000..a0d3f0e4 --- /dev/null +++ b/core/src/test/scala/com/technophobia/substeps/model/ArgumentsTest.scala @@ -0,0 +1,35 @@ +package com.technophobia.substeps.model + +import com.technophobia.substeps.runner.ExecutionContext +import org.scalatest.{FunSuite, Matchers} + +/** + * Created by ian on 13/01/17. + */ +class Sample(name : String, other : Other){ + def getName() = name + def getOther() = other +} + +class Other(name : String){ + def getName() = name +} + +class ArgumentsTest extends FunSuite with Matchers{ + + test("test Arguments expression evaluation"){ + val res1 = Arguments.evaluateExpression("${doesnt.exist}") + res1 should be (null) + + ExecutionContext.put(Scope.SUITE, "key", new Sample("suite", new Other("o1"))) + + ExecutionContext.put(Scope.SCENARIO, "key", new Sample("scenario", new Other("o2"))) + + val res2 = Arguments.evaluateExpression("${key.name}") + res2 should be ("scenario") + + val res3 = Arguments.evaluateExpression("${key.other.name}") + res3 should be ("o2") + + } +} diff --git a/core/src/test/scala/org/substeps/runner/ExpressionEvaluationTest.scala b/core/src/test/scala/org/substeps/runner/ExpressionEvaluationTest.scala new file mode 100644 index 00000000..519b9ad9 --- /dev/null +++ b/core/src/test/scala/org/substeps/runner/ExpressionEvaluationTest.scala @@ -0,0 +1,148 @@ +package org.substeps.runner + +import java.io.File + +import com.technophobia.substeps.execution.ImplementationCache +import com.technophobia.substeps.model.SubSteps.StepImplementations +import com.technophobia.substeps.model._ +import com.technophobia.substeps.runner._ +import com.technophobia.substeps.runner.builder.ExecutionNodeTreeBuilder +import com.technophobia.substeps.runner.setupteardown.SetupAndTearDown +import com.technophobia.substeps.runner.syntax.SyntaxBuilder +import org.scalatest.{FlatSpec, ShouldMatchers} +import org.slf4j.LoggerFactory +import org.substeps.report.ExecutionResultsCollector + +import scala.collection.JavaConverters._ + + +/** + * Created by ian on 13/01/17. + */ +class ExpressionEvaluationTest extends FlatSpec with ShouldMatchers with FeatureFilesFromSource{ + + private val log = LoggerFactory.getLogger(classOf[ParsingFromSourceTests]) + + + "step execution" must "evaluate expressions" in { + + val simpleFeature = + """ + | Feature: a simple feature + | Scenario: config and runtime expression scenario + | A step with a value from config "${users.default.name}" + | SetupContext + | A step with param from context "${key.other.name}" + | + """.stripMargin + + + class Sample(name : String, other : Other){ + def getName() = name + def getOther() = other + } + + class Other(name : String){ + def getName() = name + } + + @StepImplementations + class StepImpls (){ + + @SubSteps.Step("""A step with a value from config "([^"]*)"""") + def stepPassedFromConfig(arg : String) = log.debug("stepPassedFromConfig: " + arg) + + @SubSteps.Step("SetupContext") + def setupContext() = { + ExecutionContext.put(Scope.SCENARIO, "key", new Sample("scenario", new Other("fromContext"))) + + log.debug("SetupContext") + } + + @SubSteps.Step("""A step with param from context "([^"]*)"""") + def stepPassedFromContext(arg: String) = log.debug("stepPassedFromContext: " + arg) + } + + val featureFile = createFeatureFile(simpleFeature, "expression-evaluation.feature") + + val stepImplementationClasses : List[java.lang.Class[_]] = List(classOf[StepImpls]) + + val executionConfig = new SubstepsExecutionConfig + + executionConfig.setStepImplementationClasses(stepImplementationClasses.asJava) + + val syntax: Syntax = SyntaxBuilder.buildSyntax(stepImplementationClasses.asJava, new PatternMap[ParentStep]()) + + val parameters: TestParameters = new TestParameters(new TagManager(""), syntax, List(featureFile).asJava) + + val cfgWrapper = new ExecutionConfigWrapper(executionConfig) + val nodeTreeBuilder: ExecutionNodeTreeBuilder = new ExecutionNodeTreeBuilder(parameters, cfgWrapper) + + // building the tree can throw critical failures if exceptions are found + val rootNode = nodeTreeBuilder.buildExecutionNodeTree("test description") + + log.debug("rootNode 1:\n" + rootNode.toDebugString) + + val executionCollector = new ExecutionResultsCollector + val dataDir = ExecutionResultsCollector.getBaseDir(new File("target")) + executionCollector.setDataDir(dataDir) + executionCollector.setPretty(true) + + executionConfig.setDataOutputDirectory(dataDir) + + val runner = new ExecutionNodeRunner() + + + runner.addNotifier(executionCollector) + + val methodExecutorToUse = new ImplementationCache() + + val setupAndTearDown: SetupAndTearDown = new SetupAndTearDown(executionConfig.getInitialisationClasses, methodExecutorToUse) + + + val rootNode2 = runner.prepareExecutionConfig(new ExecutionConfigWrapper(executionConfig), syntax, parameters, setupAndTearDown, methodExecutorToUse, null) + + executionCollector.initOutputDirectories(rootNode2) + + log.debug("rootNode 2:\n" + rootNode2.toDebugString) + + val finalRootNode = runner.run() + + log.debug("finalRootNode:\n" + finalRootNode.toDebugString) + + // // what are we expecting now: + // // val rootDir = executionCollector.getRootReportsDir + // dataDir.exists() should be (true) + // + // val featureDirs = dataDir.listFiles().toList.filter(f => f.isDirectory) + // + // featureDirs.size should be (2) + // + // for (fDir <- featureDirs){ + // + // if (fDir.getName.contains("simple")){ + // + // validateSimpleFeatureResults(fDir) + // + // } else if (fDir.getName.contains("outline")){ + // + // + // val scenarioResults = fDir.listFiles() + // + // scenarioResults.length should be (5) + // + // } else { + // Assert.fail("unexpected sub dir") + // } + // + // } + // + // val resultSummaryFile = dataDir.listFiles().toList.filter(f => f.isFile) + // + // resultSummaryFile.size should be (1) + + + } + + +} diff --git a/core/src/test/scala/org/substeps/runner/ParsingFromSourceTests.scala b/core/src/test/scala/org/substeps/runner/ParsingFromSourceTests.scala index c7c83c3a..84ae4ebe 100644 --- a/core/src/test/scala/org/substeps/runner/ParsingFromSourceTests.scala +++ b/core/src/test/scala/org/substeps/runner/ParsingFromSourceTests.scala @@ -6,36 +6,41 @@ import java.nio.charset.Charset import com.google.common.io.Files import com.technophobia.substeps.execution.node.{ExecutionNode, IExecutionNode} import com.technophobia.substeps.execution.{ExecutionResult, ImplementationCache} -import com.technophobia.substeps.model._ import com.technophobia.substeps.model.SubSteps.StepImplementations +import com.technophobia.substeps.model._ import com.technophobia.substeps.parser.FileContents -import com.technophobia.substeps.report.DefaultExecutionReportBuilder -import com.technophobia.substeps.runner.builder.ExecutionNodeTreeBuilder import com.technophobia.substeps.runner._ +import com.technophobia.substeps.runner.builder.ExecutionNodeTreeBuilder import com.technophobia.substeps.runner.setupteardown.SetupAndTearDown import com.technophobia.substeps.runner.syntax._ -import com.technophobia.substeps.steps.TestStepImplementations import org.hamcrest.Matchers._ import org.json4s.NoTypeHints import org.json4s.native.Serialization +import org.json4s.native.Serialization.read import org.junit.Assert import org.scalatest._ +import org.slf4j.LoggerFactory import org.substeps.report.{ExecutionResultsCollector, NodeDetail} import scala.collection.JavaConverters._ -import scala.collection.JavaConverters._ -import org.json4s._ -import org.json4s.native.Serialization -import org.json4s.native.Serialization.{read, write} -import org.slf4j.{Logger, LoggerFactory} -import scala.collection.JavaConversions._ -import scala.collection.JavaConverters._ +trait FeatureFilesFromSource { + + def createFeatureFile(content: String, featureFileName: String): FeatureFile = { + val featureFileContentsFromSource = new FileContents(content.split("\n").toList.asJava, new File(featureFileName)) + + val parser: FeatureFileParser = new FeatureFileParser + + val featureFile: FeatureFile = parser.getFeatureFile(featureFileContentsFromSource) + featureFile + } + +} /** * Created by ian on 20/05/16. */ -class ParsingFromSourceTests extends FlatSpec with ShouldMatchers { +class ParsingFromSourceTests extends FlatSpec with ShouldMatchers with FeatureFilesFromSource { val UTF8 = Charset.forName("UTF-8") @@ -214,14 +219,6 @@ Scenario: inline table // TODO more assertions here } - def createFeatureFile(content: String, featureFileName: String): FeatureFile = { - val featureFileContentsFromSource = new FileContents(content.split("\n").toList.asJava, new File(featureFileName)) - - val parser: FeatureFileParser = new FeatureFileParser - - val featureFile: FeatureFile = parser.getFeatureFile(featureFileContentsFromSource) - featureFile - } "running some failing features marked as non critical" must "not fail the build and be visible" in {