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 0d5739a..4042569 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/CoverageDoclet.java @@ -15,16 +15,10 @@ */ package com.manoelcampos.javadoc.coverage; -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 com.sun.tools.doclets.standard.Standard; - -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.*; /** * A {@link Doclet} that computes coverage of JavaDoc documentation. @@ -42,13 +36,6 @@ * @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"}; - /** * The {@link DataExporter} object to export the coverage report to a file * in a specific format. @@ -57,8 +44,8 @@ public class CoverageDoclet { private final RootDoc rootDoc; /** - * 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 @@ -75,51 +62,12 @@ public static boolean start(final RootDoc rootDoc) { */ public CoverageDoclet(final RootDoc rootDoc) { this.rootDoc = rootDoc; - this.exporter = new HtmlExporter(this); - } + Configuration config = new Configuration(rootDoc.options()); - /** - * 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); - } + JavaDocsStats stats = new JavaDocsStats(rootDoc, config); - /** - * 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); } /** @@ -130,32 +78,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[] getOptionValues(final String[] optionNames) { - for (final String[] optionValues : rootDoc.options()) { - if (isParameter(optionValues[0], optionNames)) { - return optionValues; - } - } - - return new String[]{}; + public static boolean validOptions(final String[][] options, final DocErrorReporter errorReporter) { + return Configuration.areValidOptions(options, errorReporter); } /** @@ -186,44 +121,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/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/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..ae0329d --- /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 IllegalArgumentException("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 91a9e45..32492c4 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/AbstractDataExporter.java @@ -15,13 +15,13 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; +import java.io.*; + import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.manoelcampos.javadoc.coverage.stats.JavaDocsStats; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; +import lombok.NonNull; /** * Abstract class to implement JavaDoc Coverage reports in different formats. @@ -34,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); @@ -52,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()); } /** * 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.getOptionValues(CoverageDoclet.OUTPUT_NAME_OPTION); - return outputNameOption.length > 1 ? outputNameOption[1] : 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 dd12c80..aa84b80 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/exporter/HtmlExporter.java @@ -15,14 +15,14 @@ */ package com.manoelcampos.javadoc.coverage.exporter; -import com.manoelcampos.javadoc.coverage.CoverageDoclet; +import java.util.List; + 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.configuration.Configuration; +import com.manoelcampos.javadoc.coverage.stats.*; import com.sun.javadoc.PackageDoc; -import java.util.List; +import lombok.NonNull; /** * Exports the JavaDoc coverage report to an HTML file. @@ -33,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 1a6147d..ae87500 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,12 @@ */ package com.manoelcampos.javadoc.coverage.stats; +import java.util.*; + import com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; import com.sun.javadoc.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** * Computes statistics about the JavaDocs of a class, inner class, interface or enum * and its members, such as: fields, methods, constructors and annotations. @@ -46,41 +45,46 @@ public class ClassDocStats extends MembersDocStats { private List methodsStats; private List constructorsStats; - public ClassDocStats(final ClassDoc doc) { + public ClassDocStats(final ClassDoc doc, Configuration config) { 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", 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) { + private void processAnnotationsDocsStats(ClassDoc doc, Configuration config) { 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", config); + } else { + annotationsStats = new ClassMembersDocStats(new AnnotationTypeElementDoc[0], "Annotations", config); + } } - 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)); + } } } @Override public long getDocumentedMembers() { - return - Utils.boolToInt(isDocumented()) + + return Utils.boolToInt(isDocumented()) + fieldsStats.getDocumentedMembers() + enumsStats.getDocumentedMembers() + getDocumentedMethodMembers(methodsStats) + @@ -91,16 +95,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(); } /** @@ -111,7 +115,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 311f7e3..07d8428 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassMembersDocStats.java @@ -15,12 +15,13 @@ */ 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 com.manoelcampos.javadoc.coverage.Utils; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; +import com.sun.javadoc.*; + /** * Computes JavaDoc coverage statistics for specific type of members belonging to an owner. * An owner can be a class, interface or enum. @@ -35,17 +36,19 @@ public class ClassMembersDocStats extends MembersDocStats { */ private final Doc[] membersDocs; private final String membersType; + private final Configuration config; /** - * 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 config the configuration of the coverage doclet */ - ClassMembersDocStats(final Doc[] membersDocs, final String membersType) { + ClassMembersDocStats(final Doc[] membersDocs, final String membersType, Configuration config) { this.membersDocs = membersDocs; this.membersType = membersType; + this.config = config; } /** @@ -66,6 +69,7 @@ public long getMembersNumber() { * a class source code) will be computed as undocumented. */ return Arrays.stream(membersDocs) + .filter(this::filterPublicIfNecessary) .map(Doc::position) .filter(Objects::nonNull) .count(); @@ -73,7 +77,26 @@ public long getMembersNumber() { @Override public long getDocumentedMembers() { - return Arrays.stream(membersDocs).map(Doc::getRawCommentText).filter(Utils::isNotStringEmpty).count(); + return Arrays.stream(membersDocs) + .filter(this::filterPublicIfNecessary) + .map(Doc::getRawCommentText) + .filter(Utils::isNotStringEmpty) + .count(); + } + + 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; } @Override @@ -82,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 201e4c4..323dbca 100644 --- a/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java +++ b/src/main/java/com/manoelcampos/javadoc/coverage/stats/ClassesDocStats.java @@ -15,13 +15,10 @@ */ 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.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import com.manoelcampos.javadoc.coverage.configuration.Configuration; +import com.sun.javadoc.ClassDoc; /** * Computes JavaDoc coverage statistics for a list of classes. @@ -35,12 +32,15 @@ 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 config 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, Configuration config) { + classesDocStats = new ArrayList<>(); + for (final ClassDoc doc : classDocs) { + if (!config.computePublicCoverageOnly() || doc.isPublic()) { + classesDocStats.add(new ClassDocStats(doc, config)); + } } } @@ -56,7 +56,10 @@ 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(); } /** @@ -69,9 +72,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 3fd1f6a..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; @@ -40,14 +41,14 @@ 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 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, Configuration config) { this.rootDoc = rootDoc; - this.classesDocStats = new ClassesDocStats(rootDoc.classes()); + this.classesDocStats = new ClassesDocStats(rootDoc.classes(), config); 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..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(); @@ -83,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() {