From ef22ef37fb4e2511c4bb2e9a6eb182d2dd1b8daf Mon Sep 17 00:00:00 2001 From: Peter Thomas Date: Sat, 8 Sep 2018 23:10:02 +0530 Subject: [PATCH] able to resolve feature files in jar files ref #520 --- .../com/intuit/karate/FeatureContext.java | 5 +- .../java/com/intuit/karate/FileUtils.java | 91 +++++++++++++----- .../main/java/com/intuit/karate/IdeUtils.java | 2 +- .../{FileResource.java => Resource.java} | 52 ++++++++-- .../java/com/intuit/karate/core/Engine.java | 6 +- .../java/com/intuit/karate/core/Feature.java | 29 +++--- .../intuit/karate/core/FeatureBackend.java | 2 +- .../karate/core/FeatureExecutionUnit.java | 4 +- .../com/intuit/karate/core/FeatureParser.java | 32 +++--- .../karate/cucumber/CucumberRunner.java | 12 +-- .../main/java/com/intuit/karate/ui/App.java | 2 +- .../src/main/java/cucumber/api/cli/Main.java | 2 +- .../java/com/intuit/karate/FileUtilsTest.java | 17 ++-- .../karate/core/AllKarateFeaturesTest.java | 13 ++- .../karate/cucumber/CucumberUtilsTest.java | 8 +- .../src/test/resources/karate-test.jar | Bin 0 -> 2363 bytes karate-demo/build.gradle | 36 ++++--- .../java/com/intuit/karate/junit4/Karate.java | 10 +- .../karate/junit4/demos/schema-like.feature | 9 ++ .../karate/junit4/files/JarLoadingTest.java | 48 +++++++++ ...ctoryRunner.java => WorkingDirRunner.java} | 2 +- .../karate/junit4/files/called2.feature | 6 ++ .../karate/junit4/files/called3.feature | 6 ++ .../junit4/files/relative/CallerRunner.java | 15 +++ .../junit4/files/relative/called1.feature | 6 ++ .../junit4/files/relative/caller.feature | 7 ++ karate-junit4/src/test/java/common.feature | 5 + 27 files changed, 312 insertions(+), 115 deletions(-) rename karate-core/src/main/java/com/intuit/karate/{FileResource.java => Resource.java} (53%) create mode 100644 karate-core/src/test/resources/karate-test.jar create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java rename karate-junit4/src/test/java/com/intuit/karate/junit4/files/{FileWorkingDirectoryRunner.java => WorkingDirRunner.java} (86%) create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/called2.feature create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/called3.feature create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/CallerRunner.java create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/called1.feature create mode 100644 karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/caller.feature create mode 100644 karate-junit4/src/test/java/common.feature diff --git a/karate-core/src/main/java/com/intuit/karate/FeatureContext.java b/karate-core/src/main/java/com/intuit/karate/FeatureContext.java index ff799a204..f9d15e280 100644 --- a/karate-core/src/main/java/com/intuit/karate/FeatureContext.java +++ b/karate-core/src/main/java/com/intuit/karate/FeatureContext.java @@ -25,6 +25,7 @@ import com.intuit.karate.core.Feature; import java.io.File; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -38,7 +39,7 @@ public class FeatureContext { public final String tagSelector; public final Feature feature; public final Logger logger; - public final File workingDir; + public final Path parentPath; public final Map callCache; private static String getEnv(String envString) { @@ -55,7 +56,7 @@ public FeatureContext(String envString, Feature feature, File workingDir, String this.feature = feature; this.callCache = new HashMap(1); this.logger = logger; - this.workingDir = workingDir == null ? feature.getFile().getParentFile() : workingDir; + this.parentPath = workingDir == null ? feature.getPath().getParent() : workingDir.toPath(); } public static FeatureContext forEnv(String env) { diff --git a/karate-core/src/main/java/com/intuit/karate/FileUtils.java b/karate-core/src/main/java/com/intuit/karate/FileUtils.java index 5dcce9197..73a73f3d6 100755 --- a/karate-core/src/main/java/com/intuit/karate/FileUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/FileUtils.java @@ -98,8 +98,8 @@ public static ScriptValue readFile(String text, ScenarioContext context) { String contents = readFileAsString(text, context); return new ScriptValue(contents, text); } else if (isFeatureFile(text)) { - FileResource fr = resolvePath(text, context); - Feature feature = FeatureParser.parse(fr.file, fr.relativePath); + Resource fr = resolvePath(text, context); + Feature feature = FeatureParser.parse(fr); feature.setCallTag(pair.right); return new ScriptValue(feature, text); } else if (isYamlFile(text)) { @@ -139,13 +139,14 @@ public static Feature resolveFeature(String path) { return feature; } - private static FileResource resolvePath(String path, ScenarioContext context) { + private static Resource resolvePath(String path, ScenarioContext context) { if (isClassPath(path) || isFilePath(path)) { - return new FileResource(fromRelativeClassPath(path), path); + return new Resource(fromRelativeClassPath(path), path); } else { try { - File file = new File(context.featureContext.workingDir + File.separator + path); - return new FileResource(file, path); + Path parentPath = context.featureContext.parentPath; + Path childPath = parentPath.resolve(path); + return new Resource(childPath, path); } catch (Exception e) { logger.error("feature relative path resolution failed: {}", e.getMessage()); throw e; @@ -164,8 +165,8 @@ private static String readFileAsString(String path, ScenarioContext context) { } public static InputStream getFileStream(String path, ScenarioContext context) { - FileResource fr = resolvePath(path, context); - return getStream(fr.file); + Resource fr = resolvePath(path, context); + return fr.getStream(); } private static InputStream getStream(File file) { @@ -319,7 +320,7 @@ public static void renameFileIfZeroBytes(String fileName) { public static String toRelativeClassPath(File file) { Path path = file.toPath(); - for (Path rootPath : getAllClassPaths()) { + for (Path rootPath : getAllClassPaths(null)) { if (path.startsWith(rootPath)) { Path relativePath = rootPath.relativize(path); return CLASSPATH_COLON + relativePath.toString(); @@ -354,24 +355,26 @@ public static File fromRelativeClassPath(String relativePath) { } } - public static List scanForFeatureFilesOnClassPath() { - return scanForFeatureFiles(true, CLASSPATH_COLON); + public static List scanForFeatureFilesOnClassPath(ClassLoader cl) { + return scanForFeatureFiles(true, CLASSPATH_COLON, cl); } - public static List scanForFeatureFiles(List paths) { - List list = new ArrayList(); + public static List scanForFeatureFiles(List paths, ClassLoader cl) { + List list = new ArrayList(); for (String path : paths) { boolean classpath = isClassPath(path); - list.addAll(scanForFeatureFiles(classpath, path)); + list.addAll(scanForFeatureFiles(classpath, path, cl)); } return list; } - public static List getAllClassPaths() { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); + public static List getAllClassPaths(ClassLoader classLoader) { + if (classLoader == null) { + classLoader = Thread.currentThread().getContextClassLoader(); + } try { List list = new ArrayList(); - Enumeration iterator = cl.getResources(""); + Enumeration iterator = classLoader.getResources(""); while (iterator.hasMoreElements()) { URL url = iterator.nextElement(); list.add(Paths.get(url.toURI())); @@ -382,11 +385,37 @@ public static List getAllClassPaths() { } } - public static List scanForFeatureFiles(boolean classpath, String searchPath) { - List files = new ArrayList(); + private static FileSystem getFileSystem(URI uri) { + try { + return FileSystems.getFileSystem(uri); + } catch (Exception e) { + logger.warn("creating file system for URI: {} - {}", uri, e.getMessage()); + try { + return FileSystems.newFileSystem(uri, Collections.emptyMap()); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + } + + public static List scanForFeatureFiles(boolean classpath, String searchPath, ClassLoader cl) { + List files = new ArrayList(); if (classpath) { searchPath = removePrefix(searchPath); - for (Path rootPath : getAllClassPaths()) { + if (cl != null) { + try { + URL url = cl.getResource(searchPath); + if (url != null && url.toURI().getScheme().equals("jar")) { + FileSystem fileSystem = getFileSystem(url.toURI()); + Path search = fileSystem.getPath(searchPath); + collectFeatureFiles(search, files); + return files; // exit early + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + for (Path rootPath : getAllClassPaths(cl)) { collectFeatureFiles(rootPath, searchPath, files); } } else { @@ -395,7 +424,7 @@ public static List scanForFeatureFiles(boolean classpath, String s return files; } - private static void collectFeatureFiles(Path rootPath, String searchPath, List files) { + private static void collectFeatureFiles(Path rootPath, String searchPath, List files) { boolean classpath = rootPath != null; Path search; if (classpath) { @@ -419,9 +448,25 @@ private static void collectFeatureFiles(Path rootPath, String searchPath, List files) { + Stream stream; + try { + stream = Files.walk(searchPath); + } catch (IOException e) { + throw new RuntimeException(e); + } + for (Iterator paths = stream.iterator(); paths.hasNext();) { + Path path = paths.next(); + if (path.getFileName().toString().endsWith(".feature")) { + Resource resource = new Resource(path, CLASSPATH_COLON + path.toString()); + files.add(resource); + } + } + } } diff --git a/karate-core/src/main/java/com/intuit/karate/IdeUtils.java b/karate-core/src/main/java/com/intuit/karate/IdeUtils.java index eb1f01c4c..7ee037ed2 100644 --- a/karate-core/src/main/java/com/intuit/karate/IdeUtils.java +++ b/karate-core/src/main/java/com/intuit/karate/IdeUtils.java @@ -47,7 +47,7 @@ public class IdeUtils { private static final Pattern COMMAND_NAME = Pattern.compile("--name (.+?\\$)"); - public static void main(String[] args) { + public static void exec(String[] args) { String command = System.getProperty("sun.java.command"); System.out.println("command: " + command); boolean isIntellij = command.contains("org.jetbrains"); diff --git a/karate-core/src/main/java/com/intuit/karate/FileResource.java b/karate-core/src/main/java/com/intuit/karate/Resource.java similarity index 53% rename from karate-core/src/main/java/com/intuit/karate/FileResource.java rename to karate-core/src/main/java/com/intuit/karate/Resource.java index 60b547bf4..fd7dcea2c 100644 --- a/karate-core/src/main/java/com/intuit/karate/FileResource.java +++ b/karate-core/src/main/java/com/intuit/karate/Resource.java @@ -24,19 +24,59 @@ package com.intuit.karate; import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; /** * * @author pthomas3 */ -public class FileResource { +public class Resource { + + private final boolean file; + private final Path path; + private final String relativePath; - public final File file; - public final String relativePath; + public Resource(File file, String relativePath) { + this.file = true; + path = file.toPath(); + this.relativePath = relativePath; + } - public FileResource(File file, String relativePath) { - this.file = file; + public Resource(Path path, String relativePath) { + this.path = path; + file = !path.toUri().getScheme().equals("jar"); this.relativePath = relativePath; } - + + public String getRelativePath() { + return relativePath; + } + + public Path getPath() { + return path; + } + + public InputStream getStream() { + try { + return Files.newInputStream(path); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public String getAsString() { + if (file) { + return FileUtils.toString(path.toFile()); + } else { + return FileUtils.toString(getStream()); + } + } + + @Override + public String toString() { + return relativePath; + } + } 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 cfef224b1..6e43e6243 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 @@ -125,11 +125,7 @@ public static String getFeatureName(Step step) { if (step.getScenario() == null) { return UNKNOWN; } - File file = step.getScenario().getFeature().getFile(); - if (file == null) { - return UNKNOWN; - } - return file.getName(); + return step.getScenario().getFeature().getPath().getFileName().toString(); } public static Result executeStep(Step step, Actions actions) { 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 426d2e5dd..52bddb91f 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,8 +24,9 @@ package com.intuit.karate.core; import com.intuit.karate.FileUtils; +import com.intuit.karate.Resource; import com.intuit.karate.StringUtils; -import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -37,8 +38,7 @@ public class Feature { public static final String KEYWORD = "Feature"; - private final File file; - private final String relativePath; + private final Resource resource; private final String packageQualifiedName; private int line; @@ -53,10 +53,9 @@ public class Feature { private String callTag; private String callName; - public Feature(File file, String relativePath) { - this.file = file; - this.relativePath = relativePath; - this.packageQualifiedName = FileUtils.toPackageQualifiedName(relativePath); + public Feature(Resource resource) { + this.resource = resource; + this.packageQualifiedName = FileUtils.toPackageQualifiedName(resource.getRelativePath()); } public boolean isBackgroundPresent() { @@ -122,8 +121,8 @@ public String getText() { public void initLines() { if (lines == null) { - if (file != null) { - lines = StringUtils.toStringLines(FileUtils.toString(file)); + if (resource != null) { + lines = StringUtils.toStringLines(resource.toString()); } } } @@ -172,14 +171,18 @@ public List getLines() { public void setLines(List lines) { this.lines = lines; - } + } - public File getFile() { - return file; + public Resource getResource() { + return resource; + } + + public Path getPath() { + return resource.getPath(); } public String getRelativePath() { - return relativePath; + return resource.getRelativePath(); } public String getPackageQualifiedName() { diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureBackend.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureBackend.java index 61a68bde6..5338575f2 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureBackend.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureBackend.java @@ -76,7 +76,7 @@ public FeatureBackend(Feature feature, Map vars) { public FeatureBackend(Feature feature, Map vars, boolean ssl) { this.feature = feature; - featureName = feature.getFile().getName(); + featureName = feature.getPath().toFile().getName(); this.ssl = ssl; CallContext callContext = new CallContext(null, false); FeatureContext featureContext = new FeatureContext(feature, null); diff --git a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java index cc28cfcb8..41d4508a7 100644 --- a/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java +++ b/karate-core/src/main/java/com/intuit/karate/core/FeatureExecutionUnit.java @@ -98,8 +98,8 @@ public void submit(Runnable next) { private static ScenarioInfo getScenarioInfo(Scenario scenario, FeatureContext env) { ScenarioInfo info = new ScenarioInfo(); - info.setFeatureDir(env.feature.getFile().getParent()); - info.setFeatureFileName(env.feature.getFile().getName()); + info.setFeatureDir(env.feature.getPath().getParent().toString()); + info.setFeatureFileName(env.feature.getPath().getFileName().toString()); info.setScenarioName(scenario.getName()); info.setScenarioDescription(scenario.getDescription()); info.setScenarioType(scenario.isOutline() ? ScenarioOutline.KEYWORD : Scenario.KEYWORD); 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 83db70dd2..2229c815f 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 @@ -24,6 +24,7 @@ package com.intuit.karate.core; import com.intuit.karate.FileUtils; +import com.intuit.karate.Resource; import com.intuit.karate.StringUtils; import java.io.File; import java.io.FileInputStream; @@ -31,6 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -54,31 +56,29 @@ public class FeatureParser extends KarateParserBaseListener { private final ParserErrorListener errorListener = new ParserErrorListener(); private final Feature feature; - - public static Feature parse(File file) { - return new FeatureParser(file).feature; + + public static Feature parse(File file) { + Resource resource = new Resource(file, file.getPath()); + return new FeatureParser(resource).feature; + } + + public static Feature parse(Resource resource) { + return new FeatureParser(resource).feature; } public static Feature parse(String path) { File file = FileUtils.fromRelativeClassPath(path); - return FeatureParser.parse(file, path); - } - - public static Feature parse(File file, String relativePath) { - return new FeatureParser(file, relativePath).feature; + Resource resource = new Resource(file, path); + return FeatureParser.parse(resource); } public static Feature parseText(Feature old, String text) { - Feature feature = new Feature(old.getFile(), old.getRelativePath()); + Feature feature = new Feature(old.getResource()); 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 { @@ -89,9 +89,13 @@ private static InputStream toStream(File file) { } private FeatureParser(File file, String relativePath) { - this(new Feature(file, relativePath), toStream(file)); + this(new Feature(new Resource(file, relativePath)), toStream(file)); } + private FeatureParser(Resource resource) { + this(new Feature(resource), resource.getStream()); + } + private FeatureParser(Feature feature, InputStream is) { this.feature = feature; CharStream stream; 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 278dc2312..2d09ce014 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 @@ -24,7 +24,7 @@ package com.intuit.karate.cucumber; import com.intuit.karate.CallContext; -import com.intuit.karate.FileResource; +import com.intuit.karate.Resource; import com.intuit.karate.FileUtils; import com.intuit.karate.FeatureContext; import com.intuit.karate.core.Engine; @@ -89,15 +89,15 @@ public static KarateStats parallel(List tags, List paths, int th 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); + List files = FileUtils.scanForFeatureFiles(paths, null); return parallel(tagSelector, files, hook, threadCount, reportDir); } - public static KarateStats parallel(String tagSelector, List resources, int threadCount, String reportDir) { + public static KarateStats parallel(String tagSelector, List resources, int threadCount, String reportDir) { return parallel(tagSelector, resources, null, threadCount, reportDir); } - public static KarateStats parallel(String tagSelector, List resources, ExecutionHook 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() + File.separator + "surefire-reports"; new File(reportDir).mkdirs(); @@ -111,9 +111,9 @@ public static KarateStats parallel(String tagSelector, List resour int count = resources.size(); List> callables = new ArrayList<>(count); for (int i = 0; i < count; i++) { - FileResource resource = resources.get(i); + Resource resource = resources.get(i); int index = i + 1; - Feature feature = FeatureParser.parse(resource.file, resource.relativePath); + Feature feature = FeatureParser.parse(resource); callables.add(() -> { // we are now within a separate thread. the reporter filters logs by self thread String threadName = Thread.currentThread().getName(); 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 b3959914f..1fadd4e50 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 @@ -135,7 +135,7 @@ private void initFileSaveAction(AppSession session, String envString, Stage stag String suggestedName = "noname.feature"; file = chooseFileToSave(stage, "*.feature files", "*.feature", suggestedName); } else { - file = feature.getFile(); + file = feature.getPath().toFile(); } FileUtils.writeToFile(file, feature.getText()); if (needsNameToSave) { diff --git a/karate-core/src/main/java/cucumber/api/cli/Main.java b/karate-core/src/main/java/cucumber/api/cli/Main.java index 2cec861bc..02403052c 100644 --- a/karate-core/src/main/java/cucumber/api/cli/Main.java +++ b/karate-core/src/main/java/cucumber/api/cli/Main.java @@ -33,7 +33,7 @@ public class Main { public static void main(String[] args) { - IdeUtils.main(args); + IdeUtils.exec(args); } } diff --git a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java index 538ea0d07..05daf7493 100755 --- a/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java +++ b/karate-core/src/test/java/com/intuit/karate/FileUtilsTest.java @@ -36,14 +36,15 @@ public void testRenameZeroLengthFile() { @Test public void testScanFile() { String relativePath = "classpath:com/intuit/karate/ui/test.feature"; - List files = FileUtils.scanForFeatureFilesOnClassPath(); + List files = FileUtils.scanForFeatureFilesOnClassPath(null); boolean found = false; - for (FileResource file : files) { - if (file.relativePath.equals(relativePath)) { + for (Resource file : files) { + String foo = file.getRelativePath(); + if (file.getRelativePath().equals(relativePath)) { File tempFile = FileUtils.fromRelativeClassPath(relativePath); - assertEquals(tempFile, file.file); - String temp = FileUtils.toRelativeClassPath(file.file); - assertEquals(temp, file.relativePath); + assertEquals(tempFile, file.getPath().toFile()); + String temp = FileUtils.toRelativeClassPath(file.getPath().toFile()); + assertEquals(temp, file.getRelativePath()); found = true; break; } @@ -54,7 +55,7 @@ public void testScanFile() { @Test public void testScanFilePath() { String relativePath = "classpath:com/intuit/karate/ui"; - List files = FileUtils.scanForFeatureFiles(true, relativePath); + List files = FileUtils.scanForFeatureFiles(true, relativePath, null); assertEquals(2, files.size()); } @@ -65,7 +66,7 @@ public void testRelativePathForClass() { @Test public void testGetAllClasspaths() { - FileUtils.getAllClassPaths(); + FileUtils.getAllClassPaths(null); } } diff --git a/karate-core/src/test/java/com/intuit/karate/core/AllKarateFeaturesTest.java b/karate-core/src/test/java/com/intuit/karate/core/AllKarateFeaturesTest.java index 98f70abfb..ca0eed101 100644 --- a/karate-core/src/test/java/com/intuit/karate/core/AllKarateFeaturesTest.java +++ b/karate-core/src/test/java/com/intuit/karate/core/AllKarateFeaturesTest.java @@ -23,10 +23,11 @@ */ package com.intuit.karate.core; -import com.intuit.karate.FileResource; +import com.intuit.karate.Resource; import com.intuit.karate.FileUtils; import java.util.List; import org.junit.Test; +import static org.junit.Assert.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,10 +41,12 @@ public class AllKarateFeaturesTest { @Test public void testParsingAllFeaturesInKarate() { - List files = FileUtils.scanForFeatureFiles(false, ".."); - for (FileResource file : files) { - logger.debug("parsing: {}", file.relativePath); - FeatureParser.parse(file.file, file.relativePath); + List files = FileUtils.scanForFeatureFiles(false, "..", null); + logger.debug("found files count: {}", files.size()); + assertTrue(files.size() > 500); + for (Resource file : files) { + logger.debug("parsing: {}", file.getRelativePath()); + FeatureParser.parse(file); } } diff --git a/karate-core/src/test/java/com/intuit/karate/cucumber/CucumberUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/cucumber/CucumberUtilsTest.java index 4f752ea5f..dc9ea8dd8 100644 --- a/karate-core/src/test/java/com/intuit/karate/cucumber/CucumberUtilsTest.java +++ b/karate-core/src/test/java/com/intuit/karate/cucumber/CucumberUtilsTest.java @@ -1,6 +1,7 @@ package com.intuit.karate.cucumber; import com.intuit.karate.FileUtils; +import com.intuit.karate.Resource; import com.intuit.karate.core.Background; import com.intuit.karate.core.Feature; import com.intuit.karate.core.FeatureParser; @@ -8,6 +9,7 @@ import com.intuit.karate.core.ScenarioOutline; import com.intuit.karate.core.Step; import java.io.InputStream; +import java.nio.file.Paths; import java.util.List; import org.junit.Test; import static org.junit.Assert.*; @@ -25,7 +27,8 @@ public class CucumberUtilsTest { private Feature parse(String name) { InputStream is = getClass().getResourceAsStream(name); String text = FileUtils.toString(is); - return FeatureParser.parseText(new Feature(null, null), text); + Resource resource = new Resource(Paths.get(""), ""); + return FeatureParser.parseText(new Feature(resource), text); } private void printLines(List lines) { @@ -124,7 +127,8 @@ public void testMultiLineEditTable() { @Test public void testIdentifyingStepWhichIsAnHttpCall() { String text = "Feature:\nScenario:\n* method post"; - Feature feature = FeatureParser.parseText(new Feature(null, null), text); + Resource resource = new Resource(Paths.get(""), ""); + Feature feature = FeatureParser.parseText(new Feature(resource), text); Step step = feature.getSections().get(0).getScenario().getSteps().get(0); logger.debug("step name: '{}'", step.getText()); assertTrue(step.getText().startsWith("method")); diff --git a/karate-core/src/test/resources/karate-test.jar b/karate-core/src/test/resources/karate-test.jar new file mode 100644 index 0000000000000000000000000000000000000000..b9f546b03591ed1884c84fb0d3d4a68217616b3e GIT binary patch literal 2363 zcmb7FTW=dh6h7-~J+<4A8@+HDF0Jhruj3X$ak-f&7A3Z0$yNm7p&IW_?2XpD(R$q| z4?Oe*{s7_^^cg`PpzzR2JO+seBz^=!Ao0L!#hKZ7H#3&{uBPYS$`* z+8eaA;W5MJbk+5CT#xw(Sw?xAO(vBt^G9`BARkv&H`?vBPQOmu%yKGnm+o4&O$VGZ z)8r;)Q{Nqv7TymUTjU26vcexpi`d?syhvu4p+l z&?+i!ezH$L-#|=3;+UkHB5rP8duj`TS`p0(1d8WmmWlz`^%+>P98bcBU%mH36AcSe z90+y(cZkw~>%sw(Z_&xrF!*Fb-=V%YNC z9WE2d!m~Lz2j>Z7-~xe*@Z2eQJ_|2o;YAHHZ(EM#zpFvARNmAewd$H&gR?Em;hpJt zz`Z^j*vOf0xtNYkJRGq;V5a<$HPK+MC37FTa1(LH=!yo*rB7Si><+8i%o$dDJ|5}t zrnJMnA!;rhv#mjT#BJNvV6jv_s;vR(xl_;JO-uNdlQ9b$c`Wr@7HA$`f|v8K0E=08 zB@eH{B@IqXM7ryGwyD9HxVsoYMxA-Fgr*Y0mW*+kR zJ0A!@L6%ky&cYmWgz^oP7Ruy4BpyKWJ4i(c1or@Cb0{655O@aWk)IQJJ3zT8G0?I3 z^f$PLS;RSTU;$T4xJtlsye2-HyWQ*IhM@CEQKo}ps?Cb&=?bH!RHm+11H7=(i)E!s zs>_#u`T{)=bnd7p-pr9FHXl)$o?>6t*pBGS@s5UG9MeIW8tnpFg~WFmwi=KjP2Qeo8l9>M&56ehg=-Su=vND} clazz) throws InitializationError, IOException { String relative = FileUtils.toRelativeClassPath(clazz); features = Collections.singletonList(relative); } - List resources = FileUtils.scanForFeatureFiles(features); + List resources = FileUtils.scanForFeatureFiles(features, clazz.getClassLoader()); children = new ArrayList(resources.size()); - for (FileResource fr : resources) { - Feature feature = FeatureParser.parse(fr.file, fr.relativePath); + for (Resource fr : resources) { + Feature feature = FeatureParser.parse(fr); children.add(feature); } tagSelector = Engine.fromCucumberOptionsTags(tags); @@ -78,7 +78,7 @@ private static Description getScenarioDescription(String featureName, Scenario s } private static String getFeatureName(Feature feature) { - return "[" + feature.getFile().getName() + "]"; + return "[" + feature.getPath().toFile().getName() + "]"; } @Override diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/schema-like.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/schema-like.feature index 6d1315471..c0caf75e6 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/schema-like.feature +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/demos/schema-like.feature @@ -159,3 +159,12 @@ Scenario: pretty print json Scenario: more pretty print * def myJson = { foo: 'bar', baz: [1, 2, 3]} * print 'pretty print:\n' + karate.pretty(myJson) + +Scenario: various ways of checking that a string ends with a number +* def foo = 'hello1' +* match foo == '#regex hello[0-9]+' +* match foo == '#regex .+[0-9]+' +* match foo contains 'hello' +* assert foo.startsWith('hello') +* def isHello = function(s){ return s.startsWith('hello') && karate.match(s, '#regex .+[0-9]+').pass } +* match foo == '#? isHello(_)' diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java new file mode 100644 index 000000000..172a2a769 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/JarLoadingTest.java @@ -0,0 +1,48 @@ +package com.intuit.karate.junit4.files; + +import com.intuit.karate.Resource; +import com.intuit.karate.FileUtils; +import com.intuit.karate.core.Feature; +import com.intuit.karate.core.FeatureParser; +import com.intuit.karate.cucumber.CucumberRunner; +import java.io.File; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import static org.junit.Assert.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author pthomas3 + */ +public class JarLoadingTest { + + private static final Logger logger = LoggerFactory.getLogger(JarLoadingTest.class); + + @Test + public void testRunningFromJarFile() throws Exception { + File jar = new File("../karate-core/src/test/resources/karate-test.jar"); + assertTrue(jar.exists()); + URLClassLoader cl = new URLClassLoader(new URL[]{jar.toURI().toURL()}); + Class main = cl.loadClass("demo.jar1.Main"); + Method meth = main.getMethod("hello"); + Object result = meth.invoke(null); + assertEquals("hello world", result); + List list = FileUtils.scanForFeatureFiles(Collections.singletonList("classpath:demo"), cl); + assertEquals(4, list.size()); + logger.debug("resources: {}", list); + list = FileUtils.scanForFeatureFiles(Collections.singletonList("classpath:demo/jar1/caller.feature"), cl); + assertEquals(1, list.size()); + Resource resource = list.get(0); + Feature feature = FeatureParser.parse(resource); + Map map = CucumberRunner.runFeature(feature, null, false); + assertEquals(true, map.get("success")); + } + +} diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/FileWorkingDirectoryRunner.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/WorkingDirRunner.java similarity index 86% rename from karate-junit4/src/test/java/com/intuit/karate/junit4/files/FileWorkingDirectoryRunner.java rename to karate-junit4/src/test/java/com/intuit/karate/junit4/files/WorkingDirRunner.java index 91478fffa..3ece6fb8e 100644 --- a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/FileWorkingDirectoryRunner.java +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/WorkingDirRunner.java @@ -6,6 +6,6 @@ @RunWith(Karate.class) @CucumberOptions(features = "classpath:com/intuit/karate/junit4/files/working-dir.feature") -public class FileWorkingDirectoryRunner { +public class WorkingDirRunner { } \ No newline at end of file diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called2.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called2.feature new file mode 100644 index 000000000..1a9def51e --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called2.feature @@ -0,0 +1,6 @@ +@ignore +Feature: + +Scenario: +* print 'in called2' +* call read('called3.feature') \ No newline at end of file diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called3.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called3.feature new file mode 100644 index 000000000..221fedecc --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/called3.feature @@ -0,0 +1,6 @@ +@ignore +Feature: + +Scenario: +* print 'in called3' +* def success = true diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/CallerRunner.java b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/CallerRunner.java new file mode 100644 index 000000000..04ba72a14 --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/CallerRunner.java @@ -0,0 +1,15 @@ +package com.intuit.karate.junit4.files.relative; + +import com.intuit.karate.junit4.Karate; +import cucumber.api.CucumberOptions; +import org.junit.runner.RunWith; + +/** + * + * @author pthomas3 + */ +@RunWith(Karate.class) +@CucumberOptions(features = "classpath:com/intuit/karate/junit4/files/relative/caller.feature") +public class CallerRunner { + +} diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/called1.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/called1.feature new file mode 100644 index 000000000..057f524df --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/called1.feature @@ -0,0 +1,6 @@ +@ignore +Feature: + +Scenario: +* print 'in called1' +* call read('../called2.feature') diff --git a/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/caller.feature b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/caller.feature new file mode 100644 index 000000000..de8a2df8b --- /dev/null +++ b/karate-junit4/src/test/java/com/intuit/karate/junit4/files/relative/caller.feature @@ -0,0 +1,7 @@ +Feature: + +Scenario: +* print 'in caller' +* call read('classpath:common.feature') +* call read('called1.feature') +* match success == true diff --git a/karate-junit4/src/test/java/common.feature b/karate-junit4/src/test/java/common.feature new file mode 100644 index 000000000..5182d03ab --- /dev/null +++ b/karate-junit4/src/test/java/common.feature @@ -0,0 +1,5 @@ +@ignore +Feature: + +Scenario: +* print 'in common'