diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java b/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java index b9679863f..7aabb793c 100644 --- a/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationEntry.java @@ -33,9 +33,10 @@ package net.fortuna.ical4j.validate; +import java.util.Comparator; import java.util.Objects; -public class ValidationEntry { +public class ValidationEntry implements Comparable { public enum Severity { ERROR, WARNING, INFO @@ -92,4 +93,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(message, severity, context); } + + @Override + public int compareTo(ValidationEntry o) { + return Comparator.comparing(ValidationEntry::getContext) + .thenComparing(ValidationEntry::getSeverity) + .thenComparing(ValidationEntry::getMessage) + .compare(this, o); + } } diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationReport.java b/src/main/java/net/fortuna/ical4j/validate/ValidationReport.java new file mode 100644 index 000000000..f73f4be18 --- /dev/null +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationReport.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022, Ben Fortuna + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * o Neither the name of Ben Fortuna nor the names of any other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.fortuna.ical4j.validate; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; + +/** + * Generate a report from a {@link ValidationResult}. + */ +public class ValidationReport { + + public enum Format { + HTML, TEXT + } + + private final Format format; + + public ValidationReport() { + this(Format.HTML); + } + + public ValidationReport(Format format) { + this.format = format; + } + + public void output(ValidationResult result, OutputStream out) throws IOException { + output(result, new OutputStreamWriter(out, StandardCharsets.UTF_8)); + } + + public void output(ValidationResult result, Writer out) throws IOException { + switch (format) { + case HTML: outputHtml(result, out); break; + case TEXT: outputText(result, out); break; + } + } + + private void outputHtml(ValidationResult result, Writer out) throws IOException { + for (ValidationEntry entry : result.getEntries()) { + out.write(String.format("

%s: %s - %s

\n", entry.getContext(), entry.getSeverity(), entry.getMessage())); + } + } + + private void outputText(ValidationResult result, Writer out) throws IOException { + for (ValidationEntry entry : result.getEntries()) { + out.write(String.format("%s: %s - %s\n", entry.getContext(), entry.getSeverity(), entry.getMessage())); + } + } +} diff --git a/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java b/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java index 9ca164d55..07153de09 100644 --- a/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java +++ b/src/main/java/net/fortuna/ical4j/validate/ValidationResult.java @@ -49,7 +49,7 @@ public ValidationResult(ValidationEntry...entries) { } public ValidationResult(Collection entries) { - this.entries = new HashSet<>(entries); + this.entries = new TreeSet<>(entries); } public Set getEntries() { @@ -62,7 +62,7 @@ public boolean hasErrors() { public ValidationResult merge(ValidationResult result) { if (!result.getEntries().isEmpty()) { - Set merged = new HashSet<>(entries); + Set merged = new TreeSet<>(entries); merged.addAll(result.getEntries()); return new ValidationResult(merged); } else { diff --git a/src/test/groovy/net/fortuna/ical4j/validate/ValidationReportTest.groovy b/src/test/groovy/net/fortuna/ical4j/validate/ValidationReportTest.groovy new file mode 100644 index 000000000..fefead1f6 --- /dev/null +++ b/src/test/groovy/net/fortuna/ical4j/validate/ValidationReportTest.groovy @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022, Ben Fortuna + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * o Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * o Neither the name of Ben Fortuna nor the names of any other contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.fortuna.ical4j.validate + +import spock.lang.Specification + +import static net.fortuna.ical4j.validate.ValidationReport.Format.HTML +import static net.fortuna.ical4j.validate.ValidationReport.Format.TEXT + +class ValidationReportTest extends Specification { + + def 'generate empty text format report'() { + given: 'a validation result' + ValidationResult result = [] + + when: 'a report is generated' + StringWriter writer = [] + new ValidationReport(TEXT).output(result, writer) + + then: 'output matches expected' + writer as String == '' + } + + def 'generate text format report'() { + given: 'a validation result' + ValidationResult result = [] + result.entries << new ValidationEntry('Missing mandatory properties', ValidationEntry.Severity.ERROR, + 'VCALENDAR') + + when: 'a report is generated' + StringWriter writer = [] + new ValidationReport(TEXT).output(result, writer) + + then: 'output matches expected' + writer as String == 'VCALENDAR: ERROR - Missing mandatory properties\n' + } + + def 'generate multiline text format report'() { + given: 'a validation result' + ValidationResult result = [] + result.entries << new ValidationEntry('Missing mandatory properties', ValidationEntry.Severity.ERROR, + 'VCALENDAR') + result.entries << new ValidationEntry('Invalid parameter', ValidationEntry.Severity.WARNING, + 'DTSTART') + + when: 'a report is generated' + StringWriter writer = [] + new ValidationReport(TEXT).output(result, writer) + + then: 'output matches expected' + writer as String == 'DTSTART: WARNING - Invalid parameter\nVCALENDAR: ERROR - Missing mandatory properties\n' + } + + def 'generate multiline html format report'() { + given: 'a validation result' + ValidationResult result = [] + result.entries << new ValidationEntry('Missing mandatory properties', ValidationEntry.Severity.ERROR, + 'VCALENDAR') + result.entries << new ValidationEntry('Invalid parameter', ValidationEntry.Severity.WARNING, + 'DTSTART') + + when: 'a report is generated' + StringWriter writer = [] + new ValidationReport(HTML).output(result, writer) + + then: 'output matches expected' + writer as String == '

DTSTART: WARNING - Invalid parameter

\n

VCALENDAR: ERROR - Missing mandatory properties

\n' + } +}