diff --git a/CHANGELOG.md b/CHANGELOG.md index a303632..ca9f198 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## JaCoCoverage Change Log +### Version 1.5.0.20150116.2200 (2015-01-16) +* GitHub #10 add NetBeans Module projects support, provided by __Graeme Ingleby__. + ### Version 1.4.0.20141122.2340 (2014-11-22) * GitHub #24 add Java Web/EE/EJB/EAR projects support. diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index e52050a..58ebc0d 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -1,37 +1,37 @@ -## JaCoCoverage Documentation - -### What Is JaCoCoverage -The JaCoCoverage Plugin is a Netbeans plugin that enhances the existing NetBeans functionality with new code coverage features. In other words, you can launch your program or test it and JaCoCoverage will provide you coverage information by highlighting your source code files and providing various types of reports (currently, textual and HTML). This way, you can easily know what piece of code has been executed or not. - -### How It Works -The JaCoCoverage Plugin is based on JaCoCo: a library created by the [EclEmma team](http://www.eclemma.org/jacoco/). This library is able to generate coverage data when you launch a Java program. -More precsisely, JaCoCoverage uses the JaCoCo Java Agent to enable coverage collections (i.e. a JaCoCo Java Agent is attached to your program). -When your program terminates, JaCoCo generates coverage data and JaCoCoverage assures the coverage information integration in your NetBeans IDE. -JaCoCo and JaCoCoverage support Java 7 and are also tested with Java 6. It may work with Java 5 too. The EclEmma team is currently working on Java 8 support. - -### Media -NetBeans Java editor showing highlighted code. You can see covered, partially covered and not covered code, and annotations in the left margin: - -![Screenshot](http://netbeanscolors.org/files/jacococoverage_editor.png) - -A context menu is enabled for supported projects. It allows you to run and test your programs with JaCoCoverage: - -![Screenshot](http://netbeanscolors.org/files/jacococoverage_menu.png) - -JaCoCoverage is configurable: - -![Screenshot](http://netbeanscolors.org/files/jacococoverage_options.png) - -A short textual coverage report: - -![Screenshot](http://netbeanscolors.org/files/jacococoverage_consolereport.png) - -A complete HTML coverage report: - -![Screenshot](http://netbeanscolors.org/files/jacococoverage_htmlreport.png) - -### Author -* Jonathan Lermitage () - -### License -[WTFPL](http://www.wtfpl.net) License. In other words, you can do what you want: this project is entirely OpenSource, Free and Gratis. +## JaCoCoverage Documentation + +### What Is JaCoCoverage +The JaCoCoverage Plugin is a Netbeans plugin that enhances the existing NetBeans functionality with new code coverage features. In other words, you can launch your program or test it and JaCoCoverage will provide you coverage information by highlighting your source code files and providing various types of reports (currently, textual and HTML). This way, you can easily know what piece of code has been executed or not. + +### How It Works +The JaCoCoverage Plugin is based on JaCoCo: a library created by the [EclEmma team](http://www.eclemma.org/jacoco/). This library is able to generate coverage data when you launch a Java program. +More precsisely, JaCoCoverage uses the JaCoCo Java Agent to enable coverage collections (i.e. a JaCoCo Java Agent is attached to your program). +When your program terminates, JaCoCo generates coverage data and JaCoCoverage assures the coverage information integration in your NetBeans IDE. +JaCoCo and JaCoCoverage support Java 7 and 8 and are also tested with Java 6. It may work with Java 5 too. + +### Media +NetBeans Java editor showing highlighted code. You can see covered, partially covered and not covered code, and annotations in the left margin: + +![Screenshot](http://netbeanscolors.org/files/jacococoverage_editor.png) + +A context menu is enabled for supported projects. It allows you to run and test your programs with JaCoCoverage: + +![Screenshot](http://netbeanscolors.org/files/jacococoverage_menu.png) + +JaCoCoverage is configurable: + +![Screenshot](http://netbeanscolors.org/files/jacococoverage_options.png) + +A short textual coverage report: + +![Screenshot](http://netbeanscolors.org/files/jacococoverage_consolereport.png) + +A complete HTML coverage report: + +![Screenshot](http://netbeanscolors.org/files/jacococoverage_htmlreport.png) + +### Author +* Jonathan Lermitage () + +### License +[WTFPL](http://www.wtfpl.net) License. In other words, you can do what you want: this project is entirely OpenSource, Free and Gratis. diff --git a/README.md b/README.md index 98fb58e..7785277 100644 --- a/README.md +++ b/README.md @@ -29,5 +29,8 @@ For details on previous and current versions, please check the [Changelog](https ### Author * Jonathan Lermitage () +### Contributor +* Graeme Ingleby - provided NetBeans Module support + ### License [WTFPL](http://www.wtfpl.net) License. In other words, you can do what you want: this project is entirely OpenSource, Free and Gratis. diff --git a/tikione-jacocoexec-analyzer/manifest.mf b/tikione-jacocoexec-analyzer/manifest.mf index 0007f73..cba6dd5 100644 --- a/tikione-jacocoexec-analyzer/manifest.mf +++ b/tikione-jacocoexec-analyzer/manifest.mf @@ -1,6 +1,6 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: false -OpenIDE-Module: fr.tikione.jacocoexec.analyzer/1 -OpenIDE-Module-Localizing-Bundle: fr/tikione/jacocoexec/analyzer/Bundle.properties -OpenIDE-Module-Specification-Version: 1.3.3.20130929.1404 - +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: false +OpenIDE-Module: fr.tikione.jacocoexec.analyzer/1 +OpenIDE-Module-Localizing-Bundle: fr/tikione/jacocoexec/analyzer/Bundle.properties +OpenIDE-Module-Specification-Version: 1.5.0.20150116.2200 + diff --git a/tikione-jacocoexec-analyzer/src/fr/tikione/jacocoexec/analyzer/JacocoNBModuleReportGenerator.java b/tikione-jacocoexec-analyzer/src/fr/tikione/jacocoexec/analyzer/JacocoNBModuleReportGenerator.java new file mode 100644 index 0000000..9a23024 --- /dev/null +++ b/tikione-jacocoexec-analyzer/src/fr/tikione/jacocoexec/analyzer/JacocoNBModuleReportGenerator.java @@ -0,0 +1,69 @@ +package fr.tikione.jacocoexec.analyzer; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.tools.ExecFileLoader; +import org.jacoco.report.DirectorySourceFileLocator; +import org.jacoco.report.FileMultiReportOutput; +import org.jacoco.report.IReportGroupVisitor; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.MultiSourceFileLocator; +import org.jacoco.report.html.HTMLFormatter; +import org.jacoco.report.xml.XMLFormatter; + +/** + * @author Graeme Ingleby + */ +public class JacocoNBModuleReportGenerator { + + private static final String DEF_ENCODING = "UTF-8"; + + private final IReportVisitor visitor; + private final IReportGroupVisitor groupVisitor; + private final File executionDataFile; + private final ExecFileLoader execFileLoader; + + public JacocoNBModuleReportGenerator(File executationDataFile, File reportdir, boolean xmlReport) throws IOException { + this.executionDataFile = executationDataFile; + execFileLoader = new ExecFileLoader(); + execFileLoader.load(executionDataFile); + + if (xmlReport) { + XMLFormatter xmlformatter = new XMLFormatter(); + xmlformatter.setOutputEncoding(DEF_ENCODING); + visitor = xmlformatter.createVisitor(new FileOutputStream(reportdir)); + } else { + HTMLFormatter htmlFormater = new HTMLFormatter(); + visitor = htmlFormater.createVisitor(new FileMultiReportOutput(reportdir)); + } + visitor.visitInfo(execFileLoader.getSessionInfoStore().getInfos(), execFileLoader.getExecutionDataStore().getContents()); + groupVisitor = visitor.visitGroup("JaCoCo Coverage Report"); + } + + public void processNBModule(String projectName, List classDirectories, List sourceDirectories) throws IOException { + CoverageBuilder coverageBuilder = new CoverageBuilder(); + Analyzer analyzer = new Analyzer(execFileLoader.getExecutionDataStore(), coverageBuilder); + + for (String classDirectory : classDirectories) { + analyzer.analyzeAll(new File(classDirectory)); + } + + IBundleCoverage bundleCoverage = coverageBuilder.getBundle(projectName); + + MultiSourceFileLocator sourceLocator = new MultiSourceFileLocator(4); + for (String sourceDirectory : sourceDirectories) { + sourceLocator.add(new DirectorySourceFileLocator(new File(sourceDirectory), DEF_ENCODING, 4)); + } + + groupVisitor.visitBundle(bundleCoverage, sourceLocator); + } + + public void end() throws IOException { + visitor.visitEnd(); + } +} diff --git a/tikione-jacocoverage-plugin/manifest.mf b/tikione-jacocoverage-plugin/manifest.mf index e72b604..f9fa9da 100644 --- a/tikione-jacocoverage-plugin/manifest.mf +++ b/tikione-jacocoverage-plugin/manifest.mf @@ -2,5 +2,5 @@ Manifest-Version: 1.0 OpenIDE-Module: fr.tikione.jacocoverage.plugin/1 OpenIDE-Module-Layer: fr/tikione/jacocoverage/plugin/layer.xml OpenIDE-Module-Localizing-Bundle: fr/tikione/jacocoverage/plugin/Bundle.properties -OpenIDE-Module-Specification-Version: 1.4.0.20141122.2340 +OpenIDE-Module-Specification-Version: 1.5.0.20150116.2200 OpenIDE-Module-Needs: org.openide.filesystems.FileUtil.toFileObject diff --git a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ActionJacocoOnAntTaskJ2SE.java b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ActionJacocoOnAntTaskJ2SE.java index 46b670b..a055fe1 100644 --- a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ActionJacocoOnAntTaskJ2SE.java +++ b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ActionJacocoOnAntTaskJ2SE.java @@ -46,6 +46,7 @@ *
See DevFaqAddGlobalContext for global context and project tweaks. * * @author Jonathan Lermitage + * @author Graeme Ingleby */ @SuppressWarnings("CloneableImplementsClone") public abstract class ActionJacocoOnAntTaskJ2SE @@ -56,6 +57,8 @@ public abstract class ActionJacocoOnAntTaskJ2SE private static final Logger LOGGER = Logger.getLogger(ActionJacocoOnAntTaskJ2SE.class.getName()); + private static final String DEFAULT_EXCLUDES = "com.sun.*:org.apache.*:org.netbeans.*:junit.*:sun.*:org.openide.*:org.junit.*"; + /** The Ant task to launch. */ private final String antTask; @@ -134,9 +137,17 @@ private void runJacocoJavaagent(final Project project) } } - antTaskJavaagentParam = "\"" + NBUtils.getJacocoAgentJar().getAbsolutePath() - + "\"=includes=*:" + NBUtils.getProjectJavaPackagesAsStr(project, prjProps, ":", ".*") - + ",destfile=\"" + binreport.getAbsolutePath() + "\"" + exclude.toString(); + // GWI patch: If NetBeans Module Project - use different JavaAgent settings + final boolean isNBModule = Utils.isProjectSupported(NBUtils.getSelectedProject(), NBProjectTypeEnum.NBMODULE); + if (isNBModule) { + String excludes = prjProps.getProperty("jacoco.excludes"); + antTaskJavaagentParam = "\"" + NBUtils.getJacocoAgentJar().getAbsolutePath() + + "\"=destfile=\"" + binreport.getAbsolutePath() + "\"" + (excludes == null ? "" : ",excludes=" + excludes); + } else { + antTaskJavaagentParam = "\"" + NBUtils.getJacocoAgentJar().getAbsolutePath() + + "\"=includes=*:" + NBUtils.getProjectJavaPackagesAsStr(project, prjProps, ":", ".*") + + ",destfile=\"" + binreport.getAbsolutePath() + "\"" + exclude.toString(); + } FileObject scriptToExecute = project.getProjectDirectory().getFileObject("build", "xml"); if (scriptToExecute == null) { // Fix for GitHub #16. @@ -157,7 +168,12 @@ private void runJacocoJavaagent(final Project project) String prjJvmArgs; final boolean isJ2EE = Utils.isProjectSupported(NBUtils.getSelectedProject(), NBProjectTypeEnum.J2EE, NBProjectTypeEnum.J2EE_EAR, NBProjectTypeEnum.J2EE_EJB, NBProjectTypeEnum.J2EE_WEB); - if (isJ2EE) { + + // GWI patch: If NetBeans Module Project - use different JavaAgent settings + if (isNBModule) { + prjJvmArgs = Utils.getProperty(prjProps, "test.run.args"); + targetProps.put("test.run.args", prjJvmArgs + " -javaagent:" + antTaskJavaagentParam); + } else if (isJ2EE) { prjJvmArgs = Utils.getProperty(prjProps, "runmain.jvmargs"); targetProps.put("runmain.jvmargs", prjJvmArgs + " -javaagent:" + antTaskJavaagentParam); } else { @@ -194,7 +210,14 @@ public void run() { classDir = new File(prjDir + Utils.getProperty(prjProps, "build.classes.dir") + File.separator); } File srcDir = new File(prjDir + Utils.getProperty(prjProps, "src.dir") + File.separator); - JaCoCoReportAnalyzer.toXmlReport(binreport, xmlreport, classDir, srcDir); + + // GWI patch: If NBModule create a different XML Report + if (isNBModule) { + NBJaCoCoExtension.toXmlReport(binreport, xmlreport, project); + } else { + JaCoCoReportAnalyzer.toXmlReport(binreport, xmlreport, classDir, srcDir); + } + final Map coverageData = JaCoCoXmlReportParser.getCoverageData(xmlreport); new File(prjDir + Globals.JACOCOVERAGE_DATA_DIR).mkdirs(); @@ -211,7 +234,15 @@ public void run() { } if (enblHtmlReport) { reportdir.mkdirs(); - String report = JaCoCoReportAnalyzer.toHtmlReport(binreport, reportdir, classDir, srcDir, prjname); + + // GWI patch: If NetBeans Module Project - use different HTML Report + String report; + if (isNBModule) { + report = NBJaCoCoExtension.toHTMLReport(binreport, reportdir, project); + } else { + report = JaCoCoReportAnalyzer.toHtmlReport(binreport, reportdir, classDir, srcDir, prjname); + } + if (openHtmlReport) { try { HtmlBrowser.URLDisplayer.getDefault().showURL(Utilities.toURI(new File(report)).toURL()); @@ -221,8 +252,22 @@ public void run() { } } if (enblHighlight) { - for (final JavaClass jclass : coverageData.values()) { - NBUtils.colorDoc(project, jclass, cfg.isEnblHighlightingExtended(), srcDir); + + // GWI patch: GWI-Modified: New Coloring Code + if (isNBModule) { + for (final JavaClass jclass : coverageData.values()) { + try { + NBUtils.colorDoc(project, jclass, cfg.isEnblHighlightingExtended(), srcDir); + } catch (Throwable e) { + Logger.getGlobal().log(Level.SEVERE, + "Failed to color: {0} {1}", + new Object[]{jclass.getClassName(), srcDir}); + } + } + } else { + for (final JavaClass jclass : coverageData.values()) { + NBUtils.colorDoc(project, jclass, cfg.isEnblHighlightingExtended(), srcDir); + } } } keepJaCoCoWorkfiles(binreport, xmlreport, prjDir, cfg.getJaCoCoWorkfilesRule()); diff --git a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/NBJaCoCoExtension.java b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/NBJaCoCoExtension.java new file mode 100644 index 0000000..c6947a6 --- /dev/null +++ b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/NBJaCoCoExtension.java @@ -0,0 +1,102 @@ +package fr.tikione.jacocoverage.plugin.action; + +import fr.tikione.jacocoexec.analyzer.JacocoNBModuleReportGenerator; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.Sources; +import org.netbeans.spi.project.SubprojectProvider; +import org.openide.util.Exceptions; + +/** + * @author Graeme Ingleby + */ +public class NBJaCoCoExtension { + + private JacocoNBModuleReportGenerator reportGenerator; + + public static String toHTMLReport(File binreport, File reportdir, Project project) { + return (new NBJaCoCoExtension()).myReportGeneration(binreport, reportdir, project); + } + + public static void toXmlReport(File binreport, File reportfile, Project project) { + (new NBJaCoCoExtension()).myXmlReportGeneration(binreport, reportfile, project); + } + + /** + * XML Generation. + * + * @param jacocoExecFile + * @param reportdir + * @param project + */ + public void myXmlReportGeneration(File jacocoExecFile, File reportdir, Project project) { + try { + reportGenerator = new JacocoNBModuleReportGenerator(jacocoExecFile, reportdir, true); + processProject(project); + reportGenerator.end(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + + /** + * HTML Generation. + * + * @param jacocoExecFile + * @param reportdir + * @param project + * @return + */ + public String myReportGeneration(File jacocoExecFile, File reportdir, Project project) { + try { + reportGenerator = new JacocoNBModuleReportGenerator(jacocoExecFile, reportdir, false); + processProject(project); + reportGenerator.end(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + return new File(reportdir, "index.html").getAbsolutePath(); + } + + public void processProject(Project project) throws FileNotFoundException, IOException { + List moduleClassDirectories = new ArrayList<>(8); + List moduleSourceDirectories = new ArrayList<>(8); + + String prjDir = project.getProjectDirectory().getPath(); + + File classDir = new File(prjDir + "/build/classes"); + if (classDir.exists()) { + moduleClassDirectories.add(classDir.getPath()); + } + + Sources source = ProjectUtils.getSources(project); + SourceGroup[] groups = source.getSourceGroups("java"); + for (SourceGroup group : groups) { + moduleSourceDirectories.add(group.getRootFolder().getPath()); + } + File genDir = new File(prjDir + "/build/classes-generated"); + if (genDir.exists()) { + moduleSourceDirectories.add(genDir.getPath()); + } + + reportGenerator.processNBModule(project.getProjectDirectory().getName(), moduleClassDirectories, moduleSourceDirectories); + processSubprojects(project); + } + + public void processSubprojects(Project project) throws IOException { + SubprojectProvider subs = project.getLookup().lookup(SubprojectProvider.class); + if (subs != null) { + Set subProjects = subs.getSubprojects(); + for (Project p : subProjects) { + processProject(p); + } + } + } +} diff --git a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectAntTestJ2SE.java b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectAntTestJ2SE.java index 70764cc..b7e835e 100644 --- a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectAntTestJ2SE.java +++ b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectAntTestJ2SE.java @@ -41,7 +41,7 @@ public ProjectAntTestJ2SE() { super("test"); setEnabled(Utils.isProjectSupported(NBUtils.getSelectedProject(), NBProjectTypeEnum.J2SE, NBProjectTypeEnum.J2EE, NBProjectTypeEnum.J2EE_EAR, - NBProjectTypeEnum.J2EE_EJB, NBProjectTypeEnum.J2EE_WEB)); + NBProjectTypeEnum.J2EE_EJB, NBProjectTypeEnum.J2EE_WEB, NBProjectTypeEnum.NBMODULE)); putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true); putValue(Action.NAME, Bundle.CTL_ProjectAntTestJ2SE()); } diff --git a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectRemoveCoverageData.java b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectRemoveCoverageData.java index 393d559..2710d66 100644 --- a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectRemoveCoverageData.java +++ b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/action/ProjectRemoveCoverageData.java @@ -39,8 +39,7 @@ public class ProjectRemoveCoverageData public ProjectRemoveCoverageData() { super(); - setEnabled( - Utils.isProjectSupported(NBUtils.getSelectedProject(), NBProjectTypeEnum.J2SE)); + setEnabled(Utils.isProjectSupported(NBUtils.getSelectedProject(), NBProjectTypeEnum.J2SE, NBProjectTypeEnum.NBMODULE)); putValue(DynamicMenuContent.HIDE_WHEN_DISABLED, true); putValue(Action.NAME, Bundle.CTL_ProjectRemoveCoverageData()); } diff --git a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/util/NBUtils.java b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/util/NBUtils.java index 01edcdd..a748e84 100644 --- a/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/util/NBUtils.java +++ b/tikione-jacocoverage-plugin/src/fr/tikione/jacocoverage/plugin/util/NBUtils.java @@ -1,311 +1,315 @@ -package fr.tikione.jacocoverage.plugin.util; - -import fr.tikione.jacocoexec.analyzer.JavaClass; -import fr.tikione.jacocoverage.plugin.anno.AbstractCoverageAnnotation; -import fr.tikione.jacocoverage.plugin.anno.CoverageAnnotation; -import fr.tikione.jacocoverage.plugin.anno.CoverageGlyphedAnnotation; -import fr.tikione.jacocoverage.plugin.anno.EditorCoverageStateEnum; -import fr.tikione.jacocoverage.plugin.config.Config; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.regex.Matcher; -import javax.swing.text.StyledDocument; -import org.netbeans.api.java.classpath.GlobalPathRegistry; -import org.netbeans.api.project.Project; -import org.netbeans.api.project.ProjectUtils; -import org.openide.awt.HtmlBrowser; -import org.openide.cookies.EditorCookie; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileUtil; -import org.openide.loaders.DataObject; -import org.openide.loaders.DataObjectNotFoundException; -import org.openide.modules.InstalledFileLocator; -import org.openide.nodes.Node; -import org.openide.text.Line; -import org.openide.text.NbDocument; -import org.openide.util.Exceptions; -import org.openide.util.Utilities; -import org.openide.windows.IOProvider; - -/** - * Some NetBeans related utilities. - * - * @author Jonathan Lermitage - */ -public class NBUtils { - - /** - * Close a NetBeans console tab. - * - * @param tabName the name on the tab. - * @throws IOException if an I/O error occurs. - */ - public static void closeConsoleTab(String tabName) - throws IOException { - IOProvider.getDefault().getIO(tabName, false).closeInputOutput(); - } - - /** - * Color (in editor) all the document representing the Java class. - * - * @param project the project containing the Java class. - * @param jclass the Java class informations and coverage data. - * @param multiLnInst enable coloring of multi-lines instructions. - * @param srcDir the folder containing Java sources. Needed only if {@code multiLnInst} is true, otherwise you can use {@code null}. - */ - @SuppressWarnings({"AssignmentToForLoopParameter", "UnnecessaryLabelOnBreakStatement"}) - public static void colorDoc(Project project, JavaClass jclass, boolean multiLnInst, File srcDir) { - String classResource = jclass.getPackageName() + jclass.getClassName(); - String prjId = getProjectId(project); - int theme = Config.getTheme(); - FIND_JAVA_FO: - for (FileObject curRoot : GlobalPathRegistry.getDefault().getSourceRoots()) { - FileObject fileObject = curRoot.getFileObject(classResource); - if (fileObject != null && "java".equalsIgnoreCase(fileObject.getExt())) { - try { - DataObject dataObject = DataObject.find(fileObject); - Node node = dataObject.getNodeDelegate(); - EditorCookie editorCookie = node.getLookup().lookup(EditorCookie.class); - Map coverage = jclass.getCoverage(); - Map coverageDesc = jclass.getCoverageDesc(); - if (editorCookie != null) { - StyledDocument doc = editorCookie.openDocument(); - if (doc != null) { - int startLine = 0; - int endLine = NbDocument.findLineNumber(doc, doc.getLength()); - Line.Set lineset = editorCookie.getLineSet(); - for (int covIdx : coverage.keySet()) { - if (covIdx >= startLine && covIdx <= endLine) { - Line line = lineset.getOriginal(covIdx); - EditorCoverageStateEnum coverageState; - switch (coverage.get(covIdx)) { - case COVERED: - coverageState = EditorCoverageStateEnum.COVERED; - break; - case NOT_COVERED: - coverageState = EditorCoverageStateEnum.NOT_COVERED; - break; - case PARTIALLY_COVERED: - coverageState = EditorCoverageStateEnum.PARTIALLY_COVERED; - break; - default: - coverageState = EditorCoverageStateEnum.COVERED; - } - AbstractCoverageAnnotation annotation; - if (coverageDesc.containsKey(covIdx)) { - annotation = new CoverageGlyphedAnnotation( - coverageState, - prjId, - jclass.getPackageName() + jclass.getClassName(), - covIdx, - coverageDesc.get(covIdx), - theme); - } else { - annotation = new CoverageAnnotation( - coverageState, - prjId, - jclass.getPackageName() + jclass.getClassName(), - covIdx, - theme); - } - annotation.attach(line); - line.addPropertyChangeListener(annotation); - } - } - if (multiLnInst) { - File javafile = new File(srcDir, jclass.getPackageName() + jclass.getClassName()); - List javalines = org.apache.commons.io.FileUtils.readLines(javafile); - int nblines = javalines.size(); - for (int lineIdx = 0; lineIdx < nblines; lineIdx++) { - boolean isCovered = coverage.containsKey(lineIdx); - boolean isCoveredDesc = coverageDesc.containsKey(lineIdx); - if ((isCovered || isCoveredDesc) - && (lineIdx + 1 < nblines) - && (!coverage.containsKey(lineIdx + 1) && !coverageDesc.containsKey(lineIdx + 1)) - && (!Utils.isIntructionFinished(javalines.get(lineIdx)))) { - EditorCoverageStateEnum coverageState; - switch (coverage.get(lineIdx)) { - case COVERED: - coverageState = EditorCoverageStateEnum.COVERED; - break; - case NOT_COVERED: - coverageState = EditorCoverageStateEnum.NOT_COVERED; - break; - case PARTIALLY_COVERED: - coverageState = EditorCoverageStateEnum.PARTIALLY_COVERED; - break; - default: - coverageState = EditorCoverageStateEnum.COVERED; - } - coverage.put(lineIdx + 1, coverage.get(lineIdx)); - AbstractCoverageAnnotation annotation = new CoverageAnnotation( - coverageState, - prjId, - jclass.getPackageName() + jclass.getClassName(), - lineIdx + 1, - theme); - Line line = lineset.getOriginal(lineIdx + 1); - annotation.attach(line); - line.addPropertyChangeListener(annotation); - } - } - } - } - break FIND_JAVA_FO; - } - } catch (DataObjectNotFoundException ex) { - Exceptions.printStackTrace(ex); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - } - } - } - - /** - * launch the default browser to display an URL. - * - * @param url the URL to display. - */ - public static void extBrowser(String url) { - try { - HtmlBrowser.URLDisplayer.getDefault().showURL(new URL(url)); - } catch (MalformedURLException ex) { - Exceptions.printStackTrace(ex); - } - } - - /** - * Get the JaCoCo-Agent JAR file that is registered in the IDE. - * - * @return the JaCoCo-Agent JAR. - */ - public static File getJacocoAgentJar() { - return InstalledFileLocator.getDefault().locate("modules/ext/jacocoagent.jar", "fr.tikione.jacoco.lib", false); - } - - /** - * Get the JaCoCo-Ant JAR file that is registered in the IDE. - * - * @return the JaCoCo-Ant JAR. - */ - public static File getJacocoAntJar() { - return InstalledFileLocator.getDefault().locate("modules/ext/jacocoant.jar", "fr.tikione.jacoco.lib", false); - } - - /** - * Get the full path of the directory containing a given project. - * - * @param project the project. - * @return the directory containing the project. - */ - public static String getProjectDir(Project project) { - return FileUtil.getFileDisplayName(project.getProjectDirectory()); - } - - /** - * Generate a string representing the project. Two different projects should have different representation. - * - * @param project the project. - * @return a representation of the project. - */ - public static String getProjectId(Project project) { - return getProjectDir(project) + '_' + project.toString(); - } - - /** - * Retrieve the list of Java packages of a given project. - * Each element is a fully qualified package name, e.g. foo, foo.bar and foo.bar.too. - * - * @param project the project to list Java packages. - * @param prjProps the project properties. - * @return a list of Java package names. - */ - public static List getProjectJavaPackages(Project project, Properties prjProps) { - List packages = new ArrayList<>(8); - String srcFolderName = Utils.getProperty(prjProps, "src.dir"); - List packagesAsFolders = Utils.listFolders( - new File(NBUtils.getProjectDir(project) + File.separator + srcFolderName + File.separator)); - int rootDirnameLen = NBUtils.getProjectDir(project).length() + srcFolderName.length() + 2; - for (File srcPackage : packagesAsFolders) { - packages.add(srcPackage.getAbsolutePath() - .substring(rootDirnameLen) - .replaceAll(Matcher.quoteReplacement(File.separator), ".")); - } - return packages; - } - - /** - * Retrieve the list of Java packages of a given project. - * Each element is a fully qualified package name, e.g. foo, foo.bar and foo.bar.too. - * Elements are separated with a given separator string. - * - * @param project the project to list Java packages. - * @param prjProps the project properties. - * @param separator the separator string. - * @param prefix a prefix to append to the end of each package name (can be empty). - * @return a list of Java package names. - */ - public static String getProjectJavaPackagesAsStr(Project project, Properties prjProps, String separator, String prefix) { - List packagesList = getProjectJavaPackages(project, prjProps); - StringBuilder packages = new StringBuilder(256); - if (packagesList.isEmpty()) { - packages.append("*"); - } else { - boolean first = true; - for (String pack : packagesList) { - if (!first) { - packages.append(separator); - } - packages.append(pack).append(prefix); - first = false; - } - } - return packages.toString(); - } - - /** - * Get the name of a project. - * - * @param project the project. - * @return the project's name. - */ - public static String getProjectName(Project project) { - return ProjectUtils.getInformation(project).getName(); - } - - /** - * Get the selected project. Return null if multiple projects are selected. - * - * @return the selected project or null if none or many. - */ - public static Project getSelectedProject() { - Project project; - Collection prjs = getAllSelectedProjects(); - if (prjs.size() == 1) { - project = prjs.iterator().next(); - } else { - project = null; - } - return project; - } - - /** - * Get every selected projects. - * - * @return the selected projects. - */ - public static Collection getAllSelectedProjects() { - return Utilities.actionsGlobalContext().lookupAll(Project.class); - } - - private NBUtils() { - } -} +package fr.tikione.jacocoverage.plugin.util; + +import fr.tikione.jacocoexec.analyzer.JavaClass; +import fr.tikione.jacocoverage.plugin.anno.AbstractCoverageAnnotation; +import fr.tikione.jacocoverage.plugin.anno.CoverageAnnotation; +import fr.tikione.jacocoverage.plugin.anno.CoverageGlyphedAnnotation; +import fr.tikione.jacocoverage.plugin.anno.EditorCoverageStateEnum; +import fr.tikione.jacocoverage.plugin.config.Config; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import javax.swing.text.StyledDocument; +import org.netbeans.api.java.classpath.GlobalPathRegistry; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.openide.awt.HtmlBrowser; +import org.openide.cookies.EditorCookie; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectNotFoundException; +import org.openide.modules.InstalledFileLocator; +import org.openide.nodes.Node; +import org.openide.text.Line; +import org.openide.text.NbDocument; +import org.openide.util.Exceptions; +import org.openide.util.Utilities; +import org.openide.windows.IOProvider; + +/** + * Some NetBeans related utilities. + * + * @author Jonathan Lermitage + * @author Graeme Ingleby + */ +public class NBUtils { + + /** + * Close a NetBeans console tab. + * + * @param tabName the name on the tab. + * @throws IOException if an I/O error occurs. + */ + public static void closeConsoleTab(String tabName) + throws IOException { + IOProvider.getDefault().getIO(tabName, false).closeInputOutput(); + } + + /** + * Color (in editor) all the document representing the Java class. + * + * @param project the project containing the Java class. + * @param jclass the Java class informations and coverage data. + * @param multiLnInst enable coloring of multi-lines instructions. + * @param srcDir the folder containing Java sources. Needed only if {@code multiLnInst} is true, otherwise you can use {@code null}. + */ + @SuppressWarnings({"AssignmentToForLoopParameter", "UnnecessaryLabelOnBreakStatement"}) + public static void colorDoc(Project project, JavaClass jclass, boolean multiLnInst, File srcDir) { + String classResource = jclass.getPackageName() + jclass.getClassName(); + String prjId = getProjectId(project); + int theme = Config.getTheme(); + FIND_JAVA_FO: + for (FileObject curRoot : GlobalPathRegistry.getDefault().getSourceRoots()) { + FileObject fileObject = curRoot.getFileObject(classResource); + if (fileObject != null && "java".equalsIgnoreCase(fileObject.getExt())) { + try { + DataObject dataObject = DataObject.find(fileObject); + Node node = dataObject.getNodeDelegate(); + EditorCookie editorCookie = node.getLookup().lookup(EditorCookie.class); + Map coverage = jclass.getCoverage(); + Map coverageDesc = jclass.getCoverageDesc(); + if (editorCookie != null) { + StyledDocument doc = editorCookie.openDocument(); + if (doc != null) { + int startLine = 0; + int endLine = NbDocument.findLineNumber(doc, doc.getLength()); + Line.Set lineset = editorCookie.getLineSet(); + for (int covIdx : coverage.keySet()) { + if (covIdx >= startLine && covIdx <= endLine) { + Line line = lineset.getOriginal(covIdx); + EditorCoverageStateEnum coverageState; + switch (coverage.get(covIdx)) { + case COVERED: + coverageState = EditorCoverageStateEnum.COVERED; + break; + case NOT_COVERED: + coverageState = EditorCoverageStateEnum.NOT_COVERED; + break; + case PARTIALLY_COVERED: + coverageState = EditorCoverageStateEnum.PARTIALLY_COVERED; + break; + default: + coverageState = EditorCoverageStateEnum.COVERED; + } + AbstractCoverageAnnotation annotation; + if (coverageDesc.containsKey(covIdx)) { + annotation = new CoverageGlyphedAnnotation( + coverageState, + prjId, + jclass.getPackageName() + jclass.getClassName(), + covIdx, + coverageDesc.get(covIdx), + theme); + } else { + annotation = new CoverageAnnotation( + coverageState, + prjId, + jclass.getPackageName() + jclass.getClassName(), + covIdx, + theme); + } + annotation.attach(line); + line.addPropertyChangeListener(annotation); + } + } + if (multiLnInst) { + // Patch by GWI + // old: File javafile = new File(srcDir, jclass.getPackageName() + jclass.getClassName()); + // new: File javafile = new File(fileObject.getPath()); + File javafile = new File(fileObject.getPath()); + List javalines = org.apache.commons.io.FileUtils.readLines(javafile); + int nblines = javalines.size(); + for (int lineIdx = 0; lineIdx < nblines; lineIdx++) { + boolean isCovered = coverage.containsKey(lineIdx); + boolean isCoveredDesc = coverageDesc.containsKey(lineIdx); + if ((isCovered || isCoveredDesc) + && (lineIdx + 1 < nblines) + && (!coverage.containsKey(lineIdx + 1) && !coverageDesc.containsKey(lineIdx + 1)) + && (!Utils.isIntructionFinished(javalines.get(lineIdx)))) { + EditorCoverageStateEnum coverageState; + switch (coverage.get(lineIdx)) { + case COVERED: + coverageState = EditorCoverageStateEnum.COVERED; + break; + case NOT_COVERED: + coverageState = EditorCoverageStateEnum.NOT_COVERED; + break; + case PARTIALLY_COVERED: + coverageState = EditorCoverageStateEnum.PARTIALLY_COVERED; + break; + default: + coverageState = EditorCoverageStateEnum.COVERED; + } + coverage.put(lineIdx + 1, coverage.get(lineIdx)); + AbstractCoverageAnnotation annotation = new CoverageAnnotation( + coverageState, + prjId, + jclass.getPackageName() + jclass.getClassName(), + lineIdx + 1, + theme); + Line line = lineset.getOriginal(lineIdx + 1); + annotation.attach(line); + line.addPropertyChangeListener(annotation); + } + } + } + } + break FIND_JAVA_FO; + } + } catch (DataObjectNotFoundException ex) { + Exceptions.printStackTrace(ex); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + } + } + + /** + * launch the default browser to display an URL. + * + * @param url the URL to display. + */ + public static void extBrowser(String url) { + try { + HtmlBrowser.URLDisplayer.getDefault().showURL(new URL(url)); + } catch (MalformedURLException ex) { + Exceptions.printStackTrace(ex); + } + } + + /** + * Get the JaCoCo-Agent JAR file that is registered in the IDE. + * + * @return the JaCoCo-Agent JAR. + */ + public static File getJacocoAgentJar() { + return InstalledFileLocator.getDefault().locate("modules/ext/jacocoagent.jar", "fr.tikione.jacoco.lib", false); + } + + /** + * Get the JaCoCo-Ant JAR file that is registered in the IDE. + * + * @return the JaCoCo-Ant JAR. + */ + public static File getJacocoAntJar() { + return InstalledFileLocator.getDefault().locate("modules/ext/jacocoant.jar", "fr.tikione.jacoco.lib", false); + } + + /** + * Get the full path of the directory containing a given project. + * + * @param project the project. + * @return the directory containing the project. + */ + public static String getProjectDir(Project project) { + return FileUtil.getFileDisplayName(project.getProjectDirectory()); + } + + /** + * Generate a string representing the project. Two different projects should have different representation. + * + * @param project the project. + * @return a representation of the project. + */ + public static String getProjectId(Project project) { + return getProjectDir(project) + '_' + project.toString(); + } + + /** + * Retrieve the list of Java packages of a given project. + * Each element is a fully qualified package name, e.g. foo, foo.bar and foo.bar.too. + * + * @param project the project to list Java packages. + * @param prjProps the project properties. + * @return a list of Java package names. + */ + public static List getProjectJavaPackages(Project project, Properties prjProps) { + List packages = new ArrayList<>(8); + String srcFolderName = Utils.getProperty(prjProps, "src.dir"); + List packagesAsFolders = Utils.listFolders( + new File(NBUtils.getProjectDir(project) + File.separator + srcFolderName + File.separator)); + int rootDirnameLen = NBUtils.getProjectDir(project).length() + srcFolderName.length() + 2; + for (File srcPackage : packagesAsFolders) { + packages.add(srcPackage.getAbsolutePath() + .substring(rootDirnameLen) + .replaceAll(Matcher.quoteReplacement(File.separator), ".")); + } + return packages; + } + + /** + * Retrieve the list of Java packages of a given project. + * Each element is a fully qualified package name, e.g. foo, foo.bar and foo.bar.too. + * Elements are separated with a given separator string. + * + * @param project the project to list Java packages. + * @param prjProps the project properties. + * @param separator the separator string. + * @param prefix a prefix to append to the end of each package name (can be empty). + * @return a list of Java package names. + */ + public static String getProjectJavaPackagesAsStr(Project project, Properties prjProps, String separator, String prefix) { + List packagesList = getProjectJavaPackages(project, prjProps); + StringBuilder packages = new StringBuilder(256); + if (packagesList.isEmpty()) { + packages.append("*"); + } else { + boolean first = true; + for (String pack : packagesList) { + if (!first) { + packages.append(separator); + } + packages.append(pack).append(prefix); + first = false; + } + } + return packages.toString(); + } + + /** + * Get the name of a project. + * + * @param project the project. + * @return the project's name. + */ + public static String getProjectName(Project project) { + return ProjectUtils.getInformation(project).getName(); + } + + /** + * Get the selected project. Return null if multiple projects are selected. + * + * @return the selected project or null if none or many. + */ + public static Project getSelectedProject() { + Project project; + Collection prjs = getAllSelectedProjects(); + if (prjs.size() == 1) { + project = prjs.iterator().next(); + } else { + project = null; + } + return project; + } + + /** + * Get every selected projects. + * + * @return the selected projects. + */ + public static Collection getAllSelectedProjects() { + return Utilities.actionsGlobalContext().lookupAll(Project.class); + } + + private NBUtils() { + } +}