Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions java/.mvn/jvm.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
37 changes: 31 additions & 6 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<parent>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-parent</artifactId>
<version>4.5.0</version>
<version>5.0.0-SNAPSHOT</version>
</parent>

<artifactId>html-formatter</artifactId>
<version>22.0.1-SNAPSHOT</version>
<version>23.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Cucumber HTML Formatter</name>
<description>Renders Cucumber Messages as HTML</description>
Expand Down Expand Up @@ -44,14 +44,22 @@
<type>pom</type>
<scope>import</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-bom</artifactId>
<version>3.27.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>messages</artifactId>
<version>[18.0.0,31.0.0)</version>
<version>[31.0.0-SNAPSHOT,32.0.0)</version>
</dependency>

<dependency>
Expand All @@ -73,9 +81,8 @@
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>3.0</version>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>

Expand All @@ -85,4 +92,22 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.cucumber.htmlformatter;

import org.jspecify.annotations.Nullable;

import java.io.IOException;
import java.io.Writer;
import java.util.Objects;

/**
* Writes json with the forward slash ({@code /}) escaped. Assumes
Expand All @@ -10,10 +13,10 @@
class JsonInHtmlWriter extends Writer {
private static final int BUFFER_SIZE = 1024;
private final Writer delegate;
private char[] escapeBuffer;
private char @Nullable[] escapeBuffer;

JsonInHtmlWriter(Writer delegate) {
this.delegate = delegate;
this.delegate = Objects.requireNonNull(delegate);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.cucumber.htmlformatter;

import io.cucumber.messages.types.Envelope;
import org.jspecify.annotations.Nullable;

import java.io.BufferedReader;
import java.io.BufferedWriter;
Expand Down Expand Up @@ -39,20 +40,6 @@ public final class MessagesToHtmlWriter implements AutoCloseable {
private boolean firstMessageWritten = false;
private boolean streamClosed = false;

@Deprecated
public MessagesToHtmlWriter(OutputStream outputStream, Serializer serializer) throws IOException {
this(
createWriter(outputStream),
requireNonNull(serializer),
() -> createInputStream("Cucumber"),
() -> getResource("icon.url"),
() -> getResource("main.css"),
MessagesToHtmlWriter::createEmptyInputStream,
() -> getResource("main.js"),
MessagesToHtmlWriter::createEmptyInputStream
);
}

private MessagesToHtmlWriter(
OutputStreamWriter writer,
Serializer serializer,
Expand Down Expand Up @@ -88,7 +75,7 @@ private static String readTemplate() {
InputStream resource = getResource("index.mustache.html");
writeResource(writer, resource);
}
return new String(baos.toByteArray(), UTF_8);
return baos.toString(UTF_8);
} catch (IOException e) {
throw new RuntimeException("Could not read resource index.mustache.html", e);
}
Expand All @@ -108,24 +95,14 @@ private static InputStream getResource(String name) {
return resource;
}

private void writePreMessage() throws IOException {
writeTemplateBetween(writer, template, null, "{{title}}");
writeResource(writer, title);
writeTemplateBetween(writer, template, "{{title}}", "{{icon}}");
writeResource(writer, icon);
writeTemplateBetween(writer, template, "{{icon}}", "{{css}}");
writeResource(writer, css);
writeTemplateBetween(writer, template, "{{css}}", "{{custom_css}}");
writeResource(writer, customCss);
writeTemplateBetween(writer, template, "{{custom_css}}", "{{messages}}");
}

private void writePostMessage() throws IOException {
writeTemplateBetween(writer, template, "{{messages}}", "{{script}}");
writeResource(writer, script);
writeTemplateBetween(writer, template, "{{script}}", "{{custom_script}}");
writeResource(writer, customScript);
writeTemplateBetween(writer, template, "{{custom_script}}", null);
/**
* Creates a builder to construct this writer.
*
* @param serializer used to convert messages into json.
* @return a new builder
*/
public static Builder builder(Serializer serializer) {
return new Builder(serializer);
}

/**
Expand Down Expand Up @@ -153,6 +130,18 @@ public void write(Envelope envelope) throws IOException {
serializer.writeValue(jsonInHtmlWriter, envelope);
}

private void writePreMessage() throws IOException {
writeTemplateBetween(writer, template, null, "{{title}}");
writeResource(writer, title);
writeTemplateBetween(writer, template, "{{title}}", "{{icon}}");
writeResource(writer, icon);
writeTemplateBetween(writer, template, "{{icon}}", "{{css}}");
writeResource(writer, css);
writeTemplateBetween(writer, template, "{{css}}", "{{custom_css}}");
writeResource(writer, customCss);
writeTemplateBetween(writer, template, "{{custom_css}}", "{{messages}}");
}

/**
* Closes the stream, flushing it first. Once closed further write()
* invocations will cause an IOException to be thrown. Closing a closed
Expand Down Expand Up @@ -183,7 +172,15 @@ public void close() throws IOException {
}
}

private static void writeTemplateBetween(Writer writer, String template, String begin, String end)
private void writePostMessage() throws IOException {
writeTemplateBetween(writer, template, "{{messages}}", "{{script}}");
writeResource(writer, script);
writeTemplateBetween(writer, template, "{{script}}", "{{custom_script}}");
writeResource(writer, customScript);
writeTemplateBetween(writer, template, "{{custom_script}}", null);
}

private static void writeTemplateBetween(Writer writer, String template, @Nullable String begin, @Nullable String end)
throws IOException {
int beginIndex = begin == null ? 0 : template.indexOf(begin) + begin.length();
int endIndex = end == null ? template.length() : template.indexOf(end);
Expand Down Expand Up @@ -229,16 +226,6 @@ public interface Serializer {

}

/**
* Creates a builder to construct this writer.
*
* @param serializer used to convert messages into json.
* @return a new builder
*/
public static Builder builder(Serializer serializer) {
return new Builder(serializer);
}

public static final class Builder {
private final Serializer serializer;
private Supplier<InputStream> title = () -> createInputStream("Cucumber");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@NullMarked
package io.cucumber.htmlformatter;

import org.jspecify.annotations.NullMarked;
6 changes: 4 additions & 2 deletions java/src/test/java/io/cucumber/htmlformatter/Jackson.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.cucumber.htmlformatter;

import com.fasterxml.jackson.annotation.JsonCreator.Mode;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand All @@ -11,11 +10,14 @@
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_ABSENT;
import static com.fasterxml.jackson.annotation.JsonInclude.Value.construct;

final class Jackson {
public static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
.addModule(new Jdk8Module())
.addModule(new ParameterNamesModule(Mode.PROPERTIES))
.serializationInclusion(Include.NON_ABSENT)
.defaultPropertyInclusion(construct(NON_ABSENT, NON_ABSENT))
.constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)
.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,8 @@ void large_writes_with_odd_boundaries() throws IOException {
Arrays.fill(buffer, 1, buffer.length, '<');
writer.write(buffer);

StringBuilder expected = new StringBuilder();
expected.append("a");
for (int i = 1; i < buffer.length; i++) {
expected.append("\\x3C");
}
assertEquals(expected.toString(), output());
String expected = "a" + "\\x3C".repeat(buffer.length - 1);
assertEquals(expected, output());
}


Expand All @@ -74,11 +70,7 @@ void really_large_writes() throws IOException {
Arrays.fill(buffer, '<');
writer.write(buffer);

StringBuilder expected = new StringBuilder();
for (int i = 0; i < buffer.length; i++) {
expected.append("\\x3C");
}
assertEquals(expected.toString(), output());
assertEquals("\\x3C".repeat(buffer.length), output());
}

@Test
Expand All @@ -90,6 +82,6 @@ void empty_write() throws IOException {

private String output() throws IOException {
writer.flush();
return new String(out.toByteArray(), UTF_8);
return out.toString(UTF_8);
}
}
57 changes: 53 additions & 4 deletions java/src/test/java/io/cucumber/htmlformatter/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,34 @@
import io.cucumber.messages.NdjsonToMessageIterable;
import io.cucumber.messages.NdjsonToMessageIterable.Deserializer;
import io.cucumber.messages.types.Envelope;
import org.jspecify.annotations.NullMarked;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import static io.cucumber.htmlformatter.Jackson.OBJECT_MAPPER;

public final class Main {
private static final Deserializer deserializer = (json) -> OBJECT_MAPPER.readValue(json, Envelope.class);
private static final Deserializer deserializer = json -> OBJECT_MAPPER.readValue(json, Envelope.class);
private static final Serializer serializer = OBJECT_MAPPER::writeValue;

private Main() {
// main class
}

public static void main(String[] args) throws IOException {
InputStream in = System.in;
if (args.length == 1) {
InputStream in;
if (args.length != 1) {
in = new NonClosableInputStream(System.in);
} else {
in = new FileInputStream(args[0]);
}
try (NdjsonToMessageIterable envelopes = new NdjsonToMessageIterable(in, deserializer)) {
MessagesToHtmlWriter.Builder builder = MessagesToHtmlWriter.builder(serializer);
try (MessagesToHtmlWriter htmlWriter = builder.build(System.out)) {
OutputStream out = new NonClosableOutputStream(System.out);
try (MessagesToHtmlWriter htmlWriter = builder.build(out)) {
for (Envelope envelope : envelopes) {
htmlWriter.write(envelope);
}
Expand All @@ -33,4 +42,44 @@ public static void main(String[] args) throws IOException {
System.exit(1);
}
}

@NullMarked
private static class NonClosableInputStream extends InputStream {

private final InputStream delegate;

NonClosableInputStream(InputStream delegate) {
this.delegate = delegate;
}

@Override
public int read() throws IOException {
return delegate.read();
}

@Override
public int read(byte[] b, int off, int len) throws IOException {
return delegate.read(b, off, len);
}
}

@NullMarked
private static class NonClosableOutputStream extends OutputStream {

private final OutputStream delegate;

NonClosableOutputStream(OutputStream delegate) {
this.delegate = delegate;
}

@Override
public void write(int b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}
}
}
Loading