diff --git a/pom.xml b/pom.xml
index fcd70f51c..8ce474b68 100644
--- a/pom.xml
+++ b/pom.xml
@@ -81,6 +81,10 @@ SOFTWARE.
https://github.com/yegor256/cactoos
+
+ src/test/test-lib
+ ${project.build.directory}/${project.artifactId}-test-lib-${project.version}.jar
+
org.takes
@@ -144,6 +148,10 @@ SOFTWARE.
8
75
500
+
+ ${testLibJarPath}
+
+ true
@@ -172,6 +180,59 @@ SOFTWARE.
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+ org.cactoos
+ ${project.artifactId}-test-lib
+ ${project.version}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ make-test-lib
+ initialize
+
+ single
+
+
+ ${project.artifactId}-test-lib-${project.version}
+
+ ${testLibPath}/assembly.xml
+
+ false
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+
+
+ make-test-lib
+ initialize
+
+ install-file
+
+
+ ${testLibJarPath}
+ org.cactoos
+ ${project.artifactId}-test-lib
+ ${project.version}
+ jar
+
+
+
+
org.jacoco
jacoco-maven-plugin
diff --git a/src/main/java/org/cactoos/io/ResourceOf.java b/src/main/java/org/cactoos/io/ResourceOf.java
index e5af53e72..8a2c0c908 100644
--- a/src/main/java/org/cactoos/io/ResourceOf.java
+++ b/src/main/java/org/cactoos/io/ResourceOf.java
@@ -25,6 +25,12 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
import org.cactoos.Func;
import org.cactoos.Input;
import org.cactoos.Text;
@@ -225,10 +231,18 @@ public InputStream stream() throws Exception {
"The \"classloader\" is NULL, which is not allowed"
);
}
- InputStream input = this.loader.getResourceAsStream(
- this.path.asString()
- );
- if (input == null) {
+ final InputStream input;
+ final String pth = this.path.asString();
+ final URL resource = this.loader.getResource(pth);
+ if (pth.endsWith("/")
+ && resource != null
+ && "jar".equals(resource.getProtocol())
+ ) {
+ input = new JarDirectoryFileNameStream(resource, pth)
+ .files();
+ } else if (resource != null) {
+ input = resource.openStream();
+ } else {
if (this.fallback == null) {
throw new IllegalArgumentException(
"The \"fallback\" is NULL, which is not allowed"
@@ -240,4 +254,68 @@ public InputStream stream() throws Exception {
}
return input;
}
+
+ /**
+ * Class for creating a stream of file names from a directory to a jar.
+ *
+ * @since 0.56.2
+ */
+ private static final class JarDirectoryFileNameStream {
+
+ /**
+ * URL of the jar file.
+ */
+ private final URL url;
+
+ /**
+ * Path to the directory in the jar file.
+ */
+ private final String path;
+
+ /**
+ * Ctor.
+ *
+ * @param jarurl URL of the jar file.
+ * @param pth The directory for which we want to get a list of files.
+ */
+ JarDirectoryFileNameStream(final URL jarurl, final String pth) {
+ this.url = jarurl;
+ this.path = pth;
+ }
+
+ /**
+ * Create InputStream of file names from directory to jar.
+ *
+ * @return Stream with file names.
+ * @throws Exception If something goes wrong
+ */
+ public InputStream files() throws Exception {
+ try (JarFile jar = new JarFile(this.extract())) {
+ return new InputStreamOf(
+ jar
+ .stream()
+ .map(JarEntry::getName)
+ .filter(
+ name -> !this.path.equals(name)
+ && name.lastIndexOf(this.path) >= 0
+ )
+ .map(name -> name.substring(this.path.length()))
+ .collect(Collectors.joining("\n"))
+ .getBytes(StandardCharsets.UTF_8)
+ );
+ }
+ }
+
+ /**
+ * Extracts the path to a jar file from a URL.
+ *
+ * @return Path to jar file.
+ * @throws URISyntaxException If this URL cannot be converted to a URI.
+ */
+ private String extract() throws URISyntaxException {
+ final String fullpath = this.url.toURI().getSchemeSpecificPart();
+ final int idx = fullpath.indexOf("!/");
+ return fullpath.substring("file:".length(), idx);
+ }
+ }
}
diff --git a/src/test/java/org/cactoos/io/ResourceOfTest.java b/src/test/java/org/cactoos/io/ResourceOfTest.java
index 9bd2d29f4..33092f81c 100644
--- a/src/test/java/org/cactoos/io/ResourceOfTest.java
+++ b/src/test/java/org/cactoos/io/ResourceOfTest.java
@@ -28,11 +28,13 @@
import org.cactoos.Text;
import org.cactoos.bytes.BytesOf;
import org.cactoos.text.FormattedText;
+import org.cactoos.text.Split;
import org.cactoos.text.TextOf;
import org.hamcrest.core.IsEqual;
import org.junit.jupiter.api.Test;
import org.llorllale.cactoos.matchers.Assertion;
import org.llorllale.cactoos.matchers.EndsWith;
+import org.llorllale.cactoos.matchers.HasValues;
import org.llorllale.cactoos.matchers.StartsWith;
import org.llorllale.cactoos.matchers.Throws;
@@ -42,7 +44,7 @@
* @since 0.1
* @checkstyle JavadocMethodCheck (500 lines)
*/
-@SuppressWarnings("PMD.JUnitTestsShouldIncludeAssert")
+@SuppressWarnings({"PMD.JUnitTestsShouldIncludeAssert", "PMD.TooManyMethods"})
final class ResourceOfTest {
@Test
@@ -113,6 +115,66 @@ void throwsWhenResourceIsAbsent() {
).affirm();
}
+ @Test
+ void readTextFromJar() {
+ new Assertion<>(
+ "Can't to read file from jar",
+ new TextOf(
+ new BytesOf(
+ new ResourceOf(
+ "org/cactoos/io/small-text-file.txt",
+ "the replacement"
+ )
+ )
+ ),
+ new EndsWith("parent directory.")
+ ).affirm();
+ }
+
+ @Test
+ void readDirectoryFromJar() {
+ new Assertion<>(
+ "Unable to read file names from jar directory",
+ new Split(
+ new TextOf(
+ new BytesOf(
+ new ResourceOf(
+ "org/cactoos/io/dir/",
+ "the replacement"
+ )
+ )
+ ),
+ new TextOf("\\n")
+ ),
+ new HasValues<>(
+ new TextOf("second-text-file.txt"),
+ new TextOf("small-file-in-dir.txt")
+ )
+ ).affirm();
+ }
+
+ @Test
+ void readDirectory() {
+ new Assertion<>(
+ "Unable to read file names from directory",
+ new Split(
+ new TextOf(
+ new BytesOf(
+ new ResourceOf(
+ "org/cactoos/",
+ "the replacement"
+ )
+ )
+ ),
+ new TextOf("\\n")
+ ),
+ new HasValues<>(
+ new TextOf("digest-calculation.txt"),
+ new TextOf("small-text.txt")
+ )
+ ).affirm();
+ }
+
@Test
void acceptsTextAsResourceName() {
new Assertion<>(
diff --git a/src/test/test-lib/assembly.xml b/src/test/test-lib/assembly.xml
new file mode 100644
index 000000000..5aab736e0
--- /dev/null
+++ b/src/test/test-lib/assembly.xml
@@ -0,0 +1,42 @@
+
+
+
+ test-lib
+
+ jar
+
+ false
+
+
+ ${project.basedir}/${testLibPath}
+ /
+
+ org/cactoos/io/small-text-file.txt
+ org/cactoos/io/dir/second-text-file.txt
+ org/cactoos/io/dir/small-file-in-dir.txt
+
+
+
+
diff --git a/src/test/test-lib/org/cactoos/io/dir/second-text-file.txt b/src/test/test-lib/org/cactoos/io/dir/second-text-file.txt
new file mode 100644
index 000000000..e77d8b257
--- /dev/null
+++ b/src/test/test-lib/org/cactoos/io/dir/second-text-file.txt
@@ -0,0 +1 @@
+Second text file.
\ No newline at end of file
diff --git a/src/test/test-lib/org/cactoos/io/dir/small-file-in-dir.txt b/src/test/test-lib/org/cactoos/io/dir/small-file-in-dir.txt
new file mode 100644
index 000000000..d63be22f2
--- /dev/null
+++ b/src/test/test-lib/org/cactoos/io/dir/small-file-in-dir.txt
@@ -0,0 +1 @@
+Small file in the directory.
\ No newline at end of file
diff --git a/src/test/test-lib/org/cactoos/io/small-text-file.txt b/src/test/test-lib/org/cactoos/io/small-text-file.txt
new file mode 100644
index 000000000..61ef2bac6
--- /dev/null
+++ b/src/test/test-lib/org/cactoos/io/small-text-file.txt
@@ -0,0 +1 @@
+Small file in the parent directory.
\ No newline at end of file