Skip to content

Add possibility to check only public coverage #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it should be created a new class to define a command line parameter. The class would include the short and long param names and a description. Then, a list of custom parameters could be defined, so that it can be iterated here to avoid changing the method every time a new parameter is included.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that was part of the configuration rework

}

/**
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid NulPointerException, I prefer returning an empty String instead of null. We can use String.isEmpty to check if there is a value for a given parameter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't a problem with the new configuration handling any more

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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());
}

/**
Expand All @@ -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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
*/
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;
import com.manoelcampos.javadoc.coverage.stats.MembersDocStats;
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -46,34 +50,40 @@ public class ClassDocStats extends MembersDocStats {
private List<MethodDocStats> methodsStats;
private List<MethodDocStats> constructorsStats;

public ClassDocStats(final ClassDoc doc) {
public ClassDocStats(final ClassDoc doc, boolean computeOnlyForPublic) {
this.doc = doc;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config parameter should be stored in a config attribute. This way, you avoid passing the config around several methods of the class.

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));
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
}

/**
Expand All @@ -66,14 +74,31 @@ 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();
}

@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<? super Doc> filterPublicIfNecessary() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to make the method return a Predicate. That just makes the method body more complex by requiring it to return a lambda expression. You can just change the method signature to the same signature of the test method into the Predicate functional interface: private boolean filterPublicIfNecessary(Doc m).

Then, where you have filterPublicIfNecessary() you just change to a method reference this::filterPublicIfNecessary

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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));
}
}
}

Expand All @@ -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();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ public long getDocumentedMembers() {
* @return the documented Tag Stream
*/
protected Stream<Tag> 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()));
}

Expand Down