diff --git a/justify/src/main/java/org/leadpony/justify/api/JsonValidatingException.java b/justify/src/main/java/org/leadpony/justify/api/JsonValidatingException.java index 297b9010..615a7a7d 100644 --- a/justify/src/main/java/org/leadpony/justify/api/JsonValidatingException.java +++ b/justify/src/main/java/org/leadpony/justify/api/JsonValidatingException.java @@ -16,8 +16,11 @@ package org.leadpony.justify.api; +import java.io.PrintStream; +import java.io.PrintWriter; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import javax.json.stream.JsonLocation; @@ -69,6 +72,30 @@ public String getMessage() { .collect(Collectors.joining("\n")); } + /** + * Prints the problems to the specified print stream. + * + * @param stream the print stream to output. + * @throws NullPointerException if the specified {@code stream} is {@code null}. + * @since 1.1 + */ + public void printProblems(PrintStream stream) { + Objects.requireNonNull(stream, "stream must not be null."); + problems.stream().forEach(stream::println); + } + + /** + * Prints the problems to the specified print writer. + * + * @param writer the print writer to output. + * @throws NullPointerException if the specified {@code writer} is {@code null}. + * @since 1.1 + */ + public void printProblems(PrintWriter writer) { + Objects.requireNonNull(writer, "writer must not be null."); + problems.stream().forEach(writer::println); + } + private static JsonLocation extractFirstLocation(List problems) { if (problems.isEmpty()) { return null; diff --git a/justify/src/main/java/org/leadpony/justify/api/Problem.java b/justify/src/main/java/org/leadpony/justify/api/Problem.java index fb97bbf1..cc624628 100644 --- a/justify/src/main/java/org/leadpony/justify/api/Problem.java +++ b/justify/src/main/java/org/leadpony/justify/api/Problem.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.function.Consumer; import javax.json.stream.JsonLocation; @@ -67,6 +68,29 @@ default String getContextualMessage() { */ String getContextualMessage(Locale locale); + /** + * Prints this problem to the specified consumer. + * + * @param lineConsumer the consumer of printed lines. + * @throws NullPointerException if the specified {@code lineConsumer} is + * {@code null}. + * @since 1.1 + */ + default void print(Consumer lineConsumer) { + print(lineConsumer, Locale.getDefault()); + } + + /** + * Prints this problem to the specified consumer. + * + * @param lineConsumer the consumer of printed lines. + * @param locale the locale for which the message will be localized. + * @throws NullPointerException if any of the specified parameters is + * {@code null}. + * @since 1.1 + */ + void print(Consumer lineConsumer, Locale locale); + /** * Returns the location where this problem is found in the input source. * diff --git a/justify/src/main/java/org/leadpony/justify/internal/problem/ProblemBuilder.java b/justify/src/main/java/org/leadpony/justify/internal/problem/ProblemBuilder.java index b761414f..4fc6efcb 100644 --- a/justify/src/main/java/org/leadpony/justify/internal/problem/ProblemBuilder.java +++ b/justify/src/main/java/org/leadpony/justify/internal/problem/ProblemBuilder.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.function.Consumer; import javax.json.stream.JsonLocation; @@ -196,6 +197,16 @@ public String getContextualMessage(Locale locale) { return ProblemRenderer.DEFAULT_RENDERER.render(this, locale); } + /** + * {@inheritDoc} + */ + @Override + public void print(Consumer lineConsumer, Locale locale) { + requireNonNull(lineConsumer, "lineConsumer"); + requireNonNull(locale, "locale"); + ProblemRenderer.DEFAULT_RENDERER.render(this, locale, lineConsumer); + } + /** * {@inheritDoc} */ diff --git a/justify/src/test/java/org/leadpony/justify/api/JsonValidatingExceptionTest.java b/justify/src/test/java/org/leadpony/justify/api/JsonValidatingExceptionTest.java index c0f7b76e..41608802 100644 --- a/justify/src/test/java/org/leadpony/justify/api/JsonValidatingExceptionTest.java +++ b/justify/src/test/java/org/leadpony/justify/api/JsonValidatingExceptionTest.java @@ -16,7 +16,12 @@ package org.leadpony.justify.api; import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; import java.io.StringReader; +import java.io.StringWriter; import java.util.logging.Logger; import javax.json.JsonReader; import javax.json.JsonValue; @@ -97,12 +102,44 @@ public void getMessageShouldReturnMessageFromAllProblems(InstanceExceptionTestCa @ParameterizedTest @JsonSource("jsonvalidatingexceptiontest-schema.json") - public void getLocalizedMessageShouldReturnMessageFromAllProblems(ExceptionTestCase test) { + public void printProblemsShouldOutputToPrintStreamAsExpected(ExceptionTestCase test) { + JsonValidatingException thrown = catchJsonValidatingException(test.schema); + + assertThat(thrown).isNotNull(); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + thrown.printProblems(new PrintStream(stream)); + String message = stream.toString(); + LOG.info(message); + + assertThat(message.split("\n")).hasSize(test.lines); + } + + @ParameterizedTest + @JsonSource("jsonvalidatingexceptiontest-instance.json") + public void printProblemsShouldOutputToPrintStreamAsExpected(InstanceExceptionTestCase test) { + JsonValidatingException thrown = catchJsonValidatingException(test.schema, test.data); + + assertThat(thrown).isNotNull(); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + thrown.printProblems(new PrintStream(stream)); + String message = stream.toString(); + LOG.info(message); + + assertThat(message.split("\n")).hasSize(test.lines); + } + + @ParameterizedTest + @JsonSource("jsonvalidatingexceptiontest-schema.json") + public void printProblemsShouldOutputToPrintWriterAsExpected(ExceptionTestCase test) { JsonValidatingException thrown = catchJsonValidatingException(test.schema); assertThat(thrown).isNotNull(); - String message = thrown.getLocalizedMessage(); + StringWriter writer = new StringWriter(); + thrown.printProblems(new PrintWriter(writer)); + String message = writer.toString(); LOG.info(message); assertThat(message.split("\n")).hasSize(test.lines); @@ -110,12 +147,14 @@ public void getLocalizedMessageShouldReturnMessageFromAllProblems(ExceptionTestC @ParameterizedTest @JsonSource("jsonvalidatingexceptiontest-instance.json") - public void getLocalizedMessageShouldReturnMessageFromAllProblems(InstanceExceptionTestCase test) { + public void printProblemsShouldOutputToPrintWriterAsExpected(InstanceExceptionTestCase test) { JsonValidatingException thrown = catchJsonValidatingException(test.schema, test.data); assertThat(thrown).isNotNull(); - String message = thrown.getLocalizedMessage(); + StringWriter writer = new StringWriter(); + thrown.printProblems(new PrintWriter(writer)); + String message = writer.toString(); LOG.info(message); assertThat(message.split("\n")).hasSize(test.lines); diff --git a/justify/src/test/java/org/leadpony/justify/api/ProblemPrinterTest.java b/justify/src/test/java/org/leadpony/justify/api/ProblemPrinterTest.java index 7cd64919..320cc9b7 100644 --- a/justify/src/test/java/org/leadpony/justify/api/ProblemPrinterTest.java +++ b/justify/src/test/java/org/leadpony/justify/api/ProblemPrinterTest.java @@ -22,6 +22,8 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.function.Consumer; + import javax.json.stream.JsonLocation; import org.junit.jupiter.api.Test; @@ -154,6 +156,11 @@ public String getContextualMessage(Locale locale) { throw new UnsupportedOperationException(); } + @Override + public void print(Consumer lineConsumer, Locale locae) { + throw new UnsupportedOperationException(); + } + @Override public JsonLocation getLocation() { return location; diff --git a/justify/src/test/java/org/leadpony/justify/api/ProblemTest.java b/justify/src/test/java/org/leadpony/justify/api/ProblemTest.java index b5ddda6c..55bdae92 100644 --- a/justify/src/test/java/org/leadpony/justify/api/ProblemTest.java +++ b/justify/src/test/java/org/leadpony/justify/api/ProblemTest.java @@ -21,11 +21,15 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.function.Consumer; import javax.json.JsonReader; +import javax.json.JsonValue; import javax.json.stream.JsonLocation; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.leadpony.justify.test.helper.JsonSource; /** * A test class for testing the {@link Problem} implementation. @@ -138,4 +142,45 @@ public void isResolvableShouldReturnFalse() { assertThat(actual).isFalse(); } + + /** + * @author leadpony + */ + public static class ProblemTestCase { + public JsonValue schema; + public JsonValue data; + public int lines; + } + + @ParameterizedTest + @JsonSource("problemtest-message.json") + public void getContextualMessageShouldReturnMessageOfExpectedLines(ProblemTestCase test) { + Problem problem = createProblem(test); + String message = problem.getContextualMessage(Locale.ROOT); + print(message); + String[] lines = message.split("\n", -1); + assertThat(lines.length).isEqualTo(test.lines); + } + + @ParameterizedTest + @JsonSource("problemtest-message.json") + public void printShouldOutputMessageAsExpected(ProblemTestCase test) { + Problem problem = createProblem(test); + StringBuilder builder = new StringBuilder(); + Consumer consumer = line -> { + if (builder.length() > 0) { + builder.append('\n'); + } + builder.append(line); + }; + problem.print(consumer, Locale.ROOT); + String message = builder.toString(); + print(message); + String[] lines = message.split("\n", -1); + assertThat(lines.length).isEqualTo(test.lines); + } + + private static Problem createProblem(ProblemTestCase test) { + return createProblem(test.schema.toString(), test.data.toString()); + } } diff --git a/justify/src/test/resources/org/leadpony/justify/api/problemtest-message.json b/justify/src/test/resources/org/leadpony/justify/api/problemtest-message.json new file mode 100644 index 00000000..5a39f952 --- /dev/null +++ b/justify/src/test/resources/org/leadpony/justify/api/problemtest-message.json @@ -0,0 +1,31 @@ +[ + { + "schema": { + "properties": { + "foo": { + "type": "string" + } + } + }, + "data": { + "foo": 42 + }, + "lines": 1 + }, + { + "schema": { + "anyOf": [ + { + "required": ["foo"] + }, + { + "required": ["bar"] + } + ] + }, + "data": { + "baz": 42 + }, + "lines": 3 + } +] \ No newline at end of file