From c117572525a585455f5852a0cc405f7dfbd6764a Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Thu, 18 Jan 2018 08:36:46 +0100 Subject: [PATCH 1/6] first draft for public only changes --- .../javadoc/coverage/CoverageDoclet.java | 33 ++++++++++--- .../javadoc/coverage/VisibilityToCheck.java | 5 ++ .../exporter/AbstractDataExporter.java | 14 +++--- .../coverage/exporter/HtmlExporter.java | 4 +- .../javadoc/coverage/stats/ClassDocStats.java | 46 +++++++++++-------- .../coverage/stats/ClassMembersDocStats.java | 43 +++++++++++++---- .../coverage/stats/ClassesDocStats.java | 23 ++++++---- .../javadoc/coverage/stats/JavaDocsStats.java | 12 +++-- .../coverage/stats/MethodTagsDocStats.java | 3 +- 9 files changed, 123 insertions(+), 60 deletions(-) create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java index 0d5739a..d9f67e0 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java @@ -15,6 +15,12 @@ */ package com.manoelcampos.javadoc.coverage; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + import com.manoelcampos.javadoc.coverage.exporter.ConsoleExporter; import com.manoelcampos.javadoc.coverage.exporter.DataExporter; import com.manoelcampos.javadoc.coverage.exporter.HtmlExporter; @@ -24,8 +30,6 @@ import com.sun.javadoc.RootDoc; import com.sun.tools.doclets.standard.Standard; -import java.io.*; - /** * A {@link Doclet} that computes coverage of JavaDoc documentation. * It is the entry point for the JavaDoc Tool, which can be executed @@ -49,12 +53,20 @@ public class CoverageDoclet { */ public static final String OUTPUT_NAME_OPTION[] = {"-outputName", "-o"}; + /** + * A command line parameter to enable coverage reports only for certain visibility modifiers. The first value is the long version of the + * parameter name and the second is the short one. Values for this option are public (only public stuff is used) and private (everything + * is used) + */ + public static final String COVERAGE_ONLY_FOR_PUBLIC_OPTION[] = { "-modifiers", "-m" }; + /** * The {@link DataExporter} object to export the coverage report to a file * in a specific format. */ private final DataExporter exporter; private final RootDoc rootDoc; + private final boolean computeOnlyForPublicModifier; /** * Starts the actual parsing or JavaDoc documentation and generation of the coverage report. @@ -75,16 +87,23 @@ public static boolean start(final RootDoc rootDoc) { */ public CoverageDoclet(final RootDoc rootDoc) { this.rootDoc = rootDoc; + computeOnlyForPublicModifier = "public".equals(getOptionValue(COVERAGE_ONLY_FOR_PUBLIC_OPTION)); + + // this needs to be the last part as it already accesses some stuff from the doclet this.exporter = new HtmlExporter(this); } + public final boolean computeOnlyForPublicModifier() { + return computeOnlyForPublicModifier; + } + /** * Checks if a given parameter is a valid custom parameter accepted by this doclet. * @param paramName the name of the parameter to check * @return true if it's a valid custom parameter, false otherwise */ private static boolean isCustomParameter(final String paramName) { - return isParameter(paramName, OUTPUT_NAME_OPTION); + return isParameter(paramName, OUTPUT_NAME_OPTION) || isParameter(paramName, COVERAGE_ONLY_FOR_PUBLIC_OPTION); } /** @@ -131,7 +150,7 @@ public static boolean validOptions(final String[][] options, final DocErrorRepor */ public static int optionLength(final String option) { /*The custom outputName parameter accepts one argument. - * The name of the param counts as the one argument.*/ + * The name of the param counts as the one argument.*/ if (isCustomParameter(option)) { return 2; } @@ -148,14 +167,14 @@ public static int optionLength(final String option) { * @return the values associated to the option, where the 0th element is the option itself; * or an empty array if the option is invalid. */ - public String[] getOptionValues(final String[] optionNames) { + public String getOptionValue(final String[] optionNames) { for (final String[] optionValues : rootDoc.options()) { if (isParameter(optionValues[0], optionNames)) { - return optionValues; + return optionValues[1]; } } - return new String[]{}; + return null; } /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java b/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java new file mode 100644 index 0000000..67660b1 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java @@ -0,0 +1,5 @@ +package com.manoelcampos.javadoc.coverage; + +public enum VisibilityToCheck { + PUBLIC, PRIVATE; +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java index 91a9e45..b2bfedf 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java @@ -15,14 +15,14 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; -import com.manoelcampos.javadoc.coverage.Utils; -import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats; - import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; +import com.manoelcampos.javadoc.coverage.CoverageDoclet; +import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats; + /** * Abstract class to implement JavaDoc Coverage reports in different formats. * Each sub-class should implement a specific format such as HTML, CSV, JSON, etc. @@ -58,7 +58,7 @@ protected AbstractDataExporter(final CoverageDoclet doclet, final String fileExt } } - this.stats = new JavaDocsStats(doclet.getRootDoc()); + this.stats = new JavaDocsStats(doclet.getRootDoc(), doclet.computeOnlyForPublicModifier()); } /** @@ -85,8 +85,8 @@ private String generateReportFileName(final String fileExtension) { * @see CoverageDoclet#OUTPUT_NAME_OPTION */ private String getFileNameFromCommandLine() { - final String[] outputNameOption = doclet.getOptionValues(CoverageDoclet.OUTPUT_NAME_OPTION); - return outputNameOption.length > 1 ? outputNameOption[1] : DEFAULT_OUTPUT_NAME; + final String outputNameOption = doclet.getOptionValue(CoverageDoclet.OUTPUT_NAME_OPTION); + return outputNameOption != null ? outputNameOption : DEFAULT_OUTPUT_NAME; } /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java index dd12c80..10c6afe 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java @@ -15,6 +15,8 @@ */ package com.manoelcampos.javadoc.coverage.exporter; +import java.util.List; + import com.manoelcampos.javadoc.coverage.CoverageDoclet; import com.manoelcampos.javadoc.coverage.Utils; import com.manoelcampos.javadoc.coverage.stats.ClassDocStats; @@ -22,8 +24,6 @@ import com.manoelcampos.javadoc.coverage.stats.MethodDocStats; import com.sun.javadoc.PackageDoc; -import java.util.List; - /** * Exports the JavaDoc coverage report to an HTML file. * diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java index 1a6147d..eb343df 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java @@ -15,13 +15,17 @@ */ package com.manoelcampos.javadoc.coverage.stats; -import com.manoelcampos.javadoc.coverage.Utils; -import com.sun.javadoc.*; - import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.manoelcampos.javadoc.coverage.Utils; +import com.sun.javadoc.AnnotationTypeDoc; +import com.sun.javadoc.AnnotationTypeElementDoc; +import com.sun.javadoc.ClassDoc; +import com.sun.javadoc.ConstructorDoc; +import com.sun.javadoc.MethodDoc; + /** * Computes statistics about the JavaDocs of a class, inner class, interface or enum * and its members, such as: fields, methods, constructors and annotations. @@ -46,34 +50,40 @@ public class ClassDocStats extends MembersDocStats { private List methodsStats; private List constructorsStats; - public ClassDocStats(final ClassDoc doc) { + public ClassDocStats(final ClassDoc doc, boolean computeOnlyForPublic) { this.doc = doc; - fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields"); - enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts"); - processMethodsDocsStats(doc); - processConstructorsDocsStats(doc); - processAnnotationsDocsStats(doc); + fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields", computeOnlyForPublic); + enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts", computeOnlyForPublic); + processMethodsDocsStats(doc, computeOnlyForPublic); + processConstructorsDocsStats(doc, computeOnlyForPublic); + processAnnotationsDocsStats(doc, computeOnlyForPublic); } - private void processAnnotationsDocsStats(ClassDoc doc) { + private void processAnnotationsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) { if (doc instanceof AnnotationTypeDoc) { - annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations"); - } else annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations"); + annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations", computeOnlyForPublic); + } else { + annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations", computeOnlyForPublic); + } } - private void processConstructorsDocsStats(ClassDoc doc) { + private void processConstructorsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) { final ConstructorDoc[] constructors = doc.constructors(false); - constructorsStats = new ArrayList<>(constructors.length); + constructorsStats = new ArrayList<>(); for (final ConstructorDoc constructor : constructors) { - constructorsStats.add(new MethodDocStats(constructor)); + if (!computeOnlyForPublic || constructor.isPublic()) { + constructorsStats.add(new MethodDocStats(constructor)); + } } } - private void processMethodsDocsStats(ClassDoc doc) { + private void processMethodsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) { final MethodDoc[] methods = doc.methods(false); - methodsStats = new ArrayList<>(methods.length); + methodsStats = new ArrayList<>(); for (final MethodDoc method : methods) { - methodsStats.add(new MethodDocStats(method)); + if (!computeOnlyForPublic || method.isPublic()) { + methodsStats.add(new MethodDocStats(method)); + } } } diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java index 311f7e3..8a38fbd 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java @@ -15,11 +15,14 @@ */ package com.manoelcampos.javadoc.coverage.stats; -import com.manoelcampos.javadoc.coverage.Utils; -import com.sun.javadoc.Doc; - import java.util.Arrays; import java.util.Objects; +import java.util.function.Predicate; + +import com.manoelcampos.javadoc.coverage.Utils; +import com.sun.javadoc.ClassDoc; +import com.sun.javadoc.Doc; +import com.sun.javadoc.ProgramElementDoc; /** * Computes JavaDoc coverage statistics for specific type of members belonging to an owner. @@ -35,17 +38,22 @@ public class ClassMembersDocStats extends MembersDocStats { */ private final Doc[] membersDocs; private final String membersType; + private final boolean computeOnlyForPublic; /** - * Instantiates an object to compute JavaDoc coverage statistics - * for the members of a class, interface or enum. + * Instantiates an object to compute JavaDoc coverage statistics for the members of a class, interface or enum. * - * @param membersDocs the JavaDoc documentation for the members of the owner. - * @param membersType the type of the members of the owner to compute JavaDoc coverage statistics. + * @param membersDocs + * the JavaDoc documentation for the members of the owner. + * @param membersType + * the type of the members of the owner to compute JavaDoc coverage statistics. + * @param computeOnlyForPublic + * indicates that coverage should only be compute for the public part of the javadoc */ - ClassMembersDocStats(final Doc[] membersDocs, final String membersType) { + ClassMembersDocStats(final Doc[] membersDocs, final String membersType, boolean computeOnlyForPublic) { this.membersDocs = membersDocs; this.membersType = membersType; + this.computeOnlyForPublic = computeOnlyForPublic; } /** @@ -66,6 +74,7 @@ public long getMembersNumber() { * a class source code) will be computed as undocumented. */ return Arrays.stream(membersDocs) + .filter(filterPublicIfNecessary()) .map(Doc::position) .filter(Objects::nonNull) .count(); @@ -73,7 +82,23 @@ public long getMembersNumber() { @Override public long getDocumentedMembers() { - return Arrays.stream(membersDocs).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty).count(); + return Arrays.stream(membersDocs).filter(filterPublicIfNecessary()).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty) + .count(); + } + + private Predicate filterPublicIfNecessary() { + return m -> { + if (computeOnlyForPublic) { + if (m instanceof ClassDoc) { + return !computeOnlyForPublic || ((ClassDoc) m).isPublic(); + } else if (m instanceof ProgramElementDoc) { + return !computeOnlyForPublic || ((ProgramElementDoc) m).isPublic(); + } else { + throw new UnsupportedOperationException("unimplemented for type " + m.getClass()); + } + } + return true; + }; } @Override diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java index 201e4c4..eb7ea5d 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java @@ -15,14 +15,12 @@ */ package com.manoelcampos.javadoc.coverage.stats; -import com.manoelcampos.javadoc.coverage.Utils; -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.Doc; - import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.sun.javadoc.ClassDoc; + /** * Computes JavaDoc coverage statistics for a list of classes. * @@ -35,12 +33,17 @@ public class ClassesDocStats extends MembersDocStats { /** * Instantiates an object to compute JavaDoc coverage statistics for a list of classes. * - * @param docs an array of elements which enables reading the classes' JavaDoc documentation + * @param classDocs + * an array of elements which enables reading the classes' JavaDoc documentation + * @param computeOnlyForPublic + * indicates that coverage should only be compute for the public part of the javadoc */ - public ClassesDocStats(final ClassDoc[] docs){ - classesDocStats = new ArrayList<>(docs.length); - for (final ClassDoc doc : docs) { - classesDocStats.add(new ClassDocStats(doc)); + public ClassesDocStats(final ClassDoc[] classDocs, boolean computeOnlyForPublic) { + classesDocStats = new ArrayList<>(); + for (final ClassDoc doc : classDocs) { + if (!computeOnlyForPublic || doc.isPublic()) { + classesDocStats.add(new ClassDocStats(doc, computeOnlyForPublic)); + } } } @@ -56,7 +59,7 @@ public String getType() { @Override public long getDocumentedMembers() { - return classesDocStats.stream().map(ClassDocStats::getDoc).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty).count(); + return classesDocStats.stream().filter(ClassDocStats::isDocumented).count(); } /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java index 3fd1f6a..83665df 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java @@ -40,14 +40,16 @@ public class JavaDocsStats implements DocStats { private final ClassesDocStats classesDocStats; /** - * Instantiates an object to compute JavaDoc coverage statistics for all Java files - * received by the JavaDoc tool. + * Instantiates an object to compute JavaDoc coverage statistics for all Java files received by the JavaDoc tool. * - * @param rootDoc root element which enables reading JavaDoc documentation + * @param rootDoc + * root element which enables reading JavaDoc documentation + * @param computeOnlyForPublic + * indicates that coverage should only be compute for the public part of the javadoc */ - public JavaDocsStats(final RootDoc rootDoc) { + public JavaDocsStats(final RootDoc rootDoc, boolean computeOnlyForPublic) { this.rootDoc = rootDoc; - this.classesDocStats = new ClassesDocStats(rootDoc.classes()); + this.classesDocStats = new ClassesDocStats(rootDoc.classes(), computeOnlyForPublic); this.packagesDocStats = computePackagesDocsStats(); } diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java index 9146917..d7c5f52 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java @@ -68,8 +68,7 @@ public long getDocumentedMembers() { * @return the documented Tag Stream */ protected Stream getDocumentedTagStream() { - return Arrays.stream(getDoc().tags()) - .filter(tag -> getTagName().equals(tag.name())) + return Arrays.stream(getDoc().tags()).filter(tag -> getTagName().equals(tag.name())) .filter(tag -> Utils.isNotStringEmpty(tag.text())); } From 6393b85d14ee0917294a977039b88d430b3165ac Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Thu, 18 Jan 2018 13:59:22 +0100 Subject: [PATCH 2/6] remove unused enum --- .../com/manoelcampos/javadoc/coverage/VisibilityToCheck.java | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java b/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java deleted file mode 100644 index 67660b1..0000000 --- a/src/main/java/com/manoelcampos/javadoc/coverage/VisibilityToCheck.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.manoelcampos.javadoc.coverage; - -public enum VisibilityToCheck { - PUBLIC, PRIVATE; -} From 7ebf9bd6e1839528ffcf8a302863d0ba9e8298bb Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Sat, 27 Jan 2018 12:04:06 +0100 Subject: [PATCH 3/6] fixing some formatting issues --- .../javadoc/coverage/CoverageDoclet.java | 17 +++--------- .../exporter/AbstractDataExporter.java | 4 +-- .../coverage/exporter/HtmlExporter.java | 4 +-- .../javadoc/coverage/stats/ClassDocStats.java | 26 ++++++++----------- .../coverage/stats/ClassMembersDocStats.java | 24 ++++++++--------- .../coverage/stats/ClassesDocStats.java | 21 +++++++-------- .../javadoc/coverage/stats/JavaDocsStats.java | 6 ++--- .../coverage/stats/MethodTagsDocStats.java | 21 +++++++-------- 8 files changed, 50 insertions(+), 73 deletions(-) diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java index d9f67e0..302b050 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java @@ -15,19 +15,10 @@ */ package com.manoelcampos.javadoc.coverage; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; - -import com.manoelcampos.javadoc.coverage.exporter.ConsoleExporter; -import com.manoelcampos.javadoc.coverage.exporter.DataExporter; -import com.manoelcampos.javadoc.coverage.exporter.HtmlExporter; -import com.sun.javadoc.DocErrorReporter; -import com.sun.javadoc.Doclet; -import com.sun.javadoc.LanguageVersion; -import com.sun.javadoc.RootDoc; +import java.io.*; + +import com.manoelcampos.javadoc.coverage.exporter.*; +import com.sun.javadoc.*; import com.sun.tools.doclets.standard.Standard; /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java index b2bfedf..9ed5ea9 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java @@ -15,9 +15,7 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; +import java.io.*; import com.manoelcampos.javadoc.coverage.CoverageDoclet; import com.manoelcampos.javadoc.coverage.Utils; diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java index 10c6afe..6bdd553 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java @@ -19,9 +19,7 @@ import com.manoelcampos.javadoc.coverage.CoverageDoclet; import com.manoelcampos.javadoc.coverage.Utils; -import com.manoelcampos.javadoc.coverage.stats.ClassDocStats; -import com.manoelcampos.javadoc.coverage.stats.MembersDocStats; -import com.manoelcampos.javadoc.coverage.stats.MethodDocStats; +import com.manoelcampos.javadoc.coverage.stats.*; import com.sun.javadoc.PackageDoc; /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java index eb343df..e2f2c30 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java @@ -15,16 +15,10 @@ */ package com.manoelcampos.javadoc.coverage.stats; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import com.manoelcampos.javadoc.coverage.Utils; -import com.sun.javadoc.AnnotationTypeDoc; -import com.sun.javadoc.AnnotationTypeElementDoc; -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.ConstructorDoc; -import com.sun.javadoc.MethodDoc; +import com.sun.javadoc.*; /** * Computes statistics about the JavaDocs of a class, inner class, interface or enum @@ -89,8 +83,7 @@ private void processMethodsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) @Override public long getDocumentedMembers() { - return - Utils.boolToInt(isDocumented()) + + return Utils.boolToInt(isDocumented()) + fieldsStats.getDocumentedMembers() + enumsStats.getDocumentedMembers() + getDocumentedMethodMembers(methodsStats) + @@ -101,16 +94,16 @@ public long getDocumentedMembers() { @Override public long getMembersNumber() { return CLASS_DOC + - fieldsStats.getMembersNumber() + - enumsStats.getMembersNumber() + + fieldsStats.getMembersNumber() + + enumsStats.getMembersNumber() + getMethodMembers(methodsStats) + getMethodMembers(constructorsStats) + - annotationsStats.getMembersNumber(); + annotationsStats.getMembersNumber(); } private long getDocumentedMethodMembers(final List methodOrConstructor) { return methodOrConstructor.stream().filter(MethodDocStats::isDocumented).count() + - methodOrConstructor.stream().mapToLong(MethodDocStats::getDocumentedMembers).sum(); + methodOrConstructor.stream().mapToLong(MethodDocStats::getDocumentedMembers).sum(); } /** @@ -121,7 +114,10 @@ private long getDocumentedMethodMembers(final List methodOrConst * @see MethodDocStats#getMembersNumber() */ private long getMethodMembers(final List methodOrConstructor) { - return methodOrConstructor.stream().mapToLong(MethodDocStats::getMembersNumber).sum(); + return methodOrConstructor + .stream() + .mapToLong(MethodDocStats::getMembersNumber) + .sum(); } public String getName() { diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java index 8a38fbd..62489d0 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java @@ -20,9 +20,7 @@ import java.util.function.Predicate; import com.manoelcampos.javadoc.coverage.Utils; -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.Doc; -import com.sun.javadoc.ProgramElementDoc; +import com.sun.javadoc.*; /** * Computes JavaDoc coverage statistics for specific type of members belonging to an owner. @@ -43,12 +41,9 @@ public class ClassMembersDocStats extends MembersDocStats { /** * Instantiates an object to compute JavaDoc coverage statistics for the members of a class, interface or enum. * - * @param membersDocs - * the JavaDoc documentation for the members of the owner. - * @param membersType - * the type of the members of the owner to compute JavaDoc coverage statistics. - * @param computeOnlyForPublic - * indicates that coverage should only be compute for the public part of the javadoc + * @param membersDocs the JavaDoc documentation for the members of the owner. + * @param membersType the type of the members of the owner to compute JavaDoc coverage statistics. + * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc */ ClassMembersDocStats(final Doc[] membersDocs, final String membersType, boolean computeOnlyForPublic) { this.membersDocs = membersDocs; @@ -82,7 +77,10 @@ public long getMembersNumber() { @Override public long getDocumentedMembers() { - return Arrays.stream(membersDocs).filter(filterPublicIfNecessary()).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty) + return Arrays.stream(membersDocs) + .filter(filterPublicIfNecessary()) + .map(Doc::getRawCommentText) + .filter(Utils::isNotStringEmpty) .count(); } @@ -107,9 +105,9 @@ public String getType() { } /** - * A set of class members doesn't have documentation, - * only each individual member may have. - * @return + * A set of class members doesn't have documentation, only each individual member may have. + * + * @return always false */ @Override public boolean isDocumented() { diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java index eb7ea5d..c81f8df 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java @@ -15,9 +15,7 @@ */ package com.manoelcampos.javadoc.coverage.stats; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import com.sun.javadoc.ClassDoc; @@ -33,10 +31,8 @@ public class ClassesDocStats extends MembersDocStats { /** * Instantiates an object to compute JavaDoc coverage statistics for a list of classes. * - * @param classDocs - * an array of elements which enables reading the classes' JavaDoc documentation - * @param computeOnlyForPublic - * indicates that coverage should only be compute for the public part of the javadoc + * @param classDocs an array of elements which enables reading the classes' JavaDoc documentation + * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc */ public ClassesDocStats(final ClassDoc[] classDocs, boolean computeOnlyForPublic) { classesDocStats = new ArrayList<>(); @@ -59,7 +55,10 @@ public String getType() { @Override public long getDocumentedMembers() { - return classesDocStats.stream().filter(ClassDocStats::isDocumented).count(); + return classesDocStats + .stream() + .filter(ClassDocStats::isDocumented) + .count(); } /** @@ -72,9 +71,9 @@ public List getClassesList() { } /** - * A set of classes doesn't have documentation, - * only each individual class may have. - * @return + * A set of classes doesn't have documentation, only each individual class may have. + * + * @return always false */ @Override public boolean isDocumented() { diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java index 83665df..ef98496 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java @@ -42,10 +42,8 @@ public class JavaDocsStats implements DocStats { /** * Instantiates an object to compute JavaDoc coverage statistics for all Java files received by the JavaDoc tool. * - * @param rootDoc - * root element which enables reading JavaDoc documentation - * @param computeOnlyForPublic - * indicates that coverage should only be compute for the public part of the javadoc + * @param rootDoc root element which enables reading JavaDoc documentation + * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc */ public JavaDocsStats(final RootDoc rootDoc, boolean computeOnlyForPublic) { this.rootDoc = rootDoc; diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java index d7c5f52..04ef5fb 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/MethodTagsDocStats.java @@ -15,13 +15,13 @@ */ package com.manoelcampos.javadoc.coverage.stats; +import java.util.Arrays; +import java.util.stream.Stream; + import com.manoelcampos.javadoc.coverage.Utils; import com.sun.javadoc.ExecutableMemberDoc; import com.sun.javadoc.Tag; -import java.util.Arrays; -import java.util.stream.Stream; - /** * An abstract class to compute JavaDoc statistics for a set of tags * associated to a method/constructor, such as the {@code @param} and {@code @throws} tags. @@ -50,11 +50,10 @@ public abstract class MethodTagsDocStats extends MembersDocStats { } /** - * Gets the name of the tag associated to this object for which - * JavaDoc coverage statistics will be computed, for instance, - * "param" or "throws" tags. + * Gets the name of the tag associated to this object for which JavaDoc coverage statistics will be computed, for + * instance, "param" or "throws" tags. * - * @return + * @return the tag name */ public abstract String getTagName(); @@ -68,7 +67,8 @@ public long getDocumentedMembers() { * @return the documented Tag Stream */ protected Stream getDocumentedTagStream() { - return Arrays.stream(getDoc().tags()).filter(tag -> getTagName().equals(tag.name())) + return Arrays.stream(getDoc().tags()) + .filter(tag -> getTagName().equals(tag.name())) .filter(tag -> Utils.isNotStringEmpty(tag.text())); } @@ -82,10 +82,9 @@ protected ExecutableMemberDoc getDoc() { } /** - * A set of tags doesn't have documentation. - * Only each individual tag may have. + * A set of tags doesn't have documentation. Only each individual tag may have. * - * @return + * @return always false */ @Override public boolean isDocumented() { From 9556f6a3cd13ecf0a649893f305d0908a18eebe8 Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Sat, 10 Feb 2018 14:28:55 +0100 Subject: [PATCH 4/6] add configuration container --- pom.xml | 6 + .../javadoc/coverage/CoverageDoclet.java | 148 ++---------------- .../coverage/configuration/Configuration.java | 124 +++++++++++++++ .../coverage/configuration/NoValueOption.java | 20 +++ .../coverage/configuration/Option.java | 32 ++++ .../coverage/configuration/StringOption.java | 34 ++++ .../exporter/AbstractDataExporter.java | 74 +++++---- .../coverage/exporter/ConsoleExporter.java | 14 +- .../coverage/exporter/DataExporter.java | 10 -- .../coverage/exporter/HtmlExporter.java | 8 +- .../javadoc/coverage/stats/ClassDocStats.java | 19 +-- .../coverage/stats/ClassMembersDocStats.java | 38 ++--- .../coverage/stats/ClassesDocStats.java | 9 +- .../javadoc/coverage/stats/JavaDocsStats.java | 5 +- 14 files changed, 323 insertions(+), 218 deletions(-) create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java diff --git a/pom.xml b/pom.xml index cb4a35f..c94e6d4 100644 --- a/pom.xml +++ b/pom.xml @@ -174,6 +174,12 @@ system ${java.home}/../lib/tools.jar + + org.projectlombok + lombok + 1.16.20 + provided + diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java index 302b050..10766f7 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java @@ -15,11 +15,10 @@ */ package com.manoelcampos.javadoc.coverage; -import java.io.*; - +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.manoelcampos.javadoc.coverage.exporter.*; +import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats; import com.sun.javadoc.*; -import com.sun.tools.doclets.standard.Standard; /** * A {@link Doclet} that computes coverage of JavaDoc documentation. @@ -37,31 +36,17 @@ * @since 1.0.0 */ public class CoverageDoclet { - /** - * A command line parameter to enable defining the name of the coverage report. - * The first value is the long version of the parameter name and the second - * is the short one. - */ - public static final String OUTPUT_NAME_OPTION[] = {"-outputName", "-o"}; - - /** - * A command line parameter to enable coverage reports only for certain visibility modifiers. The first value is the long version of the - * parameter name and the second is the short one. Values for this option are public (only public stuff is used) and private (everything - * is used) - */ - public static final String COVERAGE_ONLY_FOR_PUBLIC_OPTION[] = { "-modifiers", "-m" }; - /** * The {@link DataExporter} object to export the coverage report to a file * in a specific format. */ private final DataExporter exporter; private final RootDoc rootDoc; - private final boolean computeOnlyForPublicModifier; + private final Configuration config; /** - * Starts the actual parsing or JavaDoc documentation and generation of the coverage report. - * This is the entry point for the JavaDoc tool to start the Doclet. + * Starts the actual parsing or JavaDoc documentation and generation of the coverage report. This is the entry point + * for the JavaDoc tool to start the Doclet. * * @param rootDoc root element which enables reading JavaDoc documentation * @return true if the Doclet was started successfully, false otherwise @@ -78,58 +63,12 @@ public static boolean start(final RootDoc rootDoc) { */ public CoverageDoclet(final RootDoc rootDoc) { this.rootDoc = rootDoc; - computeOnlyForPublicModifier = "public".equals(getOptionValue(COVERAGE_ONLY_FOR_PUBLIC_OPTION)); + this.config = new Configuration(rootDoc.options()); - // this needs to be the last part as it already accesses some stuff from the doclet - this.exporter = new HtmlExporter(this); - } - - public final boolean computeOnlyForPublicModifier() { - return computeOnlyForPublicModifier; - } + JavaDocsStats stats = new JavaDocsStats(rootDoc, config); - /** - * Checks if a given parameter is a valid custom parameter accepted by this doclet. - * @param paramName the name of the parameter to check - * @return true if it's a valid custom parameter, false otherwise - */ - private static boolean isCustomParameter(final String paramName) { - return isParameter(paramName, OUTPUT_NAME_OPTION) || isParameter(paramName, COVERAGE_ONLY_FOR_PUBLIC_OPTION); - } - - /** - * Checks if the name of a given parameter corresponds to either its long or short form. - * - * @param paramName the name of the parameter to check - * @param validNames the list of accepted names for that parameter - * @return true if the given name corresponds to one of the valid names, false otherwise - */ - private static boolean isParameter(final String paramName, final String[] validNames) { - for (String validName : validNames) { - if (validName.equalsIgnoreCase(paramName)) { - return true; - } - } - - return false; - } - - /** - * Validates command line options. - * - * @param options the array of given options - * @param errorReporter an object that allows printing error messages for invalid options - * @return true if the options are valid, false otherwise - * @see Doclet#validOptions(String[][], DocErrorReporter) - */ - public static boolean validOptions(final String[][] options, final DocErrorReporter errorReporter) { - for (final String[] opt : options) { - if (isCustomParameter(opt[0])) { - return true; - } - } - - return Standard.validOptions(options, errorReporter); + // this needs to be the last part as it already accesses some stuff from the doclet + this.exporter = new HtmlExporter(config, stats); } /** @@ -140,32 +79,19 @@ public static boolean validOptions(final String[][] options, final DocErrorRepor * @see Doclet#optionLength(String) */ public static int optionLength(final String option) { - /*The custom outputName parameter accepts one argument. - * The name of the param counts as the one argument.*/ - if (isCustomParameter(option)) { - return 2; - } - - return Standard.optionLength(option); + return Configuration.getOptionLength(option); } /** - * Gets the values associated to a given command line option. + * Checks that all given option are valid * - * @param optionNames an array containing the valid names for the command line option to get its associated values. - * This array may include the long and short versions of the option name, - * for instance {@code {-outputName, -o}}. - * @return the values associated to the option, where the 0th element is the option itself; - * or an empty array if the option is invalid. + * @param options the options to be checked on validity + * @param errorReporter + * @return true if the options are valid + * @see Doclet#validOptions(String[][], DocErrorReporter) */ - public String getOptionValue(final String[] optionNames) { - for (final String[] optionValues : rootDoc.options()) { - if (isParameter(optionValues[0], optionNames)) { - return optionValues[1]; - } - } - - return null; + public static boolean validOptions(final String[][] options, final DocErrorReporter errorReporter) { + return Configuration.areValidOptions(options, errorReporter); } /** @@ -196,44 +122,4 @@ private boolean render() { public RootDoc getRootDoc() { return rootDoc; } - - /** - * Gets a {@link PrintWriter} used by the {@link #exporter} to write - * the coverage report to. - * - * @param file the file to which the coverage report will be saved to - */ - public PrintWriter getWriter(final File file) throws FileNotFoundException { - return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file))); - } - - /** - * Gets a {@link File} object from a given file name. - * - * @param fileName the name of the file to get a {@link File} object. - * @return the {@link File} object - */ - public File getOutputFile(final String fileName) { - final File dir = new File(getOutputDir()); - if (!dir.exists() && !dir.mkdirs()) { - throw new RuntimeException("The directory '" + getOutputDir() + "' was not created due to unknown reason."); - } - - return new File(dir, fileName); - } - - /** - * Gets the output directory passed as a command line argument to javadoc tool. - * - * @return the output directory to export the JavaDocs - */ - private String getOutputDir() { - for (final String[] option : rootDoc.options()) { - if (option.length == 2 && option[0].equals("-d")) { - return Utils.includeTrailingDirSeparator(option[1]); - } - } - - return ""; - } } diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java new file mode 100644 index 0000000..0a22d71 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Configuration.java @@ -0,0 +1,124 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import java.util.*; + +import com.manoelcampos.javadoc.coverage.Utils; +import com.sun.javadoc.DocErrorReporter; +import com.sun.tools.doclets.standard.Standard; + +public class Configuration { + + private static final NoValueOption computePublicCoverageOnly = new NoValueOption("-po", "-publicOnly", + "Indicates if coverage should be computed only for the public parts of a project."); + private static final StringOption coverageFileName = new StringOption("-o", "-outputName", + "Set the filename for the created coverage file. If nothing is given, the default is \"javadoc-coverage\".", + Optional.of("javadoc-coverage")); + + private static final List> ALL_OPTIONS = new ArrayList<>(); + + /** + * Static constructor for initializing the options list + */ + static { + ALL_OPTIONS.add(computePublicCoverageOnly); + ALL_OPTIONS.add(coverageFileName); + } + + /** + * The raw options which need to be parsed to our configuration + */ + private final String[][] rawOptions; + + public Configuration(String[][] rawOptions) { + this.rawOptions = rawOptions; + } + + public boolean computePublicCoverageOnly() { + return isOptionContained(computePublicCoverageOnly); + } + + public String getCoverageFileName() { + if (isOptionContained(coverageFileName)) { + return getOptionValue(coverageFileName); + } + return coverageFileName.getDefaultValue(); + } + + /** + * Gets the output directory passed as a command line argument to javadoc tool. + * + * @return the output directory to export the JavaDocs + */ + public String getOutputDirectory() { + // This is no option of the doclet, but instead of the javadoc tool + // so we don't declare it as an option here directly) + + for (final String[] option : rawOptions) { + if (option.length == 2 && option[0].equals("-d")) { + return Utils.includeTrailingDirSeparator(option[1]); + } + } + + return ""; + } + + private boolean isOptionContained(Option option) { + for (final String[] opt : rawOptions) { + if (option.isOption(opt[0])) { + return true; + } + } + return false; + } + + private T getOptionValue(Option option) { + if (!isOptionContained(option) && !option.hasDefaultValue()) { + throw new IllegalStateException("Option is not contained and has no default value"); + } + + if (!isOptionContained(option)) { + return option.getDefaultValue(); + } + + for (final String[] opt: rawOptions) { + if (option.isOption(opt[0])) { + return option.parseValue(opt); + } + } + + throw new IllegalStateException("no valid option found although it should be there"); + } + + /** + * This method is necessary for validating the doclet parameters, which happens before instantiating the + * CoverageDoclet and the configuration container. + * + * @param option + * @return the length of the option + */ + public static int getOptionLength(final String option) { + Optional> opt = ALL_OPTIONS.stream().filter(o -> o.isOption(option)).findFirst(); + if (opt.isPresent()) { + return opt.get().getLength(); + } + return Standard.optionLength(option); + } + + /** + * This method is necessary for validating the doclet parameters, which happens before instantiating the + * CoverageDoclet and the configuration container. + * + * @param options + * @param errorReporter + * @return indicates if the given options are valid + */ + public static boolean areValidOptions(final String[][] options, final DocErrorReporter errorReporter) { + for (final String[] opt : options) { + if (ALL_OPTIONS.stream().anyMatch(o -> o.isOption(opt[0]))) { + return true; + } + } + + return Standard.validOptions(options, errorReporter); + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java new file mode 100644 index 0000000..f615411 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/NoValueOption.java @@ -0,0 +1,20 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import lombok.NonNull; + +class NoValueOption extends Option { + + public NoValueOption(@NonNull String shortName, @NonNull String longName, @NonNull String description) { + super(shortName, longName, description, 1); + } + + @Override + public Void parseValue(String[] value) { + throw new UnsupportedOperationException("NoValueOption does not have a value."); + } + + @Override + public Void getDefaultValue() { + throw new UnsupportedOperationException("NoValueOption does not have a default value."); + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java new file mode 100644 index 0000000..817f7c5 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/Option.java @@ -0,0 +1,32 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import lombok.*; + +@ToString +@Getter +@AllArgsConstructor +abstract class Option { + @NonNull + private final String shortName; + @NonNull + private final String longName; + @NonNull + private final String description; + private final int length; + + public abstract T parseValue(String[] opt); + + public final boolean isOption(String name) { + return shortName.equals(name) || longName.equals(name); + } + + public boolean hasDefaultValue() { + return false; + } + + public abstract T getDefaultValue(); + + public int getLength() { + return length; + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java new file mode 100644 index 0000000..8967ab3 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java @@ -0,0 +1,34 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import java.util.Optional; + +import lombok.NonNull; + +class StringOption extends Option { + + private final Optional defaultValue; + + public StringOption(@NonNull String shortName, @NonNull String longName, @NonNull String description, + @NonNull Optional defaultValue) { + super(shortName, longName, description, 2); + this.defaultValue = defaultValue; + } + + @Override + public String parseValue(String[] value) { + if (value.length != 2) { + throw new IllegalStateException("Wrong option line passed, string options do only have 2 values"); + } + return value[1]; + } + + @Override + public boolean hasDefaultValue() { + return defaultValue.isPresent(); + } + + @Override + public String getDefaultValue() { + return defaultValue.get(); + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java index 9ed5ea9..32492c4 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java @@ -17,10 +17,12 @@ import java.io.*; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats; +import lombok.NonNull; + /** * Abstract class to implement JavaDoc Coverage reports in different formats. * Each sub-class should implement a specific format such as HTML, CSV, JSON, etc. @@ -32,17 +34,21 @@ public abstract class AbstractDataExporter implements DataExporter { private final JavaDocsStats stats; private final PrintWriter writer; private File file; - private final CoverageDoclet doclet; + private final Configuration config; private final String reportFileName; /** * Instantiates a DataExporter object to generate JavaDoc coverage report. * - * @param doclet the {@link CoverageDoclet} which computes teh JavaDoc coverage statistics. - * @param fileExtension the extension to the report file. If empty, the report will be printed to the standard output. + * @param config the configuration of the doclet + * @param stats the javadoc statistics + * @param fileExtension the extension to the report file. If empty, the report will be printed to the standard + * output. */ - protected AbstractDataExporter(final CoverageDoclet doclet, final String fileExtension) { - this.doclet = doclet; + protected AbstractDataExporter(@NonNull final Configuration config, @NonNull final JavaDocsStats stats, + final String fileExtension) { + this.stats = stats; + this.config = config; if (Utils.isStringEmpty(fileExtension)) { writer = new PrintWriter(System.out); @@ -50,54 +56,54 @@ protected AbstractDataExporter(final CoverageDoclet doclet, final String fileExt } else { this.reportFileName = generateReportFileName(fileExtension); try { - this.writer = doclet.getWriter(file); + this.writer = getWriter(file); } catch (FileNotFoundException e) { throw new RuntimeException(e); } } - - this.stats = new JavaDocsStats(doclet.getRootDoc(), doclet.computeOnlyForPublicModifier()); } /** * Instantiates a DataExporter object that generates JavaDoc coverage report to the standard output. * - * @param doclet the {@link CoverageDoclet} which computes teh JavaDoc coverage statistics. + * @param config the configuration of the doclet + * @param stats the javadoc statistics */ - protected AbstractDataExporter(final CoverageDoclet doclet) { - this(doclet, ""); - } - - private String generateReportFileName(final String fileExtension) { - String fileName = getFileNameFromCommandLine(); - fileName = fileName + fileExtensionToAdd(fileName, fileExtension); - this.file = doclet.getOutputFile(fileName); - return fileName; + protected AbstractDataExporter(@NonNull final Configuration config, @NonNull final JavaDocsStats stats) { + this(config, stats, ""); } /** - * Gets the JavaDoc Coverage Report file name from command line options - * or the default name if no option is given. + * Gets a {@link PrintWriter} used by the {@link #exporter} to write the coverage report to. * - * @return - * @see CoverageDoclet#OUTPUT_NAME_OPTION + * @param file the file to which the coverage report will be saved to */ - private String getFileNameFromCommandLine() { - final String outputNameOption = doclet.getOptionValue(CoverageDoclet.OUTPUT_NAME_OPTION); - return outputNameOption != null ? outputNameOption : DEFAULT_OUTPUT_NAME; + private PrintWriter getWriter(final File file) throws FileNotFoundException { + return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file))); + } + + private String generateReportFileName(final String fileExtension) { + String fileName = config.getCoverageFileName(); + if (Utils.getFileExtension(fileName).isEmpty()) { + fileName += getFileExtensionStartingWithDot(fileExtension); + } + this.file = getOutputFile(fileName); + return fileName; } /** - * Gets the extension to add to a given file if it doesn't have one. + * Gets a {@link File} object for the output file * - * @param fileName the file name to try getting and extension to add - * @param defaultFileExtension the default file extension to return if the file doesn't have one - * @return the file extension to add to the file it it doesn't have one or an empty string - * if it already has. + * @return the {@link File} object */ - private String fileExtensionToAdd(final String fileName, final String defaultFileExtension) { - return Utils.getFileExtension(fileName).isEmpty() ? - getFileExtensionStartingWithDot(defaultFileExtension) : ""; + private File getOutputFile(String fileName) { + String outputDirectory = config.getOutputDirectory(); + final File dir = new File(outputDirectory); + if (!dir.exists() && !dir.mkdirs()) { + throw new RuntimeException("The directory '" + outputDirectory + "' was not created due to unknown reason."); + } + + return new File(dir, fileName); } /** diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java index 1f60fc3..eaf9804 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/ConsoleExporter.java @@ -15,13 +15,15 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; +import java.io.PrintWriter; +import java.util.List; + import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.manoelcampos.javadoc.coverage.stats.*; import com.sun.javadoc.PackageDoc; -import java.io.PrintWriter; -import java.util.List; +import lombok.NonNull; /** * Prints the JavaDoc coverage report to the console (standard output). @@ -31,8 +33,8 @@ */ public class ConsoleExporter extends AbstractDataExporter { - public ConsoleExporter(final CoverageDoclet doclet) { - super(doclet); + public ConsoleExporter(@NonNull Configuration config, @NonNull JavaDocsStats stats) { + super(config, stats); } @Override @@ -124,7 +126,7 @@ private void exportMembersDocStats(final PrintWriter writer, final MembersDocSta } final String format = (Utils.isStringEmpty(memberTypeFormat) ? "\t\t%-20s" : memberTypeFormat) + - " %6d Undocumented: %6d Documented: %6d (%.2f%%) \n"; + " %6d Undocumented: %6d Documented: %6d (%.2f%%) \n"; writer.printf(format, membersDocStats.getType()+":", membersDocStats.getMembersNumber(), membersDocStats.getUndocumentedMembers(), diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java index 4100b24..264ac32 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/DataExporter.java @@ -15,8 +15,6 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; - /** * An interface to implement JavaDoc Coverage reports in different formats such as HTML, CSV, JSON, etc. * @@ -24,14 +22,6 @@ * @since 1.0.0 */ public interface DataExporter { - /** - * The name to be used as default for the JavaDoc Coverage report if - * a specific name is not given. - * - * @see CoverageDoclet#OUTPUT_NAME_OPTION - */ - String DEFAULT_OUTPUT_NAME = "javadoc-coverage"; - /** * Gets the actual name to be used for the JavaDoc Coverage Report, * whether the default or given one. diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java index 6bdd553..aa84b80 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java @@ -17,11 +17,13 @@ import java.util.List; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.manoelcampos.javadoc.coverage.stats.*; import com.sun.javadoc.PackageDoc; +import lombok.NonNull; + /** * Exports the JavaDoc coverage report to an HTML file. * @@ -31,8 +33,8 @@ public class HtmlExporter extends AbstractDataExporter { public static final String COLUMNS = "%s%s%s%s%s%s%.2f%%\n"; - public HtmlExporter(final CoverageDoclet doclet) { - super(doclet, ".html"); + public HtmlExporter(@NonNull final Configuration config, @NonNull JavaDocsStats stats) { + super(config, stats, ".html"); } @Override diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java index e2f2c30..ae87500 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassDocStats.java @@ -18,6 +18,7 @@ import java.util.*; import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.sun.javadoc.*; /** @@ -44,20 +45,20 @@ public class ClassDocStats extends MembersDocStats { private List methodsStats; private List constructorsStats; - public ClassDocStats(final ClassDoc doc, boolean computeOnlyForPublic) { + public ClassDocStats(final ClassDoc doc, Configuration config) { this.doc = doc; - fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields", computeOnlyForPublic); - enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts", computeOnlyForPublic); - processMethodsDocsStats(doc, computeOnlyForPublic); - processConstructorsDocsStats(doc, computeOnlyForPublic); - processAnnotationsDocsStats(doc, computeOnlyForPublic); + fieldsStats = new ClassMembersDocStats(doc.fields(false), "Fields", config); + enumsStats = new ClassMembersDocStats(doc.enumConstants(), "Enum Consts", config); + processMethodsDocsStats(doc, config.computePublicCoverageOnly()); + processConstructorsDocsStats(doc, config.computePublicCoverageOnly()); + processAnnotationsDocsStats(doc, config); } - private void processAnnotationsDocsStats(ClassDoc doc, boolean computeOnlyForPublic) { + private void processAnnotationsDocsStats(ClassDoc doc, Configuration config) { if (doc instanceof AnnotationTypeDoc) { - annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations", computeOnlyForPublic); + annotationsStats = new ClassMembersDocStats(((AnnotationTypeDoc) doc).elements(), "Annotations", config); } else { - annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations", computeOnlyForPublic); + annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations", config); } } diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java index 62489d0..07d8428 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java @@ -17,9 +17,9 @@ import java.util.Arrays; import java.util.Objects; -import java.util.function.Predicate; import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.sun.javadoc.*; /** @@ -36,19 +36,19 @@ public class ClassMembersDocStats extends MembersDocStats { */ private final Doc[] membersDocs; private final String membersType; - private final boolean computeOnlyForPublic; + private final Configuration config; /** * Instantiates an object to compute JavaDoc coverage statistics for the members of a class, interface or enum. * * @param membersDocs the JavaDoc documentation for the members of the owner. * @param membersType the type of the members of the owner to compute JavaDoc coverage statistics. - * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc + * @param config the configuration of the coverage doclet */ - ClassMembersDocStats(final Doc[] membersDocs, final String membersType, boolean computeOnlyForPublic) { + ClassMembersDocStats(final Doc[] membersDocs, final String membersType, Configuration config) { this.membersDocs = membersDocs; this.membersType = membersType; - this.computeOnlyForPublic = computeOnlyForPublic; + this.config = config; } /** @@ -69,7 +69,7 @@ public long getMembersNumber() { * a class source code) will be computed as undocumented. */ return Arrays.stream(membersDocs) - .filter(filterPublicIfNecessary()) + .filter(this::filterPublicIfNecessary) .map(Doc::position) .filter(Objects::nonNull) .count(); @@ -78,25 +78,25 @@ public long getMembersNumber() { @Override public long getDocumentedMembers() { return Arrays.stream(membersDocs) - .filter(filterPublicIfNecessary()) + .filter(this::filterPublicIfNecessary) .map(Doc::getRawCommentText) .filter(Utils::isNotStringEmpty) .count(); } - private Predicate filterPublicIfNecessary() { - return m -> { - if (computeOnlyForPublic) { - if (m instanceof ClassDoc) { - return !computeOnlyForPublic || ((ClassDoc) m).isPublic(); - } else if (m instanceof ProgramElementDoc) { - return !computeOnlyForPublic || ((ProgramElementDoc) m).isPublic(); - } else { - throw new UnsupportedOperationException("unimplemented for type " + m.getClass()); - } + private boolean filterPublicIfNecessary(Doc m) { + boolean computeOnlyForPublic = config.computePublicCoverageOnly(); + + if (computeOnlyForPublic) { + if (m instanceof ClassDoc) { + return !computeOnlyForPublic || ((ClassDoc) m).isPublic(); + } else if (m instanceof ProgramElementDoc) { + return !computeOnlyForPublic || ((ProgramElementDoc) m).isPublic(); + } else { + throw new UnsupportedOperationException("unimplemented for type " + m.getClass()); } - return true; - }; + } + return true; } @Override diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java index c81f8df..323dbca 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java @@ -17,6 +17,7 @@ import java.util.*; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.sun.javadoc.ClassDoc; /** @@ -32,13 +33,13 @@ public class ClassesDocStats extends MembersDocStats { * Instantiates an object to compute JavaDoc coverage statistics for a list of classes. * * @param classDocs an array of elements which enables reading the classes' JavaDoc documentation - * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc + * @param config indicates that coverage should only be compute for the public part of the javadoc */ - public ClassesDocStats(final ClassDoc[] classDocs, boolean computeOnlyForPublic) { + public ClassesDocStats(final ClassDoc[] classDocs, Configuration config) { classesDocStats = new ArrayList<>(); for (final ClassDoc doc : classDocs) { - if (!computeOnlyForPublic || doc.isPublic()) { - classesDocStats.add(new ClassDocStats(doc, computeOnlyForPublic)); + if (!config.computePublicCoverageOnly() || doc.isPublic()) { + classesDocStats.add(new ClassDocStats(doc, config)); } } } diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java index ef98496..c2ee3e4 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/JavaDocsStats.java @@ -16,6 +16,7 @@ package com.manoelcampos.javadoc.coverage.stats; import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.RootDoc; @@ -45,9 +46,9 @@ public class JavaDocsStats implements DocStats { * @param rootDoc root element which enables reading JavaDoc documentation * @param computeOnlyForPublic indicates that coverage should only be compute for the public part of the javadoc */ - public JavaDocsStats(final RootDoc rootDoc, boolean computeOnlyForPublic) { + public JavaDocsStats(final RootDoc rootDoc, Configuration config) { this.rootDoc = rootDoc; - this.classesDocStats = new ClassesDocStats(rootDoc.classes(), computeOnlyForPublic); + this.classesDocStats = new ClassesDocStats(rootDoc.classes(), config); this.packagesDocStats = computePackagesDocsStats(); } From 0d0c7d25c9542f71dfc028dc5e830da1a6c0a8ea Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Sat, 10 Feb 2018 14:50:32 +0100 Subject: [PATCH 5/6] make variable local --- .../java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java index 10766f7..4042569 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java @@ -42,7 +42,6 @@ public class CoverageDoclet { */ private final DataExporter exporter; private final RootDoc rootDoc; - private final Configuration config; /** * Starts the actual parsing or JavaDoc documentation and generation of the coverage report. This is the entry point @@ -63,7 +62,7 @@ public static boolean start(final RootDoc rootDoc) { */ public CoverageDoclet(final RootDoc rootDoc) { this.rootDoc = rootDoc; - this.config = new Configuration(rootDoc.options()); + Configuration config = new Configuration(rootDoc.options()); JavaDocsStats stats = new JavaDocsStats(rootDoc, config); From 68fea802c0356514ffd295c0c43a8f1f363ff1ff Mon Sep 17 00:00:00 2001 From: Thomas Stieglmaier Date: Sat, 17 Feb 2018 11:44:09 +0100 Subject: [PATCH 6/6] adding an option for minimal coverage limits --- .../configuration/CoverageLimits.java | 40 +++++++++++++++++++ .../configuration/CoverageLimitsOption.java | 35 ++++++++++++++++ .../coverage/configuration/StringOption.java | 2 +- 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimits.java create mode 100644 src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimitsOption.java diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimits.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimits.java new file mode 100644 index 0000000..d530810 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimits.java @@ -0,0 +1,40 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class CoverageLimits { + + private static final int PACKAGE_INDEX = 1; + private static final int INTERFACE_INDEX = 2; + private static final int CLASS_INDEX = 3; + private static final int METHOD_INDEX = 4; + + private final double minPackageCoverage; + private final double minInterfaceCoverage; + private final double minClassCoverage; + private final double minMethodCoverage; + + public static CoverageLimits noLimits() { + return new CoverageLimits(0,0,0,0); + } + + public static CoverageLimits fromOptionsArray(String[] arr) { + double packageCov = safeParse(arr, PACKAGE_INDEX, "package"); + double interfaceCov = safeParse(arr, INTERFACE_INDEX, "interface"); + double classCov = safeParse(arr, CLASS_INDEX, "class"); + double methodCov = safeParse(arr, METHOD_INDEX, "method"); + + return new CoverageLimits(packageCov, interfaceCov, classCov, methodCov); + } + + private static double safeParse(String[] arr, int index, String exceptionMessagePrefix) { + try { + return Double.parseDouble(arr[index]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(exceptionMessagePrefix + " min coverage number was not a double: " + arr[index]); + } + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimitsOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimitsOption.java new file mode 100644 index 0000000..895f828 --- /dev/null +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/CoverageLimitsOption.java @@ -0,0 +1,35 @@ +package com.manoelcampos.javadoc.coverage.configuration; + +import java.util.Optional; + +import lombok.NonNull; + +class CoverageLimitsOption extends Option { + + private final Optional defaultValue; + + public CoverageLimitsOption(@NonNull String shortName, @NonNull String longName, @NonNull String description, + @NonNull Optional defaultValue) { + super(shortName, longName, description, 2); + this.defaultValue = defaultValue; + } + + @Override + public CoverageLimits parseValue(String[] value) { + if (value.length != 5) { + throw new IllegalArgumentException( + "Wrong option line passed, min coverage options do have exactly 5 values"); + } + return CoverageLimits.fromOptionsArray(value); + } + + @Override + public boolean hasDefaultValue() { + return defaultValue.isPresent(); + } + + @Override + public CoverageLimits getDefaultValue() { + return defaultValue.get(); + } +} diff --git a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java index 8967ab3..ae0329d 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/configuration/StringOption.java @@ -17,7 +17,7 @@ public StringOption(@NonNull String shortName, @NonNull String longName, @NonNul @Override public String parseValue(String[] value) { if (value.length != 2) { - throw new IllegalStateException("Wrong option line passed, string options do only have 2 values"); + throw new IllegalArgumentException("Wrong option line passed, string options do only have 2 values"); } return value[1]; }