From d6e5f4b981ceb75052462f5d51f34d4c63a77720 Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Mon, 27 Aug 2018 19:54:23 +0530 Subject: [PATCH] cukexit almost done - ui and gatling ported and deleted old cucumber wrappers finally. this is a big milestone and what is remaining is mainly the junit-html report there is scope for improvement, e.g. the stepdefs, context and callContext are managing the same state but we can declare success - that we no longer depend on cucumber --- .../java/com/intuit/karate/CallContext.java | 17 +- .../java/com/intuit/karate/FileUtils.java | 45 +- .../main/java/com/intuit/karate/Match.java | 2 +- .../main/java/com/intuit/karate/Script.java | 6 +- .../java/com/intuit/karate/ScriptContext.java | 6 +- .../java/com/intuit/karate/ScriptEnv.java | 20 +- .../java/com/intuit/karate/StringUtils.java | 7 + .../java/com/intuit/karate/core/Engine.java | 15 +- .../intuit/karate/core/ExecutionContext.java | 25 +- .../{ScenarioHook.java => ExecutionHook.java} | 16 +- .../java/com/intuit/karate/core/Feature.java | 88 +++- .../com/intuit/karate/core/FeatureParser.java | 69 ++- .../intuit/karate/core/FeatureSection.java | 9 + .../java/com/intuit/karate/core/Scenario.java | 15 +- .../karate/core/ScenarioExecutionUnit.java | 9 +- .../intuit/karate/core/ScenarioOutline.java | 13 +- .../intuit/karate/core/ScenarioResult.java | 15 +- .../java/com/intuit/karate/core/Step.java | 39 +- .../intuit/karate/core/StepExecutionUnit.java | 6 + .../com/intuit/karate/core/StepResult.java | 6 + .../intuit/karate/cucumber/AsyncAction.java | 38 -- .../intuit/karate/cucumber/AsyncFeature.java | 67 --- .../intuit/karate/cucumber/AsyncResult.java | 45 -- .../intuit/karate/cucumber/AsyncScenario.java | 78 --- .../intuit/karate/cucumber/AsyncSection.java | 101 ---- .../com/intuit/karate/cucumber/AsyncStep.java | 69 --- .../com/intuit/karate/cucumber/CallType.java | 36 -- .../karate/cucumber/CucumberRunner.java | 28 +- .../intuit/karate/cucumber/CucumberUtils.java | 227 --------- .../karate/cucumber/DummyFormatter.java | 106 ---- .../intuit/karate/cucumber/DummyReporter.java | 66 --- .../karate/cucumber/FeatureFilePath.java | 44 -- .../karate/cucumber/FeatureSection.java | 91 ---- .../karate/cucumber/FeatureWrapper.java | 233 --------- .../intuit/karate/cucumber/KarateBackend.java | 148 ------ .../karate/cucumber/KarateClassFinder.java | 54 --- .../intuit/karate/cucumber/KarateFeature.java | 74 --- .../karate/cucumber/KarateHtmlReporter.java | 352 -------------- .../cucumber/KarateJunitAndJsonReporter.java | 227 --------- .../karate/cucumber/KarateJunitFormatter.java | 458 ------------------ .../karate/cucumber/KarateObjectFactory.java | 92 ---- .../karate/cucumber/KarateReporter.java | 51 -- .../karate/cucumber/KarateReporterBase.java | 118 ----- .../intuit/karate/cucumber/KarateRuntime.java | 147 ------ .../karate/cucumber/KarateRuntimeOptions.java | 105 ---- .../intuit/karate/cucumber/ReportStep.java | 90 ---- .../cucumber/ScenarioOutlineWrapper.java | 82 ---- .../karate/cucumber/ScenarioWrapper.java | 116 ----- .../karate/cucumber/StepInterceptor.java | 38 -- .../intuit/karate/cucumber/StepResult.java | 71 --- .../intuit/karate/cucumber/StepWrapper.java | 122 ----- .../main/java/com/intuit/karate/ui/App.java | 9 +- .../java/com/intuit/karate/ui/AppSession.java | 73 +-- .../com/intuit/karate/ui/ExamplesPanel.java | 12 +- .../com/intuit/karate/ui/FeaturePanel.java | 20 +- .../java/com/intuit/karate/ui/LogPanel.java | 4 +- .../java/com/intuit/karate/ui/RunService.java | 2 +- .../karate/ui/ScenarioOutlinePanel.java | 10 +- .../com/intuit/karate/ui/ScenarioPanel.java | 42 +- .../com/intuit/karate/ui/SectionPanel.java | 14 +- .../com/intuit/karate/ui/StepException.java | 6 +- .../java/com/intuit/karate/ui/StepPanel.java | 20 +- .../runtime/CucumberScenarioImpl.java | 47 -- .../java/cucumber/runtime/CucumberStats.java | 36 -- .../gherkin/formatter/FilterFormatter.java | 247 ---------- .../java/com/intuit/karate/ConfigTest.java | 2 +- .../java/com/intuit/karate/FileUtilsTest.java | 11 - .../intuit/karate/core/FeatureParserTest.java | 2 +- .../intuit/karate/core/MandatoryTagHook.java | 18 +- .../karate/cucumber/CucumberRunnerTest.java | 2 +- .../karate/cucumber/CucumberUtilsTest.java | 178 +++---- .../karate/cucumber/FeatureResultTest.java | 2 +- .../karate/cucumber/FeatureReuseTest.java | 2 +- .../com/intuit/karate/cucumber/table.feature | 11 + .../com/intuit/karate/ui/AppSessionTest.java | 27 +- .../intuit/karate/gatling/KarateAction.scala | 45 +- .../java/com/intuit/karate/junit4/Karate.java | 2 +- 77 files changed, 602 insertions(+), 4244 deletions(-) rename karate-core/src/main/java/com/intuit/karate/core/{ScenarioHook.java => ExecutionHook.java} (72%) delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncAction.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncFeature.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncResult.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncScenario.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncSection.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/AsyncStep.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/CallType.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/CucumberUtils.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/DummyFormatter.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/DummyReporter.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/FeatureFilePath.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/FeatureSection.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/FeatureWrapper.java delete mode 100755 karate-core/src/main/java/com/intuit/karate/cucumber/KarateBackend.java delete mode 100755 karate-core/src/main/java/com/intuit/karate/cucumber/KarateClassFinder.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateFeature.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateHtmlReporter.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitAndJsonReporter.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitFormatter.java delete mode 100755 karate-core/src/main/java/com/intuit/karate/cucumber/KarateObjectFactory.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporter.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporterBase.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntime.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntimeOptions.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/ReportStep.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioOutlineWrapper.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioWrapper.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/StepInterceptor.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/StepResult.java delete mode 100644 karate-core/src/main/java/com/intuit/karate/cucumber/StepWrapper.java delete mode 100644 karate-core/src/main/java/cucumber/runtime/CucumberScenarioImpl.java delete mode 100644 karate-core/src/main/java/cucumber/runtime/CucumberStats.java delete mode 100644 karate-core/src/main/java/gherkin/formatter/FilterFormatter.java create mode 100644 karate-core/src/test/java/com/intuit/karate/cucumber/table.feature diff --git a/karate-core/src/main/java/com/intuit/karate/CallContext.java b/karate-core/src/main/java/com/intuit/karate/CallContext.java index 3c33aa0bf..33c0541af 100644 --- a/karate-core/src/main/java/com/intuit/karate/CallContext.java +++ b/karate-core/src/main/java/com/intuit/karate/CallContext.java @@ -23,12 +23,11 @@ */ package com.intuit.karate; -import com.intuit.karate.core.ScenarioHook; import com.intuit.karate.cucumber.ScenarioInfo; -import com.intuit.karate.cucumber.StepInterceptor; import java.util.List; import java.util.Map; import java.util.function.Consumer; +import com.intuit.karate.core.ExecutionHook; /** * @@ -45,8 +44,7 @@ public class CallContext { public final String httpClientClass; public final Consumer asyncSystem; public final Runnable asyncNext; - public final StepInterceptor stepInterceptor; - public final ScenarioHook scenarioHook; + public final ExecutionHook executionHook; private List tags; private Map> tagValues; @@ -81,16 +79,16 @@ public boolean isCalled() { } public CallContext(Map callArg, boolean evalKarateConfig) { - this(null, 0, callArg, -1, false, evalKarateConfig, null, null, null, null, null); + this(null, 0, callArg, -1, false, evalKarateConfig, null, null, null, null); } - public CallContext(ScenarioHook scenarioHook) { - this(null, 0, null, -1, false, true, null, null, null, null, scenarioHook); + public CallContext(ExecutionHook scenarioHook) { + this(null, 0, null, -1, false, true, null, null, null, scenarioHook); } public CallContext(ScriptContext parentContext, int callDepth, Map callArg, int loopIndex, boolean reuseParentContext, boolean evalKarateConfig, String httpClientClass, - Consumer asyncSystem, Runnable asyncNext, StepInterceptor stepInterceptor, ScenarioHook scenarioHook) { + Consumer asyncSystem, Runnable asyncNext, ExecutionHook scenarioHook) { this.parentContext = parentContext; this.callDepth = callDepth; this.callArg = callArg; @@ -100,8 +98,7 @@ public CallContext(ScriptContext parentContext, int callDepth, Map toStringLines(String text) { - return new BufferedReader(new StringReader(text)).lines().collect(Collectors.toList()); - } - public static String replaceFileExtension(String path, String extension) { int pos = path.lastIndexOf('.'); if (pos == -1) { diff --git a/karate-core/src/main/java/com/intuit/karate/Match.java b/karate-core/src/main/java/com/intuit/karate/Match.java index 0861b596b..26806f5ff 100644 --- a/karate-core/src/main/java/com/intuit/karate/Match.java +++ b/karate-core/src/main/java/com/intuit/karate/Match.java @@ -65,7 +65,7 @@ private static Match parse(String exp) { private Match() { ScriptEnv env = ScriptEnv.forEnvAndCurrentWorkingDir(null); CallContext callContext = new CallContext(null, 0, null, -1, false, false, - DummyHttpClient.class.getName(), null, null, null, null); + DummyHttpClient.class.getName(), null, null, null); context = new ScriptContext(env, callContext); } diff --git a/karate-core/src/main/java/com/intuit/karate/Script.java b/karate-core/src/main/java/com/intuit/karate/Script.java index 3d50b1b72..34246313c 100755 --- a/karate-core/src/main/java/com/intuit/karate/Script.java +++ b/karate-core/src/main/java/com/intuit/karate/Script.java @@ -1688,11 +1688,13 @@ public static ScriptValue evalFeatureCall(Feature feature, Object callArg, Scrip private static ScriptValue evalFeatureCall(Feature feature, ScriptContext context, Map callArg, int loopIndex, boolean reuseParentConfig) { CallContext callContext = new CallContext(context, context.callDepth + 1, callArg, loopIndex, - reuseParentConfig, false, null, context.asyncSystem, null, context.stepInterceptor, null); + reuseParentConfig, false, null, context.asyncSystem, null, context.executionHook); // if (context.env.reporter != null) { TODO call reporting // context.env.reporter.callBegin(feature, callContext); // } - FeatureResult result = Engine.executeSync(null, feature, null, callContext); + // the call is going to execute synchronously ! TODO improve + // which is why the context.asyncSystem, context.asyncNext is not really needed + FeatureResult result = Engine.execute(null, feature, null, callContext); if (result.isFailed()) { Throwable error = result.getErrors().get(0); if (error instanceof KarateException) { diff --git a/karate-core/src/main/java/com/intuit/karate/ScriptContext.java b/karate-core/src/main/java/com/intuit/karate/ScriptContext.java index 58f55c395..128bd39d0 100755 --- a/karate-core/src/main/java/com/intuit/karate/ScriptContext.java +++ b/karate-core/src/main/java/com/intuit/karate/ScriptContext.java @@ -23,8 +23,8 @@ */ package com.intuit.karate; +import com.intuit.karate.core.ExecutionHook; import com.intuit.karate.cucumber.ScenarioInfo; -import com.intuit.karate.cucumber.StepInterceptor; import com.intuit.karate.exception.KarateFileNotFoundException; import com.intuit.karate.http.Cookie; import com.intuit.karate.http.HttpClient; @@ -56,7 +56,7 @@ public class ScriptContext { protected final ScriptEnv env; protected final Consumer asyncSystem; protected final Runnable asyncNext; - protected final StepInterceptor stepInterceptor; + protected final ExecutionHook executionHook; protected final ScenarioInfo scenarioInfo; @@ -118,7 +118,7 @@ public ScriptContext(ScriptEnv env, CallContext call) { logger = env.logger; callDepth = call.callDepth; asyncSystem = call.asyncSystem; - stepInterceptor = call.stepInterceptor; + executionHook = call.executionHook; asyncNext = call.asyncNext; tags = call.getTags(); tagValues = call.getTagValues(); diff --git a/karate-core/src/main/java/com/intuit/karate/ScriptEnv.java b/karate-core/src/main/java/com/intuit/karate/ScriptEnv.java index 848ccef5d..9ae94a6fc 100644 --- a/karate-core/src/main/java/com/intuit/karate/ScriptEnv.java +++ b/karate-core/src/main/java/com/intuit/karate/ScriptEnv.java @@ -23,7 +23,6 @@ */ package com.intuit.karate; -import com.intuit.karate.cucumber.KarateReporter; import java.io.File; /** @@ -39,10 +38,9 @@ public class ScriptEnv { public final String featureName; public final ClassLoader fileClassLoader; public final CallCache callCache; - public final KarateReporter reporter; public ScriptEnv(String env, String tagSelector, File featureDir, String featureName, ClassLoader fileClassLoader, - CallCache callCache, Logger logger, KarateReporter reporter) { + CallCache callCache, Logger logger) { this.env = env; this.tagSelector = tagSelector; this.featureDir = featureDir; @@ -50,12 +48,11 @@ public ScriptEnv(String env, String tagSelector, File featureDir, String feature this.fileClassLoader = fileClassLoader; this.callCache = callCache; this.logger = logger; - this.reporter = reporter; } - public ScriptEnv(String env, String tagSelector, File featureDir, String featureName, ClassLoader fileClassLoader, KarateReporter reporter) { + public ScriptEnv(String env, String tagSelector, File featureDir, String featureName, ClassLoader fileClassLoader) { this(env, tagSelector, featureDir, featureName, fileClassLoader, new CallCache(), - new Logger(), reporter); + new Logger()); } public static ScriptEnv forEnvAndCurrentWorkingDir(String env) { @@ -67,13 +64,18 @@ public static ScriptEnv forEnvAndClass(String env, Class clazz) { } private static ScriptEnv forEnvAndWorkingDir(String env, File workingDir) { - return new ScriptEnv(env, null, workingDir, null, Thread.currentThread().getContextClassLoader(), null); + return new ScriptEnv(env, null, workingDir, null, Thread.currentThread().getContextClassLoader()); } public static ScriptEnv forEnvAndFeatureFile(String env, File featureFile) { return forFeatureFile(env, null, featureFile, Thread.currentThread().getContextClassLoader()); } + public static ScriptEnv forEnvFeatureFileAndLogger(String env, File featureFile, Logger logger) { + return new ScriptEnv(env, null, featureFile.getParentFile(), featureFile.getName(), + Thread.currentThread().getContextClassLoader(), new CallCache(), logger); + } + public static ScriptEnv forEnvTagsAndFeatureFile(String env, String tagSelector, File featureFile) { return forFeatureFile(env, tagSelector, featureFile, Thread.currentThread().getContextClassLoader()); } @@ -83,7 +85,7 @@ public static ScriptEnv forEnvAndFeatureFile(String env, File featureFile, Strin } private static ScriptEnv forFeatureFile(String env, String tagSelector, File featureFile, ClassLoader classLoader) { - return new ScriptEnv(env, tagSelector, featureFile.getParentFile(), featureFile.getName(), classLoader, null); + return new ScriptEnv(env, tagSelector, featureFile.getParentFile(), featureFile.getName(), classLoader); } public ScriptEnv refresh(String in) { // immutable @@ -94,7 +96,7 @@ public ScriptEnv refresh(String in) { // immutable karateEnv = StringUtils.trimToNull(System.getProperty(ScriptBindings.KARATE_ENV)); } } - return new ScriptEnv(karateEnv, tagSelector, featureDir, featureName, fileClassLoader, callCache, logger, reporter); + return new ScriptEnv(karateEnv, tagSelector, featureDir, featureName, fileClassLoader, callCache, logger); } @Override diff --git a/karate-core/src/main/java/com/intuit/karate/StringUtils.java b/karate-core/src/main/java/com/intuit/karate/StringUtils.java index 50ac77b48..2bd588781 100644 --- a/karate-core/src/main/java/com/intuit/karate/StringUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/StringUtils.java @@ -23,11 +23,14 @@ */ package com.intuit.karate; +import java.io.BufferedReader; +import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.stream.Collectors; /** * @@ -156,5 +159,9 @@ public static StringUtils.Pair splitByFirstLineFeed(String text) { } return StringUtils.pair(left, right); } + + public static List toStringLines(String text) { + return new BufferedReader(new StringReader(text)).lines().collect(Collectors.toList()); + } } diff --git a/karate-core/src/main/java/com/intuit/karate/core/Engine.java b/karate-core/src/main/java/com/intuit/karate/core/Engine.java index 9cdeca1bc..9aa4cbf0a 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Engine.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Engine.java @@ -83,13 +83,14 @@ public static String getBuildDir() { return command.contains("org.gradle.") ? "build" : "target"; } - public static FeatureResult executeSync(String envString, Feature feature, String tagSelector, CallContext callContext) { + public static FeatureResult execute(String envString, Feature feature, String tagSelector, CallContext callContext) { File file = feature.getFile(); ScriptEnv env = ScriptEnv.forEnvTagsAndFeatureFile(envString, tagSelector, file); if (callContext == null) { callContext = new CallContext(null, true); } - ExecutionContext exec = new ExecutionContext(feature, env, callContext); + boolean enableFileLogAppender = callContext.asyncSystem == null; + ExecutionContext exec = new ExecutionContext(feature, env, callContext, enableFileLogAppender); FeatureExecutionUnit unit = new FeatureExecutionUnit(exec); unit.submit(SYNC_EXECUTOR, NO_OP); return exec.result; @@ -290,16 +291,16 @@ public static File saveResultHtml(String targetDir, FeatureResult result) { Iterator iterator = result.getElements().iterator(); ResultElement prev = null; while (iterator.hasNext()) { - ResultElement element = iterator.next(); - if (element.isBackground()) { + ResultElement element = iterator.next(); + if (element.isBackground()) { prev = element; } else { Node scenarioDiv = div(doc, "scenario"); - append(doc, "/html/body/div", scenarioDiv); + append(doc, "/html/body/div", scenarioDiv); Node scenarioHeadingDiv = div(doc, "scenario-heading", node(doc, "span", "scenario-keyword", element.getKeyword() + ": "), node(doc, "span", "scenario-name", element.getName())); - scenarioDiv.appendChild(scenarioHeadingDiv); + scenarioDiv.appendChild(scenarioHeadingDiv); prev = null; } } @@ -331,7 +332,7 @@ private static List findMethodsMatching(String text) { } return matches; } - + public static String fromCucumberOptionsTags(List tags) { if (tags == null || tags.isEmpty()) { return null; diff --git a/karate-core/src/main/java/com/intuit/karate/core/ExecutionContext.java b/karate-core/src/main/java/com/intuit/karate/core/ExecutionContext.java index c927cfd05..9e269acc1 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ExecutionContext.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ExecutionContext.java @@ -40,13 +40,32 @@ public class ExecutionContext { public final FeatureResult result; public final LogAppender appender; - public ExecutionContext(Feature feature, ScriptEnv env, CallContext callContext) { + public ExecutionContext(Feature feature, ScriptEnv env, CallContext callContext, boolean enableFileLogAppender) { this.feature = feature; result = new FeatureResult(feature); this.env = env; this.callContext = callContext; - String basePath = feature.getPackageQualifiedName(); - this.appender = new FileLogAppender(Engine.getBuildDir() + "/surefire-reports/" + basePath + ".log", env.logger); + if (enableFileLogAppender) { + String basePath = feature.getPackageQualifiedName(); + appender = new FileLogAppender(Engine.getBuildDir() + "/surefire-reports/" + basePath + ".log", env.logger); + } else { + appender = new LogAppender() { + @Override + public String collect() { + return ""; + } + + @Override + public void append(String text) { + + } + + @Override + public void close() { + + } + }; + } } } diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioHook.java b/karate-core/src/main/java/com/intuit/karate/core/ExecutionHook.java similarity index 72% rename from karate-core/src/main/java/com/intuit/karate/core/ScenarioHook.java rename to karate-core/src/main/java/com/intuit/karate/core/ExecutionHook.java index b50b47b51..fc7a67bae 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioHook.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ExecutionHook.java @@ -23,19 +23,27 @@ */ package com.intuit.karate.core; +import com.intuit.karate.StepDefs; + /** * * @author pthomas3 */ -public interface ScenarioHook { +public interface ExecutionHook { /** * * @param scenario - * @return if the scenario should be excluded from the test-run + * @param stepDefs + * @return false if the scenario should be excluded from the test-run + * @throws RuntimeException (any) to abort the test run */ - boolean beforeScenario(Scenario scenario); + boolean beforeScenario(Scenario scenario, StepDefs stepDefs); + + void afterScenario(ScenarioResult result, StepDefs stepDefs); + + void beforeStep(Step step, StepDefs stepDefs); - void afterScenario(ScenarioResult result); + void afterStep(StepResult result, StepDefs stepDefs); } diff --git a/karate-core/src/main/java/com/intuit/karate/core/Feature.java b/karate-core/src/main/java/com/intuit/karate/core/Feature.java index fdbb03800..793fdd267 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Feature.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Feature.java @@ -24,6 +24,7 @@ package com.intuit.karate.core; import com.intuit.karate.FileUtils; +import com.intuit.karate.StringUtils; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -45,6 +46,8 @@ public class Feature { private Background background; private List sections = new ArrayList(); + private List lines; + private String callTag; public Feature(File file, String relativePath) { @@ -52,7 +55,82 @@ public Feature(File file, String relativePath) { this.relativePath = relativePath; this.packageQualifiedName = FileUtils.toPackageQualifiedName(relativePath); } + + public void addSection(FeatureSection section) { + section.setIndex(sections.size()); + sections.add(section); + } + + public FeatureSection getSection(int sectionIndex) { + return sections.get(sectionIndex); + } + + public Scenario getScenario(int sectionIndex, int scenarioIndex) { + FeatureSection section = getSection(sectionIndex); + if (scenarioIndex == -1) { + return section.getScenario(); + } + ScenarioOutline outline = section.getScenarioOutline(); + return outline.getScenarios().get(scenarioIndex); + } + + public Step getStep(int sectionIndex, int scenarioIndex, int stepIndex) { + Scenario scenario = getScenario(sectionIndex, scenarioIndex); + return scenario.getSteps().get(stepIndex); + } + + public Feature replaceStep(Step step, String text) { + return replaceLines(step.getLine(), step.getEndLine(), text); + } + + public Feature replaceLines(int start, int end, String text) { + for (int i = start - 1; i < end - 1; i++) { + lines.remove(start); + } + lines.set(start - 1, text); + return replaceText(getText()); + } + + public Feature addLine(int index, String line) { + lines.add(index, line); + return replaceText(getText()); + } + + public String getText() { + initLines(); + return joinLines(); + } + + public void initLines() { + if (lines == null) { + if (file != null) { + lines = StringUtils.toStringLines(FileUtils.toString(file)); + } + } + } + + public String joinLines(int startLine, int endLine) { + initLines(); + StringBuilder sb = new StringBuilder(); + if (endLine > lines.size()) { + endLine = lines.size(); + } + for (int i = startLine; i < endLine; i++) { + String temp = lines.get(i); + sb.append(temp).append("\n"); + } + return sb.toString(); + } + + public String joinLines() { + int lineCount = lines.size(); + return joinLines(0, lineCount); + } + public Feature replaceText(String text) { + return FeatureParser.parseText(this, text); + } + public String getCallTag() { return callTag; } @@ -60,11 +138,15 @@ public String getCallTag() { public void setCallTag(String callTag) { this.callTag = callTag; } - - public void addSection(FeatureSection section) { - sections.add(section); + + public List getLines() { + return lines; } + public void setLines(List lines) { + this.lines = lines; + } + public File getFile() { return file; } diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java index 04b5d80d5..ea57dfd6f 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureParser.java @@ -27,7 +27,9 @@ import com.intuit.karate.StringUtils; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Iterator; @@ -59,23 +61,42 @@ public static Feature parse(File file) { public static Feature parse(String path) { File file = FileUtils.fromRelativeClassPath(path); - return parse(file, path); + return FeatureParser.parse(file, path); } public static Feature parse(File file, String relativePath) { return new FeatureParser(file, relativePath).feature; } + + public static Feature parseText(Feature old, String text) { + Feature feature = new Feature(old.getFile(), old.getRelativePath()); + feature = new FeatureParser(feature, FileUtils.toInputStream(text)).feature; + feature.setCallTag(old.getCallTag()); + feature.setLines(StringUtils.toStringLines(text)); + return feature; + } private FeatureParser(File file) { this(file, FileUtils.toRelativeClassPath(file)); } + + private static InputStream toStream(File file) { + try { + return new FileInputStream(file); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } private FeatureParser(File file, String relativePath) { - feature = new Feature(file, relativePath); + this(new Feature(file, relativePath), toStream(file)); + } + + private FeatureParser(Feature feature, InputStream is) { + this.feature = feature; CharStream stream; try { - FileInputStream fis = new FileInputStream(file); - stream = CharStreams.fromStream(fis, StandardCharsets.UTF_8); + stream = CharStreams.fromStream(is, StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } @@ -92,7 +113,7 @@ private FeatureParser(File file, String relativePath) { if (errorListener.isFail()) { throw new RuntimeException(errorListener.getMessage()); } - } + } private static int getActualLine(TerminalNode node) { int count = 0; @@ -125,8 +146,7 @@ private static Table toTable(KarateParser.TableContext ctx) { List> rows = new ArrayList(rowCount); List lineNumbers = new ArrayList(rowCount); for (TerminalNode node : nodes) { - List tokens = StringUtils.split(node.getText().trim(), '|'); // TODO escaped pipe characters "\|" ? - // tokens.remove(0); + List tokens = StringUtils.split(node.getText().trim(), '|'); // TODO escaped pipe characters "\|" ? int count = tokens.size(); for (int i = 0; i < count; i++) { tokens.set(i, tokens.get(i).trim()); @@ -174,20 +194,37 @@ private static String fixDocString(String temp) { } return sb.toString().trim(); } + + private static int countLineFeeds(String text) { + int count = 0; + for (char c : text.toCharArray()) { + if (c == '\n') { + count++; + } + } + return count; + } - private static List toSteps(List list) { + private static List toSteps(Scenario scenario, List list) { List steps = new ArrayList(list.size()); + int index = 0; for (KarateParser.StepContext sc : list) { - Step step = new Step(); + Step step = new Step(scenario, index++); steps.add(step); - step.setLine(sc.line().getStart().getLine()); + int stepLine = sc.line().getStart().getLine(); + step.setLine(stepLine); step.setPrefix(sc.prefix().getText().trim()); step.setText(sc.line().getText().trim()); if (sc.docString() != null) { - step.setDocString(fixDocString(sc.docString().getText())); + String raw = sc.docString().getText(); + step.setDocString(fixDocString(raw)); + step.setEndLine(stepLine + countLineFeeds(raw)); } else if (sc.table() != null) { Table table = toTable(sc.table()); step.setTable(table); + step.setEndLine(stepLine + countLineFeeds(sc.table().getText())); + } else { + step.setEndLine(stepLine); } } return steps; @@ -211,7 +248,7 @@ public void enterBackground(KarateParser.BackgroundContext ctx) { Background background = new Background(); feature.setBackground(background); background.setLine(getActualLine(ctx.BACKGROUND())); - List steps = toSteps(ctx.step()); + List steps = toSteps(null, ctx.step()); background.setSteps(steps); if (logger.isTraceEnabled()) { logger.trace("background steps: {}", steps); @@ -221,7 +258,7 @@ public void enterBackground(KarateParser.BackgroundContext ctx) { @Override public void enterScenario(KarateParser.ScenarioContext ctx) { FeatureSection section = new FeatureSection(); - Scenario scenario = new Scenario(feature); + Scenario scenario = new Scenario(feature, section, -1); section.setScenario(scenario); feature.addSection(section); scenario.setLine(getActualLine(ctx.SCENARIO())); @@ -233,7 +270,7 @@ public void enterScenario(KarateParser.ScenarioContext ctx) { scenario.setName(pair.left); scenario.setDescription(pair.right); } - List steps = toSteps(ctx.step()); + List steps = toSteps(scenario, ctx.step()); scenario.setSteps(steps); if (logger.isTraceEnabled()) { logger.trace("scenario steps: {}", steps); @@ -243,7 +280,7 @@ public void enterScenario(KarateParser.ScenarioContext ctx) { @Override public void enterScenarioOutline(KarateParser.ScenarioOutlineContext ctx) { FeatureSection section = new FeatureSection(); - ScenarioOutline outline = new ScenarioOutline(feature); + ScenarioOutline outline = new ScenarioOutline(feature, section); section.setScenarioOutline(outline); feature.addSection(section); outline.setLine(getActualLine(ctx.SCENARIO_OUTLINE())); @@ -256,7 +293,7 @@ public void enterScenarioOutline(KarateParser.ScenarioOutlineContext ctx) { outline.setName(pair.left); outline.setDescription(pair.right); } - List steps = toSteps(ctx.step()); + List steps = toSteps(null, ctx.step()); outline.setSteps(steps); if (logger.isTraceEnabled()) { logger.trace("outline steps: {}", steps); diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureSection.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureSection.java index 8b61dbcfd..98ac2510d 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureSection.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureSection.java @@ -29,8 +29,17 @@ */ public class FeatureSection { + private int index; private Scenario scenario; private ScenarioOutline scenarioOutline; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } public boolean isOutline() { return scenarioOutline != null; diff --git a/karate-core/src/main/java/com/intuit/karate/core/Scenario.java b/karate-core/src/main/java/com/intuit/karate/core/Scenario.java index 25ef6d510..ccd804615 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Scenario.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Scenario.java @@ -36,6 +36,9 @@ public class Scenario { public static final String KEYWORD = "Scenario"; private final Feature feature; + private final FeatureSection section; + private final int index; + private List tags; private int line; private String name; @@ -43,10 +46,16 @@ public class Scenario { private List steps; private boolean outline; - public Scenario(Feature feature) { + public Scenario(Feature feature, FeatureSection section, int index) { this.feature = feature; + this.section = section; + this.index = index; } + public FeatureSection getSection() { + return section; + } + public Feature getFeature() { return feature; } @@ -55,6 +64,10 @@ public Collection getTagsEffective() { return Tags.merge(feature.getTags(), tags); } + public int getIndex() { + return index; + } + public int getLine() { return line; } diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java index 0d4e634e1..558350c4e 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioExecutionUnit.java @@ -52,12 +52,12 @@ public ScenarioExecutionUnit(Scenario scenario, StepDefs stepDefs, ExecutionCont backgroundDone = true; } } - + @Override public void submit(Consumer system, BiConsumer next) { - if (stepDefs.callContext.scenarioHook != null) { + if (stepDefs.callContext.executionHook != null) { try { - stepDefs.callContext.scenarioHook.beforeScenario(scenario); + stepDefs.callContext.executionHook.beforeScenario(scenario, stepDefs); } catch (Exception e) { String message = "scenario hook threw fatal error: " + e.getMessage(); stepDefs.context.logger.error(message); @@ -95,6 +95,9 @@ public void submit(Consumer system, BiConsumer tags; private String name; @@ -42,8 +44,9 @@ public class ScenarioOutline { private List steps; private List exampleTables; - public ScenarioOutline(Feature feature) { + public ScenarioOutline(Feature feature, FeatureSection section) { this.feature = feature; + this.section = section; } public List getScenarios() { @@ -52,7 +55,7 @@ public List getScenarios() { Table t = et.getTable(); int rowCount = t.getRows().size(); for (int i = 1; i < rowCount; i++) { // don't include header row - Scenario s = new Scenario(feature); + Scenario s = new Scenario(feature, section, i - 1); list.add(s); s.setOutline(true); s.setLine(t.getLineNumberForRow(i)); @@ -83,7 +86,7 @@ public List getScenarios() { table = table.replace(token, value); } } - Step step = new Step(); + Step step = new Step(s, original.getIndex()); step.setPrefix(original.getPrefix()); step.setText(text); step.setDocString(docString); @@ -96,6 +99,10 @@ public List getScenarios() { return list; } + public FeatureSection getSection() { + return section; + } + public int getLine() { return line; } diff --git a/karate-core/src/main/java/com/intuit/karate/core/ScenarioResult.java b/karate-core/src/main/java/com/intuit/karate/core/ScenarioResult.java index b6c0cc3bc..912ccb9f2 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/ScenarioResult.java +++ b/karate-core/src/main/java/com/intuit/karate/core/ScenarioResult.java @@ -32,13 +32,14 @@ * @author pthomas3 */ public class ScenarioResult extends ResultElement { - - + private final boolean outline; private final String keyword; + private final Scenario scenario; public ScenarioResult(Scenario scenario) { super(scenario.getName()); + this.scenario = scenario; put("line", scenario.getLine()); put("id", StringUtils.toIdString(scenario.getName())); put("description", scenario.getDescription()); @@ -53,13 +54,17 @@ public ScenarioResult(Scenario scenario) { for (Tag tag : list) { tags.add(new TagResult(tag)); } - } + } } + public Scenario getScenario() { + return scenario; + } + @Override public boolean isBackground() { return false; - } + } @Override String getKeyword() { @@ -69,6 +74,6 @@ String getKeyword() { @Override public boolean isOutline() { return outline; - } + } } diff --git a/karate-core/src/main/java/com/intuit/karate/core/Step.java b/karate-core/src/main/java/com/intuit/karate/core/Step.java index 6fdd3514b..f70f3bb9f 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/Step.java +++ b/karate-core/src/main/java/com/intuit/karate/core/Step.java @@ -28,12 +28,37 @@ * @author pthomas3 */ public class Step { - + + private final Scenario scenario; + private final int index; + private int line; + private int endLine; private String prefix; private String text; private String docString; private Table table; + + public Step(Scenario scenario, int index) { + this.scenario = scenario; + this.index = index; + } + + public boolean isBackground() { + return scenario == null; + } + + public boolean isOutline() { + return scenario != null && scenario.isOutline(); + } + + public Scenario getScenario() { + return scenario; + } + + public int getIndex() { + return index; + } public int getLine() { return line; @@ -42,6 +67,18 @@ public int getLine() { public void setLine(int line) { this.line = line; } + + public int getLineCount() { + return endLine - line + 1; + } + + public int getEndLine() { + return endLine; + } + + public void setEndLine(int endLine) { + this.endLine = endLine; + } public String getPrefix() { return prefix; diff --git a/karate-core/src/main/java/com/intuit/karate/core/StepExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/StepExecutionUnit.java index 7af41b734..6c4046666 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/StepExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/StepExecutionUnit.java @@ -49,7 +49,13 @@ public StepExecutionUnit(Step step, Scenario scenario, StepDefs stepDefs) { public void submit(Consumer system, BiConsumer next) { system.accept(() -> { String relativePath = scenario.getFeature().getRelativePath(); + if (stepDefs.callContext.executionHook != null) { + stepDefs.callContext.executionHook.beforeStep(step, stepDefs); + } Result result = Engine.execute(relativePath, step, stepDefs); + if (stepDefs.callContext.executionHook != null) { + stepDefs.callContext.executionHook.afterStep(new StepResult(step, result), stepDefs); + } if (result.isAborted()) { stepDefs.context.logger.debug("abort at {}:{}", relativePath, step.getLine()); next.accept(result, null); // same flow as passed diff --git a/karate-core/src/main/java/com/intuit/karate/core/StepResult.java b/karate-core/src/main/java/com/intuit/karate/core/StepResult.java index b9d4fc86c..a2cc93c9e 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/StepResult.java +++ b/karate-core/src/main/java/com/intuit/karate/core/StepResult.java @@ -35,6 +35,7 @@ public class StepResult extends HashMap { private static final Map DUMMY_MATCH; + private final Step step; private final Result result; private final String keyword; private final String name; @@ -57,6 +58,7 @@ public void putDocString(String text) { } public StepResult(Step step, Result result) { + this.step = step; put("line", step.getLine()); keyword = step.getPrefix(); put("keyword", keyword); @@ -67,6 +69,10 @@ public StepResult(Step step, Result result) { putDocString(step.getDocString()); this.result = result; } + + public Step getStep() { + return step; + } public Result getResult() { return result; diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncAction.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncAction.java deleted file mode 100644 index c45d8fccf..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncAction.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.exception.KarateException; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public interface AsyncAction { - - void submit(Consumer system, BiConsumer next); - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncFeature.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncFeature.java deleted file mode 100644 index 07f07b162..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncFeature.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.ScriptValueMap; -import com.intuit.karate.exception.KarateException; -import java.util.Iterator; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public class AsyncFeature implements AsyncAction { - - private final FeatureWrapper feature; - private final KarateBackend backend; - private final Iterator iterator; - - public AsyncFeature(FeatureWrapper feature, KarateBackend backend) { - this.feature = feature; - this.backend = backend; - this.iterator = feature.getSectionsByCallTag().iterator(); - } - - @Override - public void submit(Consumer system, BiConsumer next) { - if (iterator.hasNext()) { - FeatureSection fs = iterator.next(); - system.accept(() -> { - AsyncSection as = new AsyncSection(fs, backend); - as.submit(system, (r, e) -> { - if (e != null) { - next.accept(backend.getVars(), e); - } else { - AsyncFeature.this.submit(system, next); - } - }); - }); - } else { - next.accept(backend.getVars(), null); - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncResult.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncResult.java deleted file mode 100644 index 36fa4ae25..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncResult.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.ScriptValueMap; -import com.intuit.karate.exception.KarateException; -import java.util.function.BiConsumer; - -/** - * - * @author pthomas3 - */ -public class AsyncResult implements BiConsumer { - - public ScriptValueMap vars; - public KarateException error; - - @Override - public void accept(ScriptValueMap vars, KarateException error) { - this.vars = vars; - this.error = error; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncScenario.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncScenario.java deleted file mode 100644 index 82275fa41..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncScenario.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.exception.KarateException; -import java.util.Iterator; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public class AsyncScenario implements AsyncAction { - - private final ScenarioWrapper scenario; - private final KarateBackend backend; - private final Iterator iterator; - - public AsyncScenario(ScenarioWrapper scenario, KarateBackend backend) { - this.scenario = scenario; - this.backend = backend; - this.iterator = scenario.getSteps().iterator(); - } - - private void afterScenario() { - StepInterceptor interceptor = backend.getCallContext().stepInterceptor; - if (interceptor != null) { - interceptor.afterScenario(scenario, backend); - } - } - - @Override - public void submit(Consumer system, BiConsumer next) { - if (iterator.hasNext()) { - StepWrapper step = iterator.next(); - system.accept(() -> { - AsyncStep as = new AsyncStep(step, backend); - as.submit(system, (r, e) -> { - if (r != null && r.isAbort()) { - afterScenario(); - next.accept(null, null); // abort: exit early - } else if (e != null) { - afterScenario(); - next.accept(null, e); // exit with error - } else { - AsyncScenario.this.submit(system, next); - } - }); - }); - } else { - afterScenario(); - next.accept(null, null); - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncSection.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncSection.java deleted file mode 100644 index e076105bf..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncSection.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.exception.KarateException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public class AsyncSection implements AsyncAction { - - private final FeatureSection section; - private final KarateBackend backend; - private final Iterator iterator; - private List errors; - - public AsyncSection(FeatureSection section, KarateBackend backend) { - this.section = section; - this.backend = backend; - this.iterator = section.isOutline() - ? section.getScenarioOutline().getScenarios().iterator() - : Collections.singletonList(section.getScenario()).iterator(); - } - - @Override - public void submit(Consumer system, BiConsumer next) { - if (iterator.hasNext()) { - ScenarioWrapper scenario = iterator.next(); - system.accept(() -> { - if (section.isOutline()) { - if (backend.getCallContext().parentContext != null) { - KarateReporter reporter = backend.getCallContext().parentContext.getEnv().reporter; - if (reporter != null) { - reporter.exampleBegin(scenario, backend.getCallContext()); - } - } - } - AsyncScenario as = new AsyncScenario(scenario, backend); - as.submit(system, (r, e) -> { - if (section.isOutline()) { - if (e != null) { - if (errors == null) { - errors = new ArrayList(); - } - errors.add("row " + (scenario.getIndex() + 1) + ": " + e.getMessage()); - } - // continue even if one example row failed - AsyncSection.this.submit(system, next); - } else { - if (e != null) { - next.accept(null, e); - } else { - AsyncSection.this.submit(system, next); - } - } - }); - }); - } else { - KarateException ke; - if (errors != null) { - String message = "scenario outline failed:"; - for (String s : errors) { - message = message + "\n------\n" + s; - } - ke = new KarateException(message); - } else { - ke = null; - } - next.accept(null, ke); - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncStep.java b/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncStep.java deleted file mode 100644 index 1e62cc428..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/AsyncStep.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.StringUtils; -import com.intuit.karate.exception.KarateException; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public class AsyncStep implements AsyncAction { - - private final StepWrapper step; - private final KarateBackend backend; - - public AsyncStep(StepWrapper step, KarateBackend backend) { - this.step = step; - this.backend = backend; - } - - @Override - public void submit(Consumer system, BiConsumer next) { - system.accept(() -> { - StepResult result = CucumberUtils.runCalledStep(step, backend); - ScenarioWrapper scenario = step.getScenario(); - if (result.isAbort()) { - backend.getEnv().logger.debug("abort at {}:{}", scenario.getFeature().getPath(), step.getStep().getLine()); - next.accept(result, null); - } else if (!result.isPass()) { - FeatureWrapper feature = scenario.getFeature(); - String scenarioName = StringUtils.trimToNull(scenario.getScenario().getGherkinModel().getName()); - String message = "called: " + feature.getPath(); - if (scenarioName != null) { - message = message + ", scenario: " + scenarioName; - } - message = message + ", line: " + step.getStep().getLine(); - KarateException error = new KarateException(message, result.getError()); - next.accept(null, error); - } else { - next.accept(result, null); - } - }); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/CallType.java b/karate-core/src/main/java/com/intuit/karate/cucumber/CallType.java deleted file mode 100644 index 33488b996..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/CallType.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -/** - * - * @author pthomas3 - */ -public enum CallType { - - DEFAULT, - BACKGROUND_ONLY, - SCENARIO_ONLY - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberRunner.java b/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberRunner.java index 5d409a05b..d80903d56 100644 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberRunner.java +++ b/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberRunner.java @@ -26,11 +26,12 @@ import com.intuit.karate.CallContext; import com.intuit.karate.FileResource; import com.intuit.karate.FileUtils; +import com.intuit.karate.ScriptEnv; import com.intuit.karate.core.Engine; +import com.intuit.karate.core.ExecutionContext; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeatureParser; import com.intuit.karate.core.FeatureResult; -import com.intuit.karate.core.ScenarioHook; import cucumber.api.CucumberOptions; import java.io.File; import java.util.ArrayList; @@ -45,6 +46,8 @@ import java.util.Collections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.intuit.karate.core.ExecutionHook; +import com.intuit.karate.core.FeatureExecutionUnit; /** * @@ -83,7 +86,7 @@ public static KarateStats parallel(List tags, List paths, int th return parallel(tags, paths, null, threadCount, reportDir); } - public static KarateStats parallel(List tags, List paths, ScenarioHook hook, int threadCount, String reportDir) { + public static KarateStats parallel(List tags, List paths, ExecutionHook hook, int threadCount, String reportDir) { String tagSelector = tags == null ? null : Engine.fromCucumberOptionsTags(tags); List files = FileUtils.scanForFeatureFiles(paths); return parallel(tagSelector, files, hook, threadCount, reportDir); @@ -93,7 +96,7 @@ public static KarateStats parallel(String tagSelector, List resour return parallel(tagSelector, resources, null, threadCount, reportDir); } - public static KarateStats parallel(String tagSelector, List resources, ScenarioHook hook, int threadCount, String reportDir) { + public static KarateStats parallel(String tagSelector, List resources, ExecutionHook hook, int threadCount, String reportDir) { if (reportDir == null) { reportDir = Engine.getBuildDir() + "/surefire-reports"; } @@ -113,7 +116,7 @@ public static KarateStats parallel(String tagSelector, List resour callables.add(() -> { // we are now within a separate thread. the reporter filters logs by self thread String threadName = Thread.currentThread().getName(); - FeatureResult result = Engine.executeSync(null, feature, tagSelector, new CallContext(hook)); + FeatureResult result = Engine.execute(null, feature, tagSelector, new CallContext(hook)); logger.info("<<<< feature {} of {} on thread {}: {}", index, count, threadName, feature.getRelativePath()); Engine.saveResultJson(finalReportDir, result); Engine.saveResultXml(finalReportDir, result); @@ -148,7 +151,7 @@ public static KarateStats parallel(String tagSelector, List resour public static Map runFeature(Feature feature, Map vars, boolean evalKarateConfig) { CallContext callContext = new CallContext(vars, evalKarateConfig); - FeatureResult result = Engine.executeSync(null, feature, null, callContext); + FeatureResult result = Engine.execute(null, feature, null, callContext); return result.getResultAsPrimitiveMap(); } @@ -166,5 +169,20 @@ public static Map runFeature(String path, Map va Feature feature = FeatureParser.parse(path); return runFeature(feature, vars, evalKarateConfig); } + + // this is called by karate-gatling ! + public static void callAsync(String filePath, String callTag, CallContext callContext) { + File file = FileUtils.getFeatureFile(filePath); + Feature feature = FeatureParser.parse(file); + feature.setCallTag(callTag); + callAsync(feature, callContext); + } + + public static void callAsync(Feature feature, CallContext callContext) { + ScriptEnv env = ScriptEnv.forEnvAndFeatureFile(null, feature.getFile()); + ExecutionContext ec = new ExecutionContext(feature, env, callContext, false); + FeatureExecutionUnit exec = new FeatureExecutionUnit(ec); + exec.submit(callContext.asyncSystem, (r, e) -> callContext.asyncNext.run()); + } } diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberUtils.java b/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberUtils.java deleted file mode 100644 index 78e24b38d..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/CucumberUtils.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.FileUtils; -import com.intuit.karate.ScriptContext; -import com.intuit.karate.exception.KarateException; -import com.intuit.karate.ScriptEnv; -import com.intuit.karate.ScriptValueMap; -import com.intuit.karate.exception.KarateAbortException; -import cucumber.runtime.AmbiguousStepDefinitionsException; -import cucumber.runtime.FeatureBuilder; -import cucumber.runtime.RuntimeGlue; -import cucumber.runtime.StepDefinitionMatch; -import cucumber.runtime.UndefinedStepsTracker; -import cucumber.runtime.model.CucumberFeature; -import cucumber.runtime.xstream.LocalizedXStreams; -import gherkin.I18n; -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.Step; -import gherkin.formatter.model.Tag; -import gherkin.parser.Parser; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -/** - * - * @author pthomas3 - */ -public class CucumberUtils { - - private CucumberUtils() { - // only static methods - } - - public static void resolveTagsAndTagValues(KarateBackend backend, Set tags) { - if (tags.isEmpty()) { - backend.setTagValues(Collections.emptyMap()); - backend.setTags(Collections.emptyList()); - return; - } - Map> tagValues = new LinkedHashMap(tags.size()); - Map tagKeyLines = new HashMap(tags.size()); - List rawTags = new ArrayList(tags.size()); - for (Tag tag : tags) { - Integer line = tag.getLine(); - String name = tag.getName(); - List values = new ArrayList(); - if (name.startsWith("@")) { - name = name.substring(1); - } - rawTags.add(name); - Integer prevTagLine = tagKeyLines.get(name); - if (prevTagLine != null && prevTagLine > line) { - continue; // skip tag with same name but lower line number, - } - tagKeyLines.put(name, line); - int pos = name.indexOf('='); - if (pos != -1) { - if (name.length() == pos + 1) { // edge case, @foo= - values.add(""); - } else { - String temp = name.substring(pos + 1); - for (String s : temp.split(",")) { - values.add(s); - } - } - name = name.substring(0, pos); - } - tagValues.put(name, values); - } - backend.setTagValues(tagValues); - backend.setTags(rawTags); - } - - public static void initScenarioInfo(Scenario scenario, KarateBackend backend) { - ScenarioInfo info = new ScenarioInfo(); - ScriptEnv env = backend.getEnv(); - info.setFeatureDir(env.featureDir.getPath()); - info.setFeatureFileName(env.featureName); - info.setScenarioName(scenario.getName()); - info.setScenarioType(scenario.getKeyword()); // 'Scenario' | 'Scenario Outline' - info.setScenarioDescription(scenario.getDescription()); - backend.setScenarioInfo(info); - } - - public static KarateBackend getBackendWithGlue(FeatureWrapper feature, CallContext callContext) { - KarateBackend backend = new KarateBackend(feature, callContext); - ClassLoader defaultClassLoader = Thread.currentThread().getContextClassLoader(); - RuntimeGlue glue = new RuntimeGlue(new UndefinedStepsTracker(), new LocalizedXStreams(defaultClassLoader)); - backend.loadGlue(glue, null); - return backend; - } - - public static CucumberFeature parse(String text, String featurePath) { - final List features = new ArrayList<>(); - final FeatureBuilder builder = new FeatureBuilder(features); - Parser parser = new Parser(builder); - parser.parse(text, featurePath, 0); - CucumberFeature cucumberFeature = features.get(0); - cucumberFeature.setI18n(parser.getI18nLanguage()); - return cucumberFeature; - } - - private static final Consumer DEFAULT_SYNC = r -> r.run(); - - public static ScriptValueMap callSync(FeatureWrapper feature, CallContext callContext) { - KarateBackend backend = getBackendWithGlue(feature, callContext); - AsyncFeature af = new AsyncFeature(feature, backend); - AsyncResult result = new AsyncResult(); - af.submit(DEFAULT_SYNC, result); - if (result.error != null) { - throw result.error; - } - return result.vars; - } - - public static void callAsync(String filePath, String callTag, CallContext callContext) { - File file = FileUtils.getFeatureFile(filePath); - FeatureWrapper feature = FeatureWrapper.fromFileAndTag(file, callTag); - callAsync(feature, callContext); - } - - public static void callAsync(FeatureWrapper feature, CallContext callContext) { - KarateBackend backend = getBackendWithGlue(feature, callContext); - AsyncFeature af = new AsyncFeature(feature, backend); - af.submit(callContext.asyncSystem, (r, e) -> callContext.asyncNext.run()); - } - - public static StepResult runCalledStep(StepWrapper step, KarateBackend backend) { - CucumberFeature feature = step.getScenario().getFeature().getFeature(); - StepInterceptor interceptor = backend.getCallContext().stepInterceptor; - if (interceptor != null) { - interceptor.beforeStep(step, backend); - } - StepResult result = runStep(step.getStep(), backend.getEnv().reporter, feature.getI18n(), backend); - if (interceptor != null) { - interceptor.afterStep(result, backend); - } - return result; - } - - private static final DummyReporter DUMMY_REPORTER = new DummyReporter(); - - // adapted from cucumber.runtime.Runtime.runCalledStep - public static StepResult runStep(Step step, Reporter reporter, I18n i18n, KarateBackend backend) { - if (reporter == null) { - reporter = DUMMY_REPORTER; - } - StepDefinitionMatch match; - try { - match = backend.getGlue().stepDefinitionMatch(backend.getFeaturePath(), step, i18n); - } catch (AmbiguousStepDefinitionsException e) { - match = e.getMatches().get(0); - Result result = new Result(Result.FAILED, 0L, e, StepResult.DUMMY_OBJECT); - return afterStep(reporter, step, match, result, backend); - } - if (match == null) { - String message = "syntax error: '" + step.getName() + "', feature: " + backend.getFeaturePath() + ", line: " + step.getLine(); - backend.getEnv().logger.error("{}", message); - Result result = new Result(Result.FAILED, 0L, new KarateException(message), StepResult.DUMMY_OBJECT); - return afterStep(reporter, step, Match.UNDEFINED, result, backend); - } - String status = Result.PASSED; - Throwable error = null; - long startTime = System.nanoTime(); - try { - match.runStep(i18n); - } catch (KarateAbortException ke) { - status = StepResult.ABORTED; - } catch (Throwable t) { - error = t; - status = Result.FAILED; - } - long duration = backend.isCalled() ? 0 : System.nanoTime() - startTime; - Result result = new Result(status, duration, error, StepResult.DUMMY_OBJECT); - return afterStep(reporter, step, match, result, backend); - } - - private static StepResult afterStep(Reporter reporter, Step step, Match match, Result result, KarateBackend backend) { - boolean isKarateReporter = reporter instanceof KarateReporter; - CallContext callContext = backend.getCallContext(); - ScriptContext context = backend.getStepDefs().context; - if (isKarateReporter) { // report all the things ! - KarateReporter karateReporter = (KarateReporter) reporter; - karateReporter.karateStep(step, match, result, callContext, context); - } else if (!backend.isCalled() && reporter != null) { // can be null for server - reporter.match(match); - reporter.result(result); - } - return new StepResult(step, result); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/DummyFormatter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/DummyFormatter.java deleted file mode 100644 index ae5a51fa6..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/DummyFormatter.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import gherkin.formatter.Formatter; -import gherkin.formatter.model.Background; -import gherkin.formatter.model.Examples; -import gherkin.formatter.model.Feature; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.ScenarioOutline; -import gherkin.formatter.model.Step; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class DummyFormatter implements Formatter { - - @Override - public void syntaxError(String state, String event, List legalEvents, String uri, Integer line) { - - } - - @Override - public void uri(String uri) { - - } - - @Override - public void feature(Feature feature) { - - } - - @Override - public void scenarioOutline(ScenarioOutline scenarioOutline) { - - } - - @Override - public void examples(Examples examples) { - - } - - @Override - public void startOfScenarioLifeCycle(Scenario scenario) { - - } - - @Override - public void background(Background background) { - - } - - @Override - public void scenario(Scenario scenario) { - - } - - @Override - public void step(Step step) { - - } - - @Override - public void endOfScenarioLifeCycle(Scenario scenario) { - - } - - @Override - public void done() { - - } - - @Override - public void close() { - - } - - @Override - public void eof() { - - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/DummyReporter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/DummyReporter.java deleted file mode 100644 index f0fbb32a8..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/DummyReporter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; - -/** - * - * @author pthomas3 - */ -public class DummyReporter implements Reporter { - - @Override - public void before(Match match, Result result) { - - } - - @Override - public void result(Result result) { - - } - - @Override - public void after(Match match, Result result) { - - } - - @Override - public void match(Match match) { - - } - - @Override - public void embedding(String mimeType, byte[] data) { - - } - - @Override - public void write(String text) { - - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureFilePath.java b/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureFilePath.java deleted file mode 100644 index a2dc01e4d..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureFilePath.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import java.io.File; - -/** - * this class only exists to represent the feature file and the - * resource search paths (typically 'src/test/java' and 'src/test/resources') - * - * @author pthomas3 - */ -public class FeatureFilePath { - - public final File file; - public final String[] searchPaths; - - public FeatureFilePath(File file, String[] searchPaths) { - this.file = file; - this.searchPaths = searchPaths; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureSection.java b/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureSection.java deleted file mode 100644 index 5b0d558d5..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureSection.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import gherkin.formatter.model.Tag; -import java.util.List; -import java.util.stream.Collectors; - -/** - * - * @author pthomas3 - */ -public class FeatureSection { - - private final int index; - private final FeatureWrapper feature; - private final ScenarioWrapper scenario; - private final ScenarioOutlineWrapper scenarioOutline; - - public FeatureSection(int index, FeatureWrapper feature, ScenarioWrapper scenario, ScenarioOutlineWrapper scenarioOutline) { - this.index = index; - this.feature = feature; - this.scenario = scenario; - this.scenarioOutline = scenarioOutline; - if (scenario != null) { - scenario.setSection(this); - } else { - scenarioOutline.setSection(this); - } - } - - public List getTags() { - List tags; - if (isOutline()) { - tags = scenarioOutline.getScenarioOutline().getGherkinModel().getTags(); - } else { - tags = scenario.getScenario().getGherkinModel().getTags(); - } - return tags.stream().map(t -> t.getName()).collect(Collectors.toList()); - } - - public int getIndex() { - return index; - } - - public FeatureWrapper getFeature() { - return feature; - } - - public ScenarioWrapper getScenario() { - return scenario; - } - - public ScenarioOutlineWrapper getScenarioOutline() { - return scenarioOutline; - } - - public boolean isOutline() { - return scenarioOutline != null; - } - - public int getLine() { - if (isOutline()) { - return scenarioOutline.getLine(); - } else { - return scenario.getLine(); - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureWrapper.java b/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureWrapper.java deleted file mode 100644 index f7fb0a4a3..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/FeatureWrapper.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.FileUtils; -import com.intuit.karate.ScriptEnv; -import cucumber.runtime.model.CucumberFeature; -import cucumber.runtime.model.CucumberScenario; -import cucumber.runtime.model.CucumberScenarioOutline; -import cucumber.runtime.model.CucumberTagStatement; -import java.io.File; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class FeatureWrapper { - - private final String path; - private final String callTag; - private final String text; - private final List lines; - private final CucumberFeature feature; - private final List featureSections; - - private ScriptEnv scriptEnv; - - public ScriptEnv getEnv() { - return scriptEnv; - } - - public String getCallTag() { - return callTag; - } - - public void setEnv(ScriptEnv scriptEnv) { - this.scriptEnv = scriptEnv; - } - - public static FeatureWrapper fromFileAndTag(File file, String callTag) { - return fromFile(file, callTag, Thread.currentThread().getContextClassLoader(), null); - } - - public static FeatureWrapper fromFile(File file, String callTag, KarateReporter reporter) { - return fromFile(file, callTag, Thread.currentThread().getContextClassLoader(), reporter); - } - - public static FeatureWrapper fromFile(File file, String callTag, ClassLoader classLoader, KarateReporter reporter) { - String text = FileUtils.toString(file); - ScriptEnv env = new ScriptEnv(null, null, file.getParentFile(), file.getName(), classLoader, reporter); - return new FeatureWrapper(text, env, file.getPath(), callTag); - } - - public static FeatureWrapper fromFile(File file, ScriptEnv env) { - String text = FileUtils.toString(file); - return new FeatureWrapper(text, env, file.getPath(), null); - } - - public static FeatureWrapper fromString(String text, ScriptEnv scriptEnv, String path, String callTag) { - return new FeatureWrapper(text, scriptEnv, path, callTag); - } - - public static FeatureWrapper fromStream(InputStream is, ScriptEnv scriptEnv, String path) { - String text = FileUtils.toString(is); - return new FeatureWrapper(text, scriptEnv, path, null); - } - - public String joinLines(int startLine, int endLine) { - StringBuilder sb = new StringBuilder(); - if (endLine > lines.size()) { - endLine = lines.size(); - } - for (int i = startLine; i < endLine; i++) { - String line = lines.get(i); - sb.append(line).append("\n"); - } - return sb.toString(); - } - - public String joinLines() { - int lineCount = lines.size(); - return joinLines(0, lineCount); - } - - public List getLines() { - return lines; - } - - public String getFirstScenarioName() { - if (featureSections == null || featureSections.isEmpty()) { - return null; - } - FeatureSection fs = featureSections.get(0); - if (fs.isOutline()) { - return fs.getScenarioOutline().getScenarioOutline().getGherkinModel().getName(); - } else { - return fs.getScenario().getScenario().getGherkinModel().getName(); - } - } - - public CucumberFeature getFeature() { - return feature; - } - - public List getSections() { - return featureSections; - } - - public List getSectionsByCallTag() { - if (callTag == null) { - return featureSections; - } - List filtered = new ArrayList(featureSections.size()); - for (FeatureSection fs : getSections()) { - List tags = fs.getTags(); - if (tags == null || tags.isEmpty()) { - continue; - } - for (String tag : tags) { - if (callTag.equals(tag)) { - filtered.add(fs); - } - } - } - return filtered; - } - - public String getPath() { - return path; - } - - public String getText() { - return text; - } - - public FeatureWrapper addLine(int index, String line) { - lines.add(index, line); - return new FeatureWrapper(joinLines(), scriptEnv, path, callTag); - } - - public FeatureSection getSection(int sectionIndex) { - return featureSections.get(sectionIndex); - } - - public ScenarioWrapper getScenario(int sectionIndex, int scenarioIndex) { - FeatureSection section = getSection(sectionIndex); - if (scenarioIndex == -1) { - return section.getScenario(); - } - ScenarioOutlineWrapper outline = section.getScenarioOutline(); - return outline.getScenarios().get(scenarioIndex); - - } - - public StepWrapper getStep(int sectionIndex, int scenarioIndex, int stepIndex) { - ScenarioWrapper scenario = getScenario(sectionIndex, scenarioIndex); - return scenario.getSteps().get(stepIndex); - } - - public FeatureWrapper replaceStep(StepWrapper step, String text) { - return replaceLines(step.getStartLine(), step.getEndLine(), text); - } - - public FeatureWrapper replaceLines(int start, int end, String text) { - for (int i = start; i < end; i++) { - lines.remove(start); - } - lines.set(start, text); - return new FeatureWrapper(joinLines(), scriptEnv, path, callTag); - } - - public FeatureWrapper removeLine(int index) { - lines.remove(index); - return new FeatureWrapper(joinLines(), scriptEnv, path, callTag); - } - - public FeatureWrapper replaceText(String newText) { - return new FeatureWrapper(newText, scriptEnv, path, callTag); - } - - private FeatureWrapper(String text, ScriptEnv scriptEnv, String path, String callTag) { - this.path = path; - this.callTag = callTag; - this.text = text; - this.scriptEnv = scriptEnv; - this.feature = CucumberUtils.parse(text, path); - this.lines = FileUtils.toStringLines(text); - featureSections = new ArrayList<>(); - List elements = feature.getFeatureElements(); - int count = elements.size(); - for (int i = 0; i < count; i++) { - CucumberTagStatement cts = elements.get(i); - if (cts instanceof CucumberScenario) { - CucumberScenario sw = (CucumberScenario) cts; - ScenarioWrapper scenario = new ScenarioWrapper(this, -1, sw, null); - FeatureSection section = new FeatureSection(i, this, scenario, null); - featureSections.add(section); - } else if (cts instanceof CucumberScenarioOutline) { - CucumberScenarioOutline cso = (CucumberScenarioOutline) cts; - ScenarioOutlineWrapper scenarioOutline = new ScenarioOutlineWrapper(this, cso); - FeatureSection section = new FeatureSection(i, this, null, scenarioOutline); - featureSections.add(section); - } else { - throw new RuntimeException("unexpected type: " + cts.getClass()); - } - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateBackend.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateBackend.java deleted file mode 100755 index 64a011795..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateBackend.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptContext; -import com.intuit.karate.ScriptEnv; -import com.intuit.karate.ScriptValueMap; -import com.intuit.karate.StepDefs; -import cucumber.runtime.Backend; -import cucumber.runtime.ClassFinder; -import cucumber.runtime.Glue; -import cucumber.runtime.UnreportedStepExecutor; -import cucumber.runtime.java.JavaBackend; -import cucumber.runtime.snippets.FunctionNameGenerator; -import gherkin.formatter.model.Step; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -/** - * - * @author pthomas3 - */ -public class KarateBackend implements Backend { - - private final JavaBackend backend; - private final KarateObjectFactory objectFactory; - private final CallContext callContext; - private final String featurePath; - private Glue glue; - - public String getFeaturePath() { - return featurePath; - } - - public void setTags(List tags) { - callContext.setTags(tags); - } - - public void setTagValues(Map> tagValues) { - callContext.setTagValues(tagValues); - } - - public void setScenarioInfo(ScenarioInfo scenarioInfo) { - callContext.setScenarioInfo(scenarioInfo); - } - - public void setScenarioError(Throwable error) { - objectFactory.getStepDefs().context.setScenarioError(error); - } - - public boolean isCalled() { - return callContext.isCalled(); - } - - public CallContext getCallContext() { - return callContext; - } - - public ScriptEnv getEnv() { - return objectFactory.getEnv(); - } - - public ScriptValueMap getVars() { - return getStepDefs().context.getVars(); - } - - public KarateBackend(FeatureWrapper feature, CallContext callContext) { - this.callContext = callContext; - this.featurePath = feature.getPath(); - ClassFinder classFinder = new KarateClassFinder(feature.getEnv().fileClassLoader); - objectFactory = new KarateObjectFactory(feature.getEnv(), callContext); - backend = new JavaBackend(objectFactory, classFinder); - } - - public KarateObjectFactory getObjectFactory() { - return objectFactory; - } - - public StepDefs getStepDefs() { - return objectFactory.getStepDefs(); - } - - public Glue getGlue() { - return glue; - } - - public String getCallingFeature() { - if (callContext.parentContext != null) { - return callContext.parentContext.getEnv().featureName; - } else { - return null; - } - } - - @Override - public void loadGlue(Glue glue, List NOT_USED) { - this.glue = glue; - Class glueCodeClass = StepDefs.class; - for (Method method : glueCodeClass.getMethods()) { - backend.loadGlue(glue, method, glueCodeClass); - } - } - - @Override - public void setUnreportedStepExecutor(UnreportedStepExecutor executor) { - backend.setUnreportedStepExecutor(executor); - } - - @Override - public void buildWorld() { - backend.buildWorld(); - } - - @Override - public void disposeWorld() { - backend.disposeWorld(); - } - - @Override - public String getSnippet(Step step, FunctionNameGenerator functionNameGenerator) { - return backend.getSnippet(step, functionNameGenerator); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateClassFinder.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateClassFinder.java deleted file mode 100755 index ffd279988..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateClassFinder.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import cucumber.api.java.en.When; -import cucumber.runtime.ClassFinder; -import java.util.Arrays; -import java.util.Collection; - -/** - * - * @author pthomas3 - */ -public class KarateClassFinder implements ClassFinder { - - private final ClassLoader classLoader; - - public KarateClassFinder(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - @Override - public Collection> getDescendants(Class parentType, String packageName) { - Class[] classes = new Class[]{When.class}; - return Arrays.asList(classes); - } - - @Override - public Class loadClass(String className) throws ClassNotFoundException { - return (Class) classLoader.loadClass(className); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateFeature.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateFeature.java deleted file mode 100644 index 9c7323df6..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateFeature.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.FileUtils; -import cucumber.runtime.model.CucumberFeature; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class KarateFeature { - - private final KarateRuntimeOptions runtimeOptions; - private final File file; - private final CucumberFeature feature; - - public CucumberFeature getFeature() { - return feature; - } - - public KarateFeature(CucumberFeature feature, KarateRuntimeOptions karateOptions) { - file = FileUtils.resolveIfClassPath(feature.getPath(), karateOptions.getClassLoader()); - this.feature = feature; - this.runtimeOptions = karateOptions; - } - - public KarateFeature(File file) { - this.file = file; - runtimeOptions = new KarateRuntimeOptions(file); - feature = runtimeOptions.loadFeatures().get(0); - } - - public static List loadFeatures(KarateRuntimeOptions runtimeOptions) { - List features = runtimeOptions.loadFeatures(); - List karateFeatures = new ArrayList(features.size()); - for (CucumberFeature feature : features) { - KarateFeature kf = new KarateFeature(feature, runtimeOptions); - karateFeatures.add(kf); - } - return karateFeatures; - } - - public KarateRuntime getRuntime(KarateReporter reporter) { - KarateRuntime kr = runtimeOptions.getRuntime(file, reporter); - reporter.setLogger(kr.getLogger()); - return kr; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateHtmlReporter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateHtmlReporter.java deleted file mode 100644 index 224886323..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateHtmlReporter.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.FileUtils; -import com.intuit.karate.StringUtils; -import com.intuit.karate.XmlUtils; -import cucumber.runtime.model.CucumberFeature; -import gherkin.formatter.Formatter; -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Background; -import gherkin.formatter.model.DataTableRow; -import gherkin.formatter.model.DocString; -import gherkin.formatter.model.Examples; -import gherkin.formatter.model.Feature; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.ScenarioOutline; -import gherkin.formatter.model.Step; -import java.io.File; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Stack; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -/** - * - * @author pthomas3 - */ -public class KarateHtmlReporter extends KarateReporterBase { - - private final Reporter reporter; - private final Formatter formatter; - private final String buildDir; - - private CucumberFeature feature; - private Document doc; - private List steps; - private int currentScenario; - private int exampleNumber; - - private final DecimalFormat NUMBER_FORMAT = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - - public KarateHtmlReporter(Reporter reporter, Formatter formatter) { - this.reporter = reporter; - this.formatter = formatter; - NUMBER_FORMAT.applyPattern("0.######"); - String command = System.getProperty("sun.java.command", ""); - buildDir = command.contains("org.gradle.") ? "build" : "target"; - tempFilePath = buildDir + "/karate-html.log"; - } - - private void append(String path, Node node) { - Node temp = XmlUtils.getNodeByPath(doc, path, true); - temp.appendChild(node); - } - - private void set(String path, String value) { - XmlUtils.setByPath(doc, path, value); - } - - private Node node(String name, String clazz, String text) { - return XmlUtils.createElement(doc, name, text, clazz == null ? null : Collections.singletonMap("class", clazz)); - } - - private Node node(String name, String clazz) { - return node(name, clazz, null); - } - - private Node div(String clazz, String value) { - return node("div", clazz, value); - } - - private Node div(String clazz, Node... childNodes) { - Node parent = node("div", clazz); - for (Node child : childNodes) { - parent.appendChild(child); - } - return parent; - } - - private String getFile(String name) { - return FileUtils.toString(getClass().getClassLoader().getResourceAsStream(name)); - } - - public void startKarateFeature(CucumberFeature feature) { - currentScenario = 0; - this.feature = feature; - String html = getFile("report-template.html"); - String img = getFile("karate-logo.svg"); - Node svg = XmlUtils.toXmlDoc(img); - String js = getFile("report-template.js"); - doc = XmlUtils.toXmlDoc(html); - XmlUtils.setByPath(doc, "/html/body/img", svg); - set("/html/head/title", feature.getPath()); - set("/html/head/script", js); - } - - public void endKarateFeature() { - String xml = "/n" + XmlUtils.toString(doc); - String packageName = FileUtils.toPackageQualifiedName(feature.getPath()); - File file = new File(buildDir + "/surefire-reports/TEST-" + packageName + ".html"); - try { - FileUtils.writeToFile(file, xml); - System.out.println("Karate version: " + FileUtils.getKarateVersion()); - System.out.println("html report: (paste into browser to view)\n" - + "-----------------------------------------\n" - + file.toURI() + '\n'); - } catch (Exception e) { - System.out.println("html report output failed: " + e.getMessage()); - } - } - - private String getScenarioName(Scenario scenario) { - String scenarioName = StringUtils.trimToNull(scenario.getName()); - if (scenarioName == null) { - scenarioName = currentScenario + ""; - } - if (scenario.getKeyword().equals("Scenario Outline")) { - return scenarioName + " (" + (++exampleNumber) + ")"; - } else { - return scenarioName; - } - } - - private String getDuration(Result result) { - if (result.getDuration() == null) { - return "-"; - } - double duration = ((double) result.getDuration()) / 1000000000; - return NUMBER_FORMAT.format(duration); - } - - private void appendLog(Node parent, String log) { - if (!log.isEmpty()) { - Node pre = node("div", "preformatted"); - pre.setTextContent(log); - parent.appendChild(pre); - } - } - - //========================================================================== - private ReportStep prevStep; - private Stack> callStack; - - @Override - public void karateStepProceed(Step step, Match match, Result result, CallContext callContext) { - String log = appender.collect(); - // step should be first - int prevDepth = prevStep == null ? 0 : prevStep.getCallContext().callDepth; - int currDepth = callContext.callDepth; - prevStep = new ReportStep(step, match, result, log, callContext); - if (currDepth > prevDepth) { // called - List temp = new ArrayList(); - temp.add(prevStep); - callStack.push(temp); - } else { - if (currDepth < prevDepth) { // callBegin return - for (ReportStep s : callStack.pop()) { - prevStep.addCalled(s); - } - } - if (callStack.isEmpty()) { - steps.add(prevStep); - } else { - callStack.peek().add(prevStep); - } - } - // just pass on to downstream - formatter.step(step); - reporter.match(match); - reporter.result(result); - } - - @Override - public void result(Result result) { - // only downstream - reporter.result(result); - } - - @Override - public void startOfScenarioLifeCycle(Scenario scenario) { - currentScenario++; - steps = new ArrayList(); - prevStep = null; - callStack = new Stack(); - Node scenarioDiv = div("scenario"); - append("/html/body/div", scenarioDiv); - Node scenarioHeadingDiv = div("scenario-heading", - node("span", "scenario-keyword", scenario.getKeyword() + ": "), - node("span", "scenario-name", getScenarioName(scenario))); - scenarioDiv.appendChild(scenarioHeadingDiv); - formatter.startOfScenarioLifeCycle(scenario); - } - - @Override - public void examples(Examples examples) { - exampleNumber = 0; - formatter.examples(examples); - } - - private void stepHtml(ReportStep reportStep, Node parent) { - Step step = reportStep.getStep(); - Result result = reportStep.getResult(); - String extraClass = ""; - if ("failed".equals(result.getStatus())) { - extraClass = " failed"; - } else if ("skipped".equals(result.getStatus())) { - extraClass = " skipped"; - } else { - extraClass = " passed"; - } - Node stepRow = div("step-row", - div("step-cell" + extraClass, step.getKeyword() + step.getName()), - div("time-cell" + extraClass, getDuration(result))); - parent.appendChild(stepRow); - if (step.getRows() != null) { - Node table = node("table", null); - parent.appendChild(table); - for (DataTableRow row : step.getRows()) { - Node tr = node("tr", null); - table.appendChild(tr); - for (String cell : row.getCells()) { - tr.appendChild(node("td", null, cell)); - } - } - } - if (reportStep.getCalled() != null) { // this is a 'call' - for (ReportStep rs : reportStep.getCalled()) { - Node calledStepsDiv = div("scenario-steps-nested"); - parent.appendChild(calledStepsDiv); - stepHtml(rs, calledStepsDiv); - } - } else if (step.getDocString() != null) { // only for non-call, else un-synced stack traces may creep in - DocString docString = step.getDocString(); - parent.appendChild(node("div", "preformatted", docString.getValue())); - } - appendLog(parent, reportStep.getLog()); - } - - @Override - public void endOfScenarioLifeCycle(Scenario scenario) { - Node scenarioStepsDiv = div("scenario-steps"); - append("/html/body/div/div[" + currentScenario + "]", scenarioStepsDiv); - int count = steps.size(); - for (int i = 0; i < count; i++) { - ReportStep reportStep = steps.get(i); - stepHtml(reportStep, scenarioStepsDiv); - } - formatter.endOfScenarioLifeCycle(scenario); - } - - // as-is =================================================================== - @Override - public void feature(Feature f) { - formatter.feature(f); - } - - @Override - public void done() { - formatter.done(); - } - - @Override - public void background(Background background) { - formatter.background(background); - } - - @Override - public void scenario(Scenario scenario) { - formatter.scenario(scenario); - } - - @Override - public void scenarioOutline(ScenarioOutline scenarioOutline) { - formatter.scenarioOutline(scenarioOutline); - } - - @Override - public void match(Match match) { - reporter.match(match); - } - - @Override - public void embedding(String mimeType, byte[] data) { - reporter.embedding(mimeType, data); - } - - @Override - public void write(String text) { - reporter.write(text); - } - - @Override - public void uri(String uri) { - formatter.uri(uri); - } - - @Override - public void close() { - formatter.close(); - } - - @Override - public void eof() { - formatter.eof(); - } - - @Override - public void syntaxError(String state, String event, List legalEvents, String uri, Integer line) { - formatter.syntaxError(state, event, legalEvents, uri, line); - } - - @Override - public void before(Match match, Result result) { - reporter.before(match, result); - } - - @Override - public void after(Match match, Result result) { - reporter.after(match, result); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitAndJsonReporter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitAndJsonReporter.java deleted file mode 100644 index f94e5ea62..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitAndJsonReporter.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.FileUtils; -import com.intuit.karate.StringUtils; -import cucumber.runtime.formatter.CucumberJSONFormatter; -import gherkin.formatter.model.Background; -import gherkin.formatter.model.Examples; -import gherkin.formatter.model.Feature; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.ScenarioOutline; -import gherkin.formatter.model.Step; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class KarateJunitAndJsonReporter extends KarateReporterBase { - - private final KarateJunitFormatter junit; - private final CucumberJSONFormatter json; - private final String xmlReportPath; - private final String jsonReportPath; - - private Exception failureReason; - - public void setFailureReason(Exception failureReason) { - this.failureReason = failureReason; - } - - public Exception getFailureReason() { - return failureReason; - } - - public KarateJunitFormatter getJunitFormatter() { - return junit; - } - - public KarateJunitAndJsonReporter(String featurePath, String reportPath) throws IOException { - this.xmlReportPath = reportPath; - junit = new KarateJunitFormatter(featurePath, reportPath); - int pos = reportPath.lastIndexOf('.'); // foo/bar.xml - String basePath = reportPath.substring(0, pos); - jsonReportPath = basePath + ".json"; - tempFilePath = basePath + ".log"; - FileWriter fileWriter = new FileWriter(jsonReportPath); - json = new CucumberJSONFormatter(fileWriter); - } - - public static KarateJunitAndJsonReporter getInstance(String featurePath, String reportDirPath) { - File reportDir = new File(reportDirPath); - String featurePackagePath = FileUtils.toPackageQualifiedName(featurePath); - try { - reportDir.mkdirs(); - reportDirPath = reportDir.getPath() + File.separator; - String reportPath = reportDirPath + "TEST-" + featurePackagePath + ".xml"; - return new KarateJunitAndJsonReporter(featurePackagePath, reportPath); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public void karateStepProceed(Step step, Match match, Result result, CallContext callContext) { - junit.step(step); - json.step(step); - // step has to happen first ! - match(match); - if ("aborted".equals(result.getStatus())) { - result = Result.SKIPPED; // else 3rd-party cucumber reporter breaks - } - result(result); - } - - @Override - public void syntaxError(String state, String event, List legalEvents, String uri, Integer line) { - junit.syntaxError(state, event, legalEvents, uri, line); - json.syntaxError(state, event, legalEvents, uri, line); - } - - @Override - public void uri(String uri) { - junit.uri(uri); - json.uri(uri); - this.uri = uri; - } - - private String uri; - - private Feature rename(Feature f) { - String name = uri; // swap - String description = f.getName(); - String extra = StringUtils.trimToNull(f.getDescription()); - if (extra != null) { - description = description + '\n' + extra; - } - return new Feature(f.getComments(), f.getTags(), f.getKeyword(), name, description, f.getLine(), f.getId()); - } - - @Override - public void feature(Feature feature) { - junit.feature(feature); - json.feature(rename(feature)); // use the uri as the name - } - - @Override - public void scenarioOutline(ScenarioOutline scenarioOutline) { - junit.scenarioOutline(scenarioOutline); - json.scenarioOutline(scenarioOutline); - } - - @Override - public void examples(Examples examples) { - junit.examples(examples); - json.examples(examples); - } - - @Override - public void startOfScenarioLifeCycle(Scenario scenario) { - junit.startOfScenarioLifeCycle(scenario); - json.startOfScenarioLifeCycle(scenario); - } - - @Override - public void background(Background background) { - junit.background(background); - json.background(background); - } - - @Override - public void scenario(Scenario scenario) { - junit.scenario(scenario); - json.scenario(scenario); - } - - @Override - public void endOfScenarioLifeCycle(Scenario scenario) { - junit.endOfScenarioLifeCycle(scenario); - json.endOfScenarioLifeCycle(scenario); - } - - @Override - public void done() { - junit.done(); - json.done(); - } - - @Override - public void close() { - junit.close(); - json.close(); - FileUtils.renameFileIfZeroBytes(xmlReportPath); - FileUtils.renameFileIfZeroBytes(jsonReportPath); - } - - @Override - public void eof() { - junit.eof(); - json.eof(); - } - - @Override - public void before(Match match, Result result) { - junit.before(match, result); - json.before(match, result); - } - - @Override - public void result(Result result) { - junit.result(result); - json.result(result); - } - - @Override - public void after(Match match, Result result) { - junit.after(match, result); - json.after(match, result); - } - - @Override - public void match(Match match) { - junit.match(match); - json.match(match); - } - - @Override - public void embedding(String mimeType, byte[] data) { - junit.embedding(mimeType, data); - json.embedding(mimeType, data); - } - - @Override - public void write(String text) { - junit.write(text); - json.write(text); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitFormatter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitFormatter.java deleted file mode 100644 index 7bb1b77b7..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateJunitFormatter.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.FileUtils; -import com.intuit.karate.StringUtils; -import com.intuit.karate.exception.KarateException; -import cucumber.runtime.CucumberException; -import cucumber.runtime.io.URLOutputStream; -import cucumber.runtime.io.UTF8OutputStreamWriter; -import gherkin.formatter.Formatter; -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Background; -import gherkin.formatter.model.Examples; -import gherkin.formatter.model.Feature; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.ScenarioOutline; -import gherkin.formatter.model.Step; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URL; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * adapted from cucumber.runtime.formatter.JUnitFormatter - * - * @author pthomas3 - */ -public class KarateJunitFormatter implements Formatter, Reporter { - - private static final Logger logger = LoggerFactory.getLogger(KarateJunitFormatter.class); - - private final Writer out; - private final Document doc; - private final Element rootElement; - - private TestCase testCase; - private Element currentElement; - - private final String featurePath; - private final String reportPath; - - private int currentScenario; - private int exampleNumber; - - private int testCount; - private int failCount; - private int skipCount; - private double timeTaken; - private Set failMessages; - - public int getTestCount() { - return testCount; - } - - public int getFailCount() { - return failCount; - } - - public int getSkipCount() { - return skipCount; - } - - public double getTimeTaken() { - return timeTaken; - } - - public boolean isFail() { - return failCount > 0; - } - - public String getFeaturePath() { - return featurePath; - } - - public Collection getFailMessages() { - return failMessages; - } - - public KarateJunitFormatter(String featurePath, String reportPath) throws IOException { - this.featurePath = featurePath; - this.reportPath = reportPath; - logger.trace(">> {}", reportPath); - URL url = FileUtils.toFileUrl(reportPath); - this.out = new UTF8OutputStreamWriter(new URLOutputStream(url)); - try { - doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); - rootElement = doc.createElement("testsuite"); - doc.appendChild(rootElement); - } catch (ParserConfigurationException e) { - throw new CucumberException("Error while processing unit report", e); - } - } - - @Override - public void feature(Feature feature) { - testCase = new TestCase(); - testCase.feature = feature; - } - - @Override - public void step(Step step) { - testCase.steps.add(step); - } - - private void printStatsToConsole() { - System.out.println("---------------------------------------------------------"); - System.out.println("feature: " + featurePath); - System.out.println("report: " + reportPath); - System.out.println(String.format("scenarios: %2d | failed: %2d | skipped: %2d | time: %.2f", testCount, failCount, skipCount, timeTaken)); - System.out.println("---------------------------------------------------------"); - } - - @Override - public void done() { - try { - String featureName = StringUtils.trimToNull(testCase.feature.getName()); - if (featureName == null) { - featureName = featurePath; - } - rootElement.setAttribute("name", featureName); - String testCountString = rootElement.getAttribute("tests"); - try { - testCount = Integer.valueOf(testCountString); - } catch (Exception e) { - testCount = 0; - logger.warn("invalid test count: {}", e.getMessage()); - } - failCount = rootElement.getElementsByTagName("failure").getLength(); - rootElement.setAttribute("failures", String.valueOf(failCount)); - skipCount = rootElement.getElementsByTagName("skipped").getLength(); - rootElement.setAttribute("skipped", String.valueOf(skipCount)); - timeTaken = sumTimes(rootElement.getElementsByTagName("testcase")); - rootElement.setAttribute("time", formatTime(timeTaken)); - printStatsToConsole(); - if (rootElement.getElementsByTagName("testcase").getLength() == 0) { - addDummyTestCase(); // to avoid failed Jenkins jobs - } - TransformerFactory transfac = TransformerFactory.newInstance(); - Transformer trans = transfac.newTransformer(); - trans.setOutputProperty(OutputKeys.INDENT, "yes"); - StreamResult result = new StreamResult(out); - DOMSource source = new DOMSource(doc); - trans.transform(source, result); - out.close(); // this should flush() as well - } catch (Exception e) { - throw new KarateException("error saving junit xml file", e); - } - logger.trace("<< {}", reportPath); - } - - @Override - public void startOfScenarioLifeCycle(Scenario scenario) { - testCase.steps.clear(); - testCase.results.clear(); - currentScenario++; - testCase.scenario = scenario; - currentElement = testCase.createTestCaseElement(doc); - testCase.writeElement(currentElement); - rootElement.appendChild(currentElement); - increaseAttributeValue(rootElement, "tests"); - } - - @Override - public void examples(Examples examples) { - exampleNumber = 0; - } - - @Override - public void endOfScenarioLifeCycle(Scenario scenario) { - if (testCase.steps.isEmpty()) { - testCase.handleEmptyTestCase(doc, currentElement); - } else { - testCase.updateElement(currentElement); - } - } - - private void addDummyTestCase() { - Element dummy = doc.createElement("testcase"); - dummy.setAttribute("classname", "dummy"); - dummy.setAttribute("name", "dummy"); - rootElement.appendChild(dummy); - Element skipped = doc.createElement("skipped"); - skipped.setAttribute("message", "No features found"); - dummy.appendChild(skipped); - } - - @Override - public void result(Result result) { - testCase.results.add(result); - //testCase.updateElement(currentElement); - } - - private double sumTimes(NodeList testCaseNodes) { - double totalDurationSecondsForAllTimes = 0.0d; - for (int i = 0; i < testCaseNodes.getLength(); i++) { - try { - double testCaseTime - = Double.parseDouble(testCaseNodes.item(i).getAttributes().getNamedItem("time").getNodeValue()); - totalDurationSecondsForAllTimes += testCaseTime; - } catch (Exception e) { - logger.warn("junit xml reporter failed: {}", e.getMessage()); - } - } - return totalDurationSecondsForAllTimes; - } - - private String formatTime(double time) { - DecimalFormat nfmt = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - nfmt.applyPattern("0.######"); - return nfmt.format(time); - } - - private void increaseAttributeValue(Element element, String attribute) { - int value = 0; - if (element.hasAttribute(attribute)) { - value = Integer.parseInt(element.getAttribute(attribute)); - } - element.setAttribute(attribute, String.valueOf(++value)); - } - - private class TestCase { - - private final DecimalFormat NUMBER_FORMAT = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US); - - private TestCase(Scenario scenario) { - this.scenario = scenario; - NUMBER_FORMAT.applyPattern("0.######"); - } - - private TestCase() { - this(null); - } - - Scenario scenario; - private Feature feature; - final List steps = new ArrayList(); - final List results = new ArrayList(); - - private Element createTestCaseElement(Document doc) { - return doc.createElement("testcase"); - } - - private void writeElement(Element tc) { - tc.setAttribute("classname", featurePath); - tc.setAttribute("name", calculateElementName(scenario)); - } - - private String calculateElementName(Scenario scenario) { - String scenarioName = StringUtils.trimToNull(scenario.getName()); - if (scenarioName == null) { - scenarioName = currentScenario + ""; - } - if (scenario.getKeyword().equals("Scenario Outline")) { - return scenarioName + " (" + (++exampleNumber) + ")"; - } else { - return scenarioName; - } - } - - public void updateElement(Element tc) { - tc.setAttribute("time", calculateTotalDurationString()); - StringBuilder sb = new StringBuilder(); - addStepAndResultListing(sb); - Result skipped = null, failed = null; - for (Result result : results) { - if ("failed".equals(result.getStatus())) { - failed = result; - } - if ("undefined".equals(result.getStatus()) || "pending".equals(result.getStatus())) { - skipped = result; - } - } - Element child; - if (failed != null) { - addStackTrace(sb, failed); - child = createElementWithMessage(doc, sb, "failure", failed.getErrorMessage()); - if (failMessages == null) { - // TODO investigate why a set is needed, a list ends up with mysterious duplicates - failMessages = new LinkedHashSet(); - } - failMessages.add(failed.getErrorMessage()); - } else if (skipped != null) { - child = createElement(doc, sb, "skipped"); - } else { - child = createElement(doc, sb, "system-out"); - } - Node existingChild = tc.getFirstChild(); - if (existingChild == null) { - tc.appendChild(child); - } else { - tc.replaceChild(child, existingChild); - } - } - - public void handleEmptyTestCase(Document doc, Element tc) { - tc.setAttribute("time", calculateTotalDurationString()); - Element child = createElementWithMessage(doc, new StringBuilder(), "skipped", "The scenario has no steps"); - tc.appendChild(child); - } - - private String calculateTotalDurationString() { - long totalDurationNanos = 0; - for (Result r : results) { - totalDurationNanos += r.getDuration() == null ? 0 : r.getDuration(); - } - double totalDurationSeconds = ((double) totalDurationNanos) / 1000000000; - return NUMBER_FORMAT.format(totalDurationSeconds); - } - - private void addStepAndResultListing(StringBuilder sb) { - for (int i = 0; i < steps.size(); i++) { - int length = sb.length(); - String resultStatus = "not executed"; - if (i < results.size()) { - resultStatus = results.get(i).getStatus(); - } - sb.append(steps.get(i).getKeyword()); - sb.append(steps.get(i).getName()); - do { - sb.append("."); - } while (sb.length() - length < 76); - sb.append(resultStatus); - sb.append("\n"); - } - } - - private void addStackTrace(StringBuilder sb, Result failed) { - sb.append("\nStackTrace:\n"); - StringWriter sw = new StringWriter(); - failed.getError().printStackTrace(new PrintWriter(sw)); - sb.append(sw.toString()); - } - - private Element createElementWithMessage(Document doc, StringBuilder sb, String elementType, String message) { - Element child = createElement(doc, sb, elementType); - child.setAttribute("message", message); - return child; - } - - private Element createElement(Document doc, StringBuilder sb, String elementType) { - Element child = doc.createElement(elementType); - child.appendChild(doc.createCDATASection(sb.toString())); - return child; - } - - } - - //========================================================================== - - @Override - public void syntaxError(String state, String event, List legalEvents, String uri, Integer line) { - - } - - @Override - public void uri(String uri) { - - } - - @Override - public void scenarioOutline(ScenarioOutline scenarioOutline) { - - } - - @Override - public void background(Background background) { - - } - - @Override - public void scenario(Scenario scenario) { - - } - - @Override - public void close() { - - } - - @Override - public void eof() { - - } - - @Override - public void before(Match match, Result result) { - - } - - @Override - public void after(Match match, Result result) { - - } - - @Override - public void match(Match match) { - - } - - @Override - public void embedding(String mimeType, byte[] data) { - - } - - @Override - public void write(String text) { - - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateObjectFactory.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateObjectFactory.java deleted file mode 100755 index 90663ad35..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateObjectFactory.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.ScriptEnv; -import com.intuit.karate.StepDefs; -import cucumber.api.java.ObjectFactory; - -/** - * - * @author pthomas3 - */ -public class KarateObjectFactory implements ObjectFactory { - - private StepDefs stepDefs; - private ScriptEnv scriptEnv; - private final CallContext callContext; - - public KarateObjectFactory(ScriptEnv scriptEnv, CallContext callContext) { - this.scriptEnv = scriptEnv; - this.callContext = callContext; - } - - public StepDefs reset(String envString) { - scriptEnv = scriptEnv.refresh(envString); - stop(); // clear step defs - return getInstance(null); - } - - public ScriptEnv getEnv() { - if (stepDefs != null) { // get the latest, just in case it was clobbered - return stepDefs.context.getEnv(); - } else { - return scriptEnv; - } - } - - @Override - public void start() { - - } - - @Override - public void stop() { - stepDefs = null; // ensure re-build for multiple scenarios in the same feature - } - - @Override - public boolean addClass(Class glueClass) { - return true; - } - - @Override - public T getInstance(Class glueClass) { - if (stepDefs == null) { - // the lazy forEnvAndCurrentWorkingDir gives users the chance to over-ride the env - // for example using a JUnit @BeforeClass hook - stepDefs = new StepDefs(scriptEnv, callContext); - } - return (T) stepDefs; - } - - public StepDefs getStepDefs() { - if (stepDefs == null) { - getInstance(null); - } - return stepDefs; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporter.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporter.java deleted file mode 100644 index 017c69502..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporter.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptContext; -import gherkin.formatter.Formatter; -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Step; - -/** - * - * @author pthomas3 - */ -public interface KarateReporter extends Formatter, Reporter { - - public void callBegin(FeatureWrapper feature, CallContext callContext); - - public void exampleBegin(ScenarioWrapper feature, CallContext callContext); - - public void karateStep(Step step, Match match, Result result, CallContext call, ScriptContext context); - - public void karateStepProceed(Step step, Match match, Result result, CallContext call); - - public void setLogger(Logger logger); - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporterBase.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporterBase.java deleted file mode 100644 index 7643c526d..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateReporterBase.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.JsonUtils; -import com.intuit.karate.FileLogAppender; -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptContext; -import com.intuit.karate.StringUtils; -import gherkin.formatter.model.DocString; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Step; - -/** - * - * @author pthomas3 - */ -public abstract class KarateReporterBase implements KarateReporter { - - protected String tempFilePath; - protected FileLogAppender appender; - - @Override - public void setLogger(Logger logger) { - appender = new FileLogAppender(tempFilePath, logger); - } - - public static Result passed(long time) { - return new Result(Result.PASSED, time, null, StepResult.DUMMY_OBJECT); - } - - public static Result failed(long time, Throwable t) { - return new Result(Result.FAILED, null, t, StepResult.DUMMY_OBJECT); - } - - @Override // this is a hack to bring called feature steps into cucumber reports - public void callBegin(FeatureWrapper feature, CallContext callContext) { - appender.collect(); // clear log to suppress misleading stack trace from previous call if any - DocString docString = null; - if (callContext.callArg != null) { - String json = JsonUtils.toPrettyJsonString(JsonUtils.toJsonDoc(callContext.callArg)); - docString = new DocString("", json, 0); - } - String prefix = "call" + (callContext.loopIndex == -1 ? "" : "[" + callContext.loopIndex + "]"); - String featureName = StringUtils.trimToNull(feature.getFeature().getGherkinFeature().getName()); - String scenarioName = StringUtils.trimToNull(feature.getFirstScenarioName()); - if (featureName != null) { - prefix = prefix + " [" + featureName + "]"; - } - if (scenarioName != null) { - prefix = prefix + " [" + scenarioName + "]"; - } - Step step = new Step(null, "* ", prefix + " " + feature.getPath(), 0, null, docString); - karateStep(step, Match.UNDEFINED, passed(0L), callContext, null); - } - - @Override // this is a hack to format scenario outlines better when they appear in a 'called' feature - public void exampleBegin(ScenarioWrapper scenario, CallContext callContext) { - String data = StringUtils.trimToNull(scenario.getScenario().getVisualName()); - Step step = new Step(null, "* ", data, 0, null, null); - karateStep(step, Match.UNDEFINED, passed(0L), callContext, null); - } - - @Override // see the step() method for an explanation of this hack - public void karateStep(Step step, Match match, Result result, CallContext callContext, ScriptContext context) { - boolean isPrint = step.getName().startsWith("print "); - boolean isNoise = false; // TODO step.getKeyword().charAt(0) == '*'; - boolean showAllSteps = true; // TODO context == null ? true : context.getConfig().isShowAllSteps(); - boolean logEnabled = context == null ? true : context.getConfig().isLogEnabled(); - if (!isPrint && isNoise && !showAllSteps) { - appender.collect(); // swallow log - } - if (step.getDocString() == null && (isPrint || logEnabled)) { - String log = appender.collect(); - if (!log.isEmpty()) { - DocString docString = new DocString("", log, step.getLine()); - step = new Step(step.getComments(), step.getKeyword(), step.getName(), step.getLine(), step.getRows(), docString); - } - } - // TODO figure out a way to skip steps completely - // exiting here does not work because of some weird held state in the json reporter :( - karateStepProceed(step, match, result, callContext); - } - - @Override - public void step(Step step) { - // hack alert ! - // normally the cucumber formatter iterates over all steps before execution begins - // we don't, and this actually speeds up things considerably, see also CucumberUtils.runStep() - // now we can 'in-line' called feature steps in the final report, plus time stats - see StepWrapper.run() - // the downside is that on failure, we don't show skipped steps (only in called features) - // but really, this should not be a big concern for karate users - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntime.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntime.java deleted file mode 100644 index b9a525c8e..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntime.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.Logger; -import com.intuit.karate.ScriptContext; -import com.intuit.karate.ScriptEnv; -import com.intuit.karate.ScriptValue; -import com.intuit.karate.http.HttpConfig; -import cucumber.runtime.CucumberScenarioImpl; -import cucumber.runtime.CucumberStats; -import cucumber.runtime.Runtime; -import cucumber.runtime.RuntimeGlue; -import gherkin.I18n; -import gherkin.formatter.Reporter; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Scenario; -import gherkin.formatter.model.Step; -import gherkin.formatter.model.Tag; -import java.util.Collections; -import java.util.Set; - -/** - * - * @author pthomas3 - */ -public class KarateRuntime extends Runtime { - - private final KarateBackend backend; - private final CucumberStats stats; - private CucumberScenarioImpl scenarioResult; - private boolean stopped; - private ScriptContext prevContext; - - public KarateRuntime(KarateRuntimeOptions kro, KarateBackend backend, RuntimeGlue glue) { - super(kro.getResourceLoader(), kro.getClassLoader(), Collections.singletonList(backend), kro.getRuntimeOptions(), glue); - this.backend = backend; - this.stats = new CucumberStats(kro.getRuntimeOptions().isMonochrome()); - } - - public Logger getLogger() { - return backend.getEnv().logger; - } - - private void addStepToCounterAndResult(Result result) { - scenarioResult.add(result); - stats.addStep(result); - } - - @Override - public void runStep(String featurePath, Step step, Reporter reporter, I18n i18n) { - if (stopped) { - Match match = Match.UNDEFINED; - Result result = Result.SKIPPED; - if (reporter instanceof KarateReporter) { // simulate cucumber flow to keep json-formatter happy - // below call internally invokes reporter.match(match) and reporter.result(result) as - // KarateReporterBase.karateStep() -> karateStepProceed() -> result() / match() - // the else clause is needed to compensate ! - ((KarateReporter) reporter).karateStep(step, match, result, backend.getCallContext(), backend.getStepDefs().context); - } else { - reporter.match(match); - reporter.result(result); - } - addStepToCounterAndResult(result); - return; - } - StepResult result = CucumberUtils.runStep(step, reporter, i18n, backend); - if (!result.isPass() || result.isAbort()) { - if (!result.isAbort()) { - addError(result.getError()); - backend.setScenarioError(result.getError()); - } - prevContext = backend.getStepDefs().context; - stopped = true; // skip remaining steps - } - addStepToCounterAndResult(result.getResult()); - } - - @Override - public void buildBackendWorlds(Reporter reporter, Set tags, Scenario scenario) { - backend.buildWorld(); - // tags only work at top-level, this does not apply to 'called' features - CucumberUtils.resolveTagsAndTagValues(backend, tags); - // 'karate.info' also does not apply to 'called' features - CucumberUtils.initScenarioInfo(scenario, backend); - scenarioResult = new CucumberScenarioImpl(reporter, tags, scenario); - } - - @Override - public void disposeBackendWorlds(String scenarioDesignation) { - stats.addScenario(scenarioResult.getStatus(), scenarioDesignation); - prevContext = backend.getStepDefs().context; - invokeAfterHookIfConfigured(false); - backend.disposeWorld(); - stopped = false; // else a failed scenario results in all remaining ones in the feature being skipped ! - } - - @Override - public void printSummary() { - stats.printStats(System.out, false); - } - - public void afterFeature() { - invokeAfterHookIfConfigured(true); - } - - private void invokeAfterHookIfConfigured(boolean afterFeature) { - if (prevContext == null) { // edge case where there are zero scenarios, e.g. only a Background: - ScriptEnv env = backend.getEnv(); - env.logger.warn("no runnable scenarios found: {}", env); - return; - } - HttpConfig config = prevContext.getConfig(); - ScriptValue sv = afterFeature ? config.getAfterFeature() : config.getAfterScenario(); - if (sv.isFunction()) { - try { - sv.invokeFunction(prevContext); - } catch (Exception e) { - String prefix = afterFeature ? "afterFeature" : "afterScenario"; - prevContext.logger.warn("{} hook failed: {}", prefix, e.getMessage()); - } - } - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntimeOptions.java b/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntimeOptions.java deleted file mode 100644 index 959cee18e..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/KarateRuntimeOptions.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import com.intuit.karate.FileUtils; -import com.intuit.karate.ScriptEnv; -import cucumber.runtime.RuntimeGlue; -import cucumber.runtime.RuntimeOptions; -import cucumber.runtime.RuntimeOptionsFactory; -import cucumber.runtime.UndefinedStepsTracker; -import cucumber.runtime.io.MultiLoader; -import cucumber.runtime.io.ResourceLoader; -import cucumber.runtime.model.CucumberFeature; -import cucumber.runtime.xstream.LocalizedXStreams; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class KarateRuntimeOptions { - - private final ClassLoader classLoader; - private final RuntimeOptions runtimeOptions; - private final ResourceLoader resourceLoader; - - public KarateRuntimeOptions(Class clazz) { - classLoader = clazz.getClassLoader(); - RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(clazz); - runtimeOptions = runtimeOptionsFactory.create(); - resourceLoader = new MultiLoader(classLoader); - } - - public KarateRuntimeOptions(File file) { - this(null, Arrays.asList(file.getPath())); - } - - public KarateRuntimeOptions(List tags, List files) { - classLoader = FileUtils.createClassLoader(files.toArray(new String[]{})); - if (tags != null) { - List temp = new ArrayList(); - for (String tag : tags) { // to support logical AND, user can do -t twice - temp.add("-t"); - temp.add(tag); - } - temp.addAll(files); - runtimeOptions = new RuntimeOptions(temp); - } else { - runtimeOptions = new RuntimeOptions(files); - } - resourceLoader = new MultiLoader(classLoader); - } - - public KarateRuntime getRuntime(File file, KarateReporter reporter) { - File featureDir = file.getParentFile(); - ScriptEnv env = new ScriptEnv(null, null, featureDir, file.getName(), classLoader, reporter); - CallContext callContext = new CallContext(null, true); - FeatureWrapper fw = FeatureWrapper.fromFile(file, env); - KarateBackend backend = new KarateBackend(fw, callContext); - RuntimeGlue glue = new RuntimeGlue(new UndefinedStepsTracker(), new LocalizedXStreams(classLoader)); - return new KarateRuntime(this, backend, glue); - } - - public List loadFeatures() { - return runtimeOptions.cucumberFeatures(resourceLoader); - } - - public ClassLoader getClassLoader() { - return classLoader; - } - - public ResourceLoader getResourceLoader() { - return resourceLoader; - } - - public RuntimeOptions getRuntimeOptions() { - return runtimeOptions; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/ReportStep.java b/karate-core/src/main/java/com/intuit/karate/cucumber/ReportStep.java deleted file mode 100644 index 7d5963260..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/ReportStep.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.CallContext; -import gherkin.formatter.model.Match; -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Step; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class ReportStep { - - private final Step step; - private final Match match; - private final Result result; - private final String log; - private final CallContext callContext; - private List called; - - public ReportStep(Step step, Match match, Result result, String log, CallContext callContext) { - this.step = step; - this.match = match; - this.result = result; - this.log = log; - this.callContext = callContext; - } - - public ReportStep addCalled(ReportStep step) { - if (called == null) { - called = new ArrayList(); - } - called.add(step); - return step; - } - - public ReportStep addCalled(Step step, Match match, Result result, String log, CallContext callContext) { - return addCalled(new ReportStep(step, match, result, log, callContext)); - } - - public List getCalled() { - return called; - } - - public Match getMatch() { - return match; - } - - public Result getResult() { - return result; - } - - public Step getStep() { - return step; - } - - public String getLog() { - return log; - } - - public CallContext getCallContext() { - return callContext; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioOutlineWrapper.java b/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioOutlineWrapper.java deleted file mode 100644 index b0762131d..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioOutlineWrapper.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import cucumber.runtime.model.CucumberExamples; -import cucumber.runtime.model.CucumberScenario; -import cucumber.runtime.model.CucumberScenarioOutline; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class ScenarioOutlineWrapper { - - private final FeatureWrapper feature; - private FeatureSection section; - private final CucumberScenarioOutline scenarioOutline; - private final List scenarios; - - public ScenarioOutlineWrapper(FeatureWrapper feature, CucumberScenarioOutline scenarioOutline) { - this.feature = feature; - this.scenarioOutline = scenarioOutline; - this.scenarios = new ArrayList<>(); - for (CucumberExamples examples : scenarioOutline.getCucumberExamplesList()) { // TODO can this be more than 1 - List exampleScenarios = examples.createExampleScenarios(); - int count = exampleScenarios.size(); - for (int i = 0; i < count; i++) { - CucumberScenario scenario = exampleScenarios.get(i); - ScenarioWrapper sw = new ScenarioWrapper(feature, i, scenario, this); - scenarios.add(sw); - } - } - } - - public FeatureSection getSection() { - return section; - } - - public void setSection(FeatureSection section) { - this.section = section; - } - - public FeatureWrapper getFeature() { - return feature; - } - - public CucumberScenarioOutline getScenarioOutline() { - return scenarioOutline; - } - - public List getScenarios() { - return scenarios; - } - - public int getLine() { - return scenarioOutline.getGherkinModel().getLine(); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioWrapper.java b/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioWrapper.java deleted file mode 100644 index 98ba88186..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/ScenarioWrapper.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import cucumber.runtime.model.CucumberBackground; -import cucumber.runtime.model.CucumberScenario; -import gherkin.formatter.model.Step; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author pthomas3 - */ -public class ScenarioWrapper { - - private final int index; - private final FeatureWrapper feature; - private FeatureSection section; - private final CucumberScenario scenario; - private final ScenarioOutlineWrapper parent; - private final List steps; - - public ScenarioWrapper(FeatureWrapper feature, int index, CucumberScenario scenario, ScenarioOutlineWrapper parent) { - this.feature = feature; - this.index = index; - this.scenario = scenario; - this.parent = parent; - this.steps = new ArrayList<>(); - CucumberBackground cucumberBackground = scenario.getCucumberBackground(); - int counter = 0; - int currentLine = 0; - if (cucumberBackground != null) { - for (Step step : cucumberBackground.getSteps()) { - int firstLine = step.getLine(); - String priorText = feature.joinLines(currentLine, firstLine - 1); - steps.add(new StepWrapper(this, counter++, priorText, step, true)); - currentLine = step.getLineRange().getLast(); - } - } - for (Step step : scenario.getSteps()) { - int firstLine = step.getLine(); - String priorText = feature.joinLines(currentLine, firstLine - 1); - steps.add(new StepWrapper(this, counter++, priorText, step, false)); - currentLine = step.getLineRange().getLast(); - } - } - - public String getNameAndDescription() { - String name = scenario.getGherkinModel().getName(); - String description = scenario.getGherkinModel().getDescription(); - return name + description; - } - - public void setSection(FeatureSection section) { - this.section = section; - } - - public FeatureSection getSection() { - if (section == null) { - return parent.getSection(); - } else { - return section; - } - } - - public int getIndex() { - return index; - } - - public List getSteps() { - return steps; - } - - public FeatureWrapper getFeature() { - return feature; - } - - public CucumberScenario getScenario() { - return scenario; - } - - public ScenarioOutlineWrapper getParent() { - return parent; - } - - public boolean isChild() { - return parent != null; - } - - public int getLine() { - return scenario.getGherkinModel().getLine(); - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/StepInterceptor.java b/karate-core/src/main/java/com/intuit/karate/cucumber/StepInterceptor.java deleted file mode 100644 index 1e9ab7bd7..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/StepInterceptor.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * The MIT License - * - * Copyright 2018 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -/** - * - * @author pthomas3 - */ -public interface StepInterceptor { - - void beforeStep(StepWrapper step, KarateBackend backend); - - void afterStep(StepResult result, KarateBackend backend); - - void afterScenario(ScenarioWrapper scenario, KarateBackend backend); - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/StepResult.java b/karate-core/src/main/java/com/intuit/karate/cucumber/StepResult.java deleted file mode 100644 index 40196daf8..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/StepResult.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import gherkin.formatter.model.Result; -import gherkin.formatter.model.Step; - -/** - * - * @author pthomas3 - */ -public class StepResult { - - public static final String ABORTED = "aborted"; - public static final Result PASSED = new Result(Result.PASSED, null, null); - public static final Object DUMMY_OBJECT = new Object(); - - private final Step step; - private final Result result; - private final boolean pass; - private final boolean abort; - - public StepResult(Step step, Result result) { - this.step = step; - this.result = result; - pass = result.getError() == null; - abort = result.getStatus().equals(ABORTED); - } - - public Step getStep() { - return step; - } - - public Result getResult() { - return result; - } - - public Throwable getError() { - return result.getError(); - } - - public boolean isPass() { - return pass; - } - - public boolean isAbort() { - return abort; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/cucumber/StepWrapper.java b/karate-core/src/main/java/com/intuit/karate/cucumber/StepWrapper.java deleted file mode 100644 index a3f89fb8a..000000000 --- a/karate-core/src/main/java/com/intuit/karate/cucumber/StepWrapper.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * The MIT License - * - * Copyright 2017 Intuit Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package com.intuit.karate.cucumber; - -import com.intuit.karate.StringUtils; -import gherkin.formatter.model.DocString; -import gherkin.formatter.model.Step; - -/** - * - * @author pthomas3 - */ -public class StepWrapper { - - private final ScenarioWrapper scenario; - private final int index; - private final Step step; - private final boolean background; - private final String priorText; - private final String text; - - public StepWrapper(ScenarioWrapper scenario, int index, String priorText, Step step, boolean background) { - this.scenario = scenario; - this.index = index; - this.priorText = StringUtils.trimToNull(priorText); - this.background = background; - this.step = step; - this.text = getStepText(step, scenario); - } - - private static String getStepText(Step step, ScenarioWrapper scenario) { - StringBuilder sb = new StringBuilder(); - sb.append(step.getKeyword()); - sb.append(step.getName()); - DocString docString = step.getDocString(); - if (docString != null) { - sb.append("\n\"\"\"\n"); - sb.append(docString.getValue()); - sb.append("\n\"\"\""); - } - if (step.getRows() != null) { - String text = scenario.getFeature().joinLines(step.getLine(), step.getLineRange().getLast() + 1); - sb.append('\n').append(text); - } - return sb.toString(); - } - - public boolean isHttpCall() { - String name = step.getName(); - return name.startsWith("method") || name.startsWith("soap"); - } - - public int getIndex() { - return index; - } - - public boolean isBackground() { - return background; - } - - public boolean isPriorTextPresent() { - return priorText != null; - } - - public String getPriorText() { - return priorText; - } - - public int getPriorTextLineCount() { - if (!isPriorTextPresent()) { - return 0; - } - String[] split = priorText.split("\n"); - return split.length; - } - - public Step getStep() { - return step; - } - - public int getStartLine() { - return step.getLine() - 1; - } - - public int getEndLine() { - return step.getLineRange().getLast() - 1; - } - - public ScenarioWrapper getScenario() { - return scenario; - } - - public String getText() { - return text; - } - - public int getLineCount() { - return getEndLine() - getStartLine() + 1; - } - -} diff --git a/karate-core/src/main/java/com/intuit/karate/ui/App.java b/karate-core/src/main/java/com/intuit/karate/ui/App.java index 6fb07f5d1..b3959914f 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/App.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/App.java @@ -27,7 +27,7 @@ import com.intuit.karate.ScriptBindings; import com.intuit.karate.convert.ConvertUtils; import com.intuit.karate.convert.PostmanItem; -import com.intuit.karate.cucumber.FeatureWrapper; +import com.intuit.karate.core.Feature; import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Scene; @@ -47,6 +47,7 @@ * @author pthomas3 */ public class App extends Application { + public static final double PADDING = 3.0; public static final Insets PADDING_INSET = new Insets(App.PADDING, App.PADDING, App.PADDING, App.PADDING); @@ -129,12 +130,12 @@ private void initNewFileAction(HeaderPanel header, String envString, Stage stage private void initFileSaveAction(AppSession session, String envString, Stage stage) { session.headerPanel.setFileSaveAction(e -> { File file; - FeatureWrapper feature = session.getFeature(); + Feature feature = session.getFeature(); if (needsNameToSave) { - String suggestedName = feature.getFeature().getGherkinFeature().getName(); + String suggestedName = "noname.feature"; file = chooseFileToSave(stage, "*.feature files", "*.feature", suggestedName); } else { - file = new File(feature.getPath()); + file = feature.getFile(); } FileUtils.writeToFile(file, feature.getText()); if (needsNameToSave) { diff --git a/karate-core/src/main/java/com/intuit/karate/ui/AppSession.java b/karate-core/src/main/java/com/intuit/karate/ui/AppSession.java index 9303093fb..8e35ad1bf 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/AppSession.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/AppSession.java @@ -24,28 +24,21 @@ package com.intuit.karate.ui; import com.intuit.karate.CallContext; -import com.intuit.karate.FileUtils; +import com.intuit.karate.Logger; import com.intuit.karate.ScriptEnv; -import com.intuit.karate.ScriptValue; -import com.intuit.karate.ScriptValueMap; -import com.intuit.karate.cucumber.CucumberUtils; -import com.intuit.karate.cucumber.FeatureFilePath; -import com.intuit.karate.cucumber.FeatureSection; -import com.intuit.karate.cucumber.FeatureWrapper; -import com.intuit.karate.cucumber.KarateBackend; -import com.intuit.karate.cucumber.ScenarioOutlineWrapper; -import com.intuit.karate.cucumber.ScenarioWrapper; -import com.intuit.karate.cucumber.StepWrapper; +import com.intuit.karate.StepDefs; +import com.intuit.karate.core.Feature; +import com.intuit.karate.core.FeatureParser; +import com.intuit.karate.core.FeatureSection; +import com.intuit.karate.core.Scenario; +import com.intuit.karate.core.ScenarioOutline; +import com.intuit.karate.core.Step; import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.FXCollections; -import javafx.collections.ObservableList; /** * @@ -54,19 +47,21 @@ public class AppSession { public final File featureFile; - private FeatureWrapper feature; // mutable, can be re-built - public final KarateBackend backend; + private Feature feature; // mutable, can be re-built public final HeaderPanel headerPanel; public final FeaturePanel featurePanel; public final VarsPanel varsPanel; public final LogPanel logPanel; public final HttpPanel httpPanel; - + public final Logger logger = new Logger(); + + private StepDefs stepDefs; + RunService runner; BooleanBinding runningNow; BooleanProperty notRunning; - public FeatureWrapper getFeature() { + public Feature getFeature() { return feature; } @@ -74,12 +69,21 @@ public AppSession(File featureFile, String envString) { this(featureFile, envString, false); } + public StepDefs getStepDefs() { + return stepDefs; + } + public ScriptEnv getEnv() { - return backend.getEnv(); + return stepDefs.context.getEnv(); } - public void resetBackendAndVarsTable(String env) { - backend.getObjectFactory().reset(env); + public ScriptEnv getEnv(String envString) { + return ScriptEnv.forEnvFeatureFileAndLogger(envString, featureFile, logger); + } + + public void resetBackendAndVarsTable(String envString) { + ScriptEnv env = getEnv(envString); + stepDefs = new StepDefs(env, new CallContext(null, true)); refreshVarsTable(); } @@ -104,11 +108,8 @@ public void runUpto(StepPanel stepPanel) { public AppSession(File featureFile, String envString, boolean test) { this.featureFile = featureFile; - FeatureFilePath ffp = FileUtils.parseFeaturePath(featureFile); - ScriptEnv env = ScriptEnv.forEnvAndFeatureFile(envString, ffp.file, ffp.searchPaths); - feature = FeatureWrapper.fromFile(ffp.file, env); - CallContext callContext = new CallContext(null, true); - backend = CucumberUtils.getBackendWithGlue(feature, callContext); + feature = FeatureParser.parse(featureFile); + resetBackendAndVarsTable(envString); if (!test) { notRunning = new SimpleBooleanProperty(Boolean.TRUE); runningNow = notRunning.not(); @@ -116,7 +117,7 @@ public AppSession(File featureFile, String envString, boolean test) { headerPanel = new HeaderPanel(this); featurePanel = new FeaturePanel(this); varsPanel = new VarsPanel(this, FXCollections.emptyObservableList()); - logPanel = new LogPanel(backend.getEnv().logger); + logPanel = new LogPanel(logger); httpPanel = new HttpPanel(); } else { headerPanel = null; @@ -139,30 +140,32 @@ public void refreshVarsTable() { } public void refreshVarsTable(VarLists stepVarLists) { - varsPanel.refresh(stepVarLists); - httpPanel.refresh(stepVarLists); + if (varsPanel != null) { // just in case called from constructor + varsPanel.refresh(stepVarLists); + httpPanel.refresh(stepVarLists); + } } public FeatureSection refresh(FeatureSection section) { return feature.getSection(section.getIndex()); } - public ScenarioOutlineWrapper refresh(ScenarioOutlineWrapper outline) { + public ScenarioOutline refresh(ScenarioOutline outline) { return feature.getSection(outline.getSection().getIndex()).getScenarioOutline(); } - public ScenarioWrapper refresh(ScenarioWrapper scenario) { + public Scenario refresh(Scenario scenario) { return feature.getScenario(scenario.getSection().getIndex(), scenario.getIndex()); } - public StepWrapper refresh(StepWrapper step) { + public Step refresh(Step step) { int stepIndex = step.getIndex(); int scenarioIndex = step.getScenario().getIndex(); int sectionIndex = step.getScenario().getSection().getIndex(); return feature.getStep(sectionIndex, scenarioIndex, stepIndex); } - public void replace(StepWrapper step, String text) { + public void replace(Step step, String text) { feature = feature.replaceStep(step, text); featurePanel.action(AppAction.REFRESH); headerPanel.initTextContent(); @@ -174,7 +177,7 @@ public void replaceFeature(String text) { } public VarLists getVars() { - return new VarLists(backend.getStepDefs()); + return new VarLists(stepDefs); } public BooleanBinding isRunningNow() { diff --git a/karate-core/src/main/java/com/intuit/karate/ui/ExamplesPanel.java b/karate-core/src/main/java/com/intuit/karate/ui/ExamplesPanel.java index 4be92d5e2..718e68712 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/ExamplesPanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/ExamplesPanel.java @@ -23,8 +23,8 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.ScenarioWrapper; -import com.intuit.karate.cucumber.StepWrapper; +import com.intuit.karate.core.Scenario; +import com.intuit.karate.core.Step; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -42,10 +42,10 @@ public class ExamplesPanel extends TitledPane { private final VBox content; private final AppSession session; - private ScenarioWrapper scenario; + private Scenario scenario; private final List stepPanels; - public ExamplesPanel(AppSession session, ScenarioWrapper scenario) { + public ExamplesPanel(AppSession session, Scenario scenario) { super(); content = new VBox(0); setContent(content); @@ -57,9 +57,9 @@ public ExamplesPanel(AppSession session, ScenarioWrapper scenario) { } private void initTitleAndContent() { - setText(scenario.getScenario().getVisualName()); + setText(scenario.getName()); Optional previousStep = Optional.empty(); - for (StepWrapper step : scenario.getSteps()) { + for (Step step : scenario.getSteps()) { StepPanel stepPanel = new StepPanel(session, step, previousStep); content.getChildren().add(stepPanel); stepPanels.add(stepPanel); diff --git a/karate-core/src/main/java/com/intuit/karate/ui/FeaturePanel.java b/karate-core/src/main/java/com/intuit/karate/ui/FeaturePanel.java index 6bdcf6ba1..26a64d13e 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/FeaturePanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/FeaturePanel.java @@ -23,8 +23,8 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.FeatureSection; -import gherkin.formatter.model.Feature; +import com.intuit.karate.core.Feature; +import com.intuit.karate.core.FeatureSection; import javafx.scene.control.ScrollPane; import javafx.scene.layout.BorderPane; import javafx.scene.layout.VBox; @@ -59,19 +59,17 @@ public FeaturePanel(AppSession session) { addSections(); this.setCenter(scrollPane); } - - private void addSections() { - final Feature gherkinFeature = session.getFeature().getFeature().getGherkinFeature(); + private void addSections() { + final Feature feature = session.getFeature(); TextFlow flow = new TextFlow(); - Text keyword=new Text(gherkinFeature.getKeyword()+" : "); - Text name=new Text(gherkinFeature.getName()); + Text keyword = new Text("Feature: "); + Text name = new Text(feature.getName()); flow.getChildren().addAll(keyword, name); - flow.setMaxHeight(8); content.getChildren().add(flow); for (FeatureSection section : session.getFeature().getSections()) { - SectionPanel sectionPanel = new SectionPanel(session, section); + SectionPanel sectionPanel = new SectionPanel(session, section); content.getChildren().add(sectionPanel); if (!sectionPanels.isEmpty()) { sectionPanel.setExpanded(false); @@ -79,12 +77,12 @@ private void addSections() { sectionPanels.add(sectionPanel); } } - + public void action(AppAction action) { for (SectionPanel panel : sectionPanels) { panel.action(action); } - } + } public void refresh() { sectionPanels.clear(); diff --git a/karate-core/src/main/java/com/intuit/karate/ui/LogPanel.java b/karate-core/src/main/java/com/intuit/karate/ui/LogPanel.java index d093bd74a..c0a42c84f 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/LogPanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/LogPanel.java @@ -23,13 +23,12 @@ */ package com.intuit.karate.ui; +import com.intuit.karate.LogAppender; import com.intuit.karate.Logger; import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; -import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; import static com.intuit.karate.ui.App.PADDING_INSET; @@ -44,6 +43,7 @@ public class LogPanel extends BorderPane { public LogPanel(Logger logger) { setPadding(PADDING_INSET); textArea = new TextArea(); + LogAppender appender = new TextAreaLogAppender(logger, textArea); textArea.setPrefRowCount(40); textArea.setPrefColumnCount(120); textArea.setFont(App.getDefaultFont()); diff --git a/karate-core/src/main/java/com/intuit/karate/ui/RunService.java b/karate-core/src/main/java/com/intuit/karate/ui/RunService.java index 1b815f897..95393621f 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/RunService.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/RunService.java @@ -80,7 +80,7 @@ protected Void call() throws Exception { session.featurePanel.action(AppAction.RUN); } } catch (Exception e) { - session.backend.getEnv().logger.error("step execution paused."); + session.getStepDefs().context.logger.error("step execution paused."); } session.markRunStopped(); return null; diff --git a/karate-core/src/main/java/com/intuit/karate/ui/ScenarioOutlinePanel.java b/karate-core/src/main/java/com/intuit/karate/ui/ScenarioOutlinePanel.java index 7d3bfbcdb..7b460481e 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/ScenarioOutlinePanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/ScenarioOutlinePanel.java @@ -23,8 +23,8 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.ScenarioOutlineWrapper; -import com.intuit.karate.cucumber.ScenarioWrapper; +import com.intuit.karate.core.Scenario; +import com.intuit.karate.core.ScenarioOutline; import java.util.ArrayList; import java.util.List; import javafx.scene.layout.BorderPane; @@ -39,10 +39,10 @@ public class ScenarioOutlinePanel extends BorderPane { private final VBox content; private final AppSession session; - private ScenarioOutlineWrapper outline; + private ScenarioOutline outline; private final List examplesPanels; - public ScenarioOutlinePanel(AppSession session, ScenarioOutlineWrapper outline) { + public ScenarioOutlinePanel(AppSession session, ScenarioOutline outline) { super(); this.session = session; this.outline = outline; @@ -53,7 +53,7 @@ public ScenarioOutlinePanel(AppSession session, ScenarioOutlineWrapper outline) } private void initTitleAndContent() { - for (ScenarioWrapper scenario : outline.getScenarios()) { + for (Scenario scenario : outline.getScenarios()) { ExamplesPanel examplePanel = new ExamplesPanel(session, scenario); content.getChildren().add(examplePanel); if (!examplesPanels.isEmpty()) { diff --git a/karate-core/src/main/java/com/intuit/karate/ui/ScenarioPanel.java b/karate-core/src/main/java/com/intuit/karate/ui/ScenarioPanel.java index 686d96713..a50ee3634 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/ScenarioPanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/ScenarioPanel.java @@ -23,8 +23,8 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.ScenarioWrapper; -import com.intuit.karate.cucumber.StepWrapper; +import com.intuit.karate.core.Scenario; +import com.intuit.karate.core.Step; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -37,33 +37,43 @@ * @author pthomas3 */ public class ScenarioPanel extends BorderPane { - - private final VBox content; + + private final VBox content; private final AppSession session; - private ScenarioWrapper scenario; + private Scenario scenario; private final List stepPanels; - - public ScenarioPanel(AppSession session, ScenarioWrapper scenario) { + + public ScenarioPanel(AppSession session, Scenario scenario) { super(); content = new VBox(0); setCenter(content); this.session = session; this.scenario = scenario; stepPanels = new ArrayList(scenario.getSteps().size()); - initTitleAndContent(); + initTitleAndContent(); } + private Optional previousStep = Optional.empty(); + + private void addStep(Step step) { + StepPanel stepPanel = new StepPanel(session, step, previousStep); + content.getChildren().add(stepPanel); + stepPanels.add(stepPanel); + previousStep = Optional.of(stepPanel); + } + private void initTitleAndContent() { - Optional previousStep = Optional.empty(); - for (StepWrapper step : scenario.getSteps()) { - StepPanel stepPanel = new StepPanel(session, step, previousStep); - content.getChildren().add(stepPanel); - stepPanels.add(stepPanel); - previousStep = Optional.of(stepPanel); + if (scenario.getFeature().getBackground() != null) { + for (Step step : scenario.getFeature().getBackground().getSteps()) { + addStep(step); + } + } + for (Step step : scenario.getSteps()) { + addStep(step); } } - + public void action(AppAction action) { scenario = session.refresh(scenario); for (StepPanel panel : stepPanels) { @@ -75,5 +85,5 @@ public void action(AppAction action) { StepPanel getStepAtIndex(int index) { return stepPanels.get(index); } - + } diff --git a/karate-core/src/main/java/com/intuit/karate/ui/SectionPanel.java b/karate-core/src/main/java/com/intuit/karate/ui/SectionPanel.java index 8b3019f70..c9fd3c28d 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/SectionPanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/SectionPanel.java @@ -23,9 +23,9 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.FeatureSection; -import com.intuit.karate.cucumber.ScenarioOutlineWrapper; -import com.intuit.karate.cucumber.ScenarioWrapper; +import com.intuit.karate.core.FeatureSection; +import com.intuit.karate.core.Scenario; +import com.intuit.karate.core.ScenarioOutline; import javafx.geometry.Insets; import javafx.scene.control.TitledPane; import javafx.scene.layout.VBox; @@ -55,14 +55,14 @@ public SectionPanel(AppSession session, FeatureSection section) { private void initTitleAndContent() { if (section.isOutline()) { - ScenarioOutlineWrapper outline = section.getScenarioOutline(); - setText(outline.getScenarioOutline().getVisualName()); + ScenarioOutline outline = section.getScenarioOutline(); + setText(outline.getName()); outlinePanel = new ScenarioOutlinePanel(session, outline); content.setPadding(new Insets(5, 5, 5, 5)); content.getChildren().add(outlinePanel); } else { - ScenarioWrapper scenario = section.getScenario(); - setText(scenario.getScenario().getVisualName()); + Scenario scenario = section.getScenario(); + setText(scenario.getName()); scenarioPanel = new ScenarioPanel(session, scenario); content.getChildren().add(scenarioPanel); } diff --git a/karate-core/src/main/java/com/intuit/karate/ui/StepException.java b/karate-core/src/main/java/com/intuit/karate/ui/StepException.java index d9296fc6f..de49bc19c 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/StepException.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/StepException.java @@ -23,7 +23,7 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.StepResult; +import com.intuit.karate.core.Result; /** * @@ -31,9 +31,9 @@ */ public class StepException extends RuntimeException { - public final StepResult result; + public final Result result; - public StepException(StepResult result) { + public StepException(Result result) { super(result.getError()); this.result = result; } diff --git a/karate-core/src/main/java/com/intuit/karate/ui/StepPanel.java b/karate-core/src/main/java/com/intuit/karate/ui/StepPanel.java index 237f81d1c..2565b0093 100644 --- a/karate-core/src/main/java/com/intuit/karate/ui/StepPanel.java +++ b/karate-core/src/main/java/com/intuit/karate/ui/StepPanel.java @@ -23,9 +23,10 @@ */ package com.intuit.karate.ui; -import com.intuit.karate.cucumber.CucumberUtils; -import com.intuit.karate.cucumber.StepResult; -import com.intuit.karate.cucumber.StepWrapper; +import com.intuit.karate.core.Engine; +import com.intuit.karate.core.Feature; +import com.intuit.karate.core.Result; +import com.intuit.karate.core.Step; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -54,7 +55,7 @@ public class StepPanel extends AnchorPane { private Optional