diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000000..e69de29bb2d diff --git a/book.css b/book.css new file mode 100644 index 00000000000..aeeb104feb2 --- /dev/null +++ b/book.css @@ -0,0 +1,186 @@ +P.Code { + display: block; + text-align: left; + text-indent: 0.00pt; + margin-top: 0.000000pt; + margin-bottom: 0.000000pt; + margin-right: 0.000000pt; + margin-left: 15pt; + font-size: 10.000000pt; + color: #4444CC; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Courier New"; +} +H6.CaptionFigColumn { + display: block; + text-align: left; + text-indent: 0.000000pt; + margin-top: 3.000000pt; + margin-bottom: 11.000000pt; + margin-right: 0.000000pt; + margin-left: 0.000000pt; + font-size: 9.000000pt; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Arial"; +} +P.Note { + display: block; + text-align: left; + text-indent: 0pt; + margin-top: 19.500000pt; + margin-bottom: 19.500000pt; + margin-right: 0.000000pt; + margin-left: 30pt; + font-size: 11.000000pt; + font-style: Italic; + color: #000000; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family: "Arial"; +} +EM.UILabel { + font-weight: Bold; + text-decoration: none; + vertical-align: baseline; + text-transform: none; +} +EM.CodeName { + font-weight: Bold; + text-decoration: none; + vertical-align: baseline; + text-transform: none; + font-family:"Courier New"; +} + +body, html { border: 0px } + + +/* following font face declarations need to be removed for DBCS */ + +body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font-family: Arial, Helvetica, sans-serif; color: #000000} +pre { font-family: Courier, monospace} + +/* end font face declarations */ + +/* following font size declarations should be OK for DBCS */ +body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt {font-size: 10pt; } +pre { font-size: 10pt} + +/* end font size declarations */ + +body { background: #FFFFFF} +h1 { font-size: 18pt; margin-top: 15px; margin-bottom: 3px } +h2 { font-size: 14pt; margin-top: 20px; margin-bottom: 3px } +h3 { font-size: 11pt; margin-top: 20px; margin-bottom: 3px } +h4 { font-size: 10pt; margin-top: 20px; margin-bottom: 3px; font-style: italic } +p { margin-top: 10px; margin-bottom: 10px } +pre { margin-left: 6px; font-size: 9pt; color: #4444CC } +a:link { color: #0000FF } +a:hover { color: #000080 } +a:visited { text-decoration: underline } +ul { margin-top: 0; margin-bottom: 10px } +li { margin-top: 0; margin-bottom: 0 } +li p { margin-top: 0; margin-bottom: 0 } +ol { margin-top: 0; margin-bottom: 10px } +dl { margin-top: 0; margin-bottom: 10px } +dt { margin-top: 0; margin-bottom: 0; font-weight: bold } +dd { margin-top: 0; margin-bottom: 0 } +strong { font-weight: bold} +em { font-style: italic} +var { font-style: italic} +div.revision { border-left-style: solid; border-left-width: thin; + border-left-color: #7B68EE; padding-left:5px } +th { font-weight: bold } + +pre.code { + color: #000000; + margin: 0px 0px 0px 0px; + padding: 10px 10px 10px 10px; + background-color:#e0e0e0; + border: 1px solid #000000; +} + +div.menu { + background-image:url(images/topic.gif); + background-repeat:no-repeat; + background-position:left center; + padding-left:17px; + white-space:nowrap; + margin-bottom:2pt; +} +div.menu a { + color:#000000; + text-decoration:none; +} +div.menu a:visited { + color:#000000; + text-decoration:none; +} +div.menu a:hover { + text-decoration:underline; +} +div.menuhi { + color:#ffffff; + background-color:#000080; + background-image:url(images/topic.gif); + background-repeat:no-repeat; + background-position:left center; + padding-left:17px; + white-space:nowrap; + margin-bottom:2pt; +} +div.menuhi a { + color:#ffffff; + text-decoration:none; +} +div.menuhi a:visited { + color:#ffffff; + text-decoration:none; +} +div.menuhi a:hover { + text-decoration:underline; +} + +a.extern { + background-image:url(images/extern.gif); + background-repeat:no-repeat; + background-position:left center; + padding-left:15px; +} + +td.footer { + color:#8998a5; + font-size:8pt; +} +td.footer a { + color:#8998a5; +} + +p.info { + color: #000000; + margin: 0px 0px 0px 0px; + padding: 5px 5px 5px 25px; + background-color:#e0e0ff; + border: 1px solid #8080ff; + background-image:url(images/info.gif); + background-position:5px 5px; + background-repeat:no-repeat; +} + +p.warn { + color: #000000; + margin: 0px 0px 0px 0px; + padding: 5px 5px 5px 25px; + background-color:#ffffe0; + border: 1px solid #ffcc00; + background-image:url(images/warning.gif); + background-position:5px 5px; + background-repeat:no-repeat; +} \ No newline at end of file diff --git a/changes.html b/changes.html new file mode 100644 index 00000000000..10a5424b3ea --- /dev/null +++ b/changes.html @@ -0,0 +1,404 @@ + + +
+ + + + ++ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + +
+EclEmma Change LogVersion 3.1.9 (2024/05/22)
Version 3.1.8 (2023/12/12)
Version 3.1.7 (2023/06/07)
Version 3.1.6 (2022/06/01)
Version 3.1.5 (2021/09/08)
Version 3.1.4 (2020/12/08)
Version 3.1.3 (2020/03/13)
Version 3.1.2 (2019/03/12)
Version 3.1.1 (2018/09/12)
Version 3.1.0 (2018/06/27)
Version 3.0.1 (2017/11/14)
Version 3.0.0 (2017/06/28)+ This is the first release under the umbrella of the Eclipse Foundation. + EclEmma is now a official Eclipse.org project and included in several Eclipse + Oxygen (4.7) packages. +
Version 2.3.3 (2016/02/23)
Version 2.3.2 (2014/09/14)
Version 2.3.1 (2014/05/11)
Version 2.3.0 (2014/03/19)
Version 2.2.1 (2013/06/09)
Version 2.2.0 (2012/10/26)
Version 2.1.4 (2012/08/01)
Version 2.1.3 (2012/07/12)
Version 2.1.2 (2012/05/09)
Version 2.1.1 (2012/04/09)
Version 2.1.0 (2012/02/26)
Version 2.0.1 (2011/12/28)
Version 2.0.0 (2011/12/18)+ The first version of EclEmma that is backed by JaCoCo instead of EMMA. This + adds several enhancements and new features to EclEmma. +
Version 1.5.3 (2011/05/05)
Version 1.5.2 (2011/04/15)
Version 1.5.1 (2010/08/18)
Version 1.5.0 (2010/06/24)
Version 1.4.3 (2009/10/18)
Version 1.4.2 (2009/08/19)
Version 1.4.1 (2009/03/05)
Version 1.4.0 (2009/03/03)
Version 1.3.2 (2008/07/15)
Version 1.3.1 (2008/03/05)
Version 1.3.0 (2007/09/11)
Version 1.2.2 (2007/07/03)
Version 1.2.1 (2007/06/25)
Version 1.2.0 (2007/04/12)
Version 1.1.0 (2007/02/25)
Version 1.0.0 (2007/01/15)+ Since EclEmma is now out for more than three month, has been downloaded + more than 3,000 times and I've tried to fix many of the reported issues it's + time for the first 1.0 version! +
Version 0.1.8 (2006/12/18)
Version 0.1.7 (2006/11/19)
Version 0.1.6 (2006/10/31)
Version 0.1.5 (2006/10/18)
Version 0.1.4 (2006/09/30)
+ This is the first release after the source tree has moved to SourceForge.
+ The complete source is now available at the SVN repository
+
Version 0.1.3 (2006/09/18)
Version 0.1.2 (2006/08/29)+ Preview release with online documentation and some internal clean-up. +
Version 0.1.1 (2006/08/25)+ Preview release with additional features, like support for PDE launches and + selection of instrumented classes. Clean-up and clarification of internal + structures. + Version 0.1.0 (2006/08/09)+ The initial drop for some friends and colleagues for testing purposes. + It has been developed under Eclipse 3.1.1, some successful testing + happened with Eclipse 3.2.0. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2024-05-22 in Commit + a04d6441 + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + +
+Contact+ Any information and feedback of general interest can be posted at the + JaCoCo and + EclEmma Users group.. + Comments and reviews for EclEmma might also be posted at the + Eclipse Marketplace + operated by the Eclipse Foundation. + + Please rely on the channels described here to + get instant support for EclEmma. + Team+ + Marc R. Hoffmann, Project Lead ++ Marc started the EclEmma project in 2006 and authored the initial releases. In + 2009 he also started the JaCoCo project to + create a modern code coverage backend for EclEmma and other tools. Marc is + CTO at mtrail in + Berne/Switzerland. + + Brock Janiczak, Developer ++ As a developer Brock contributed several features since the early days of + EclEmma. + + Evgeny Mandrikov, Build Manager ++ As our build manager Evgeny maintains the Maven/Tycho based build for EclEmma. + Credits+ Many useful features of EclEmma are based on the ideas of users. Several + developers helped to improve the quality of EclEmma by filing bug reports and + submitting patches. Please see the change log for + individual credits. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2017-03-28 in Commit + 1ce487ba + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + + +
+Architecture+ Design decisions for the EclEmma plug-in should be based on the following + guidelines: +
+ The following sections provide a high level overview about EclEmma's key + implementation strategies. + Separate Backend from GUI+ EclEmma is packaged in two plug-ins: The core plug-in offers all functionality + for launching and analysis. It has no dependencies on the Eclipse UI and all + functionality can also be used in headless mode. The JUnit tests for + the core plug-in run headless. The UI plug-in provides the workbench + integration and relies on the core's public API only. This approach also + verifies the usability of the core API. + JaCoCo Execution Data Files+ To avoid modifying projects all data files are stored in the plug-in's state + location. + Launching in Coverage Mode+ Instead of re-implementing launcher for the different launch types, the + existing launchers for the Run mode are used with adjusted launch + configurations. The coverage launchers perform these steps: +
Coverage Session
+ A coverage session (
+ Whenever a coverage launch terminates a coverage session is automatically + created. While there can be a list of coverage sessions, at most one session + can be the active session which is used to provide coverage summaries + for Java elements and source code highlighting. + Coverage Analysis
+ As soon as a coverage session becomes active the corresponding execution data
+ is processed and analyzed against the classes in the workspace. Coverage
+ information is described by a Editor Highlighting+ The EclEmma UI plug-in tracks the currently opened Java editors and + piggybacks a specialized annotation model to the editors' annotation model. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2017-03-28 in Commit + 1ce487ba + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + + +
+Release Checklist+ For each new release the following tasks should be performed. + Code Quality
Documentation
Build and Distribution
Support
|
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2013-06-10 in Commit + a3a2710a + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + + +
+EclEmma 2.0 Position Paper+ The EclEmma code coverage plug-in for + Eclipse originally was designed as a wrapper for the + EMMA code coverage + library to make EMMA available within the Eclipse IDE. Since its initial + release in 2006 EclEmma became a popular addition to the Eclipse Java IDE. As + EMMA maintenance has stopped some years ago and we wanted to see functional + enhancements like branch coverage for EclEmma we started a completely new + code coverage backend called + JaCoCo under the + umbrella of the EclEmma project. The purpose of this paper is to setup + expectations for the EclEmma/JaCoCo user community and serve as a guide line + for technical decisions. The first release fully backed by JaCoCo is + "EclEmma 2.0". + + Marc R. Hoffmann, Mountainminds GmbH & Co. KG, September 2011 (updated) + Starting Point and Maxims+ Since its initial release in 2006 EclEmma became one of the most widely uses + code coverage tool in the Java developer's tool box and is one of the + most installed + Eclipse plug-ins. As EMMA development has stopped shortly after the first + EclEmma release in 2006 we started working on an alternative called JaCoCo in + 2009. The aim of the JaCoCo Project is + providing a lightweight, flexible and well documented library for + integration with various build and development tools, see this + mission statement + for details. In the meantime JaCoCo is fully functional and has been adopted + by several projects. For example the Eclipse platform integration builds are + analyzed using the JaCoCo Ant tasks. Many open source as well as commercial + projects use the + JaCoCo plug-in for Sonar + to control test quality. + + As EclEmma was originally developed to provide code coverage analysis directly + for the individual developer, the same now applies for JaCoCo. A consistent + view to test coverage metrics in the automated builds as well as the local + Eclipse IDE requires a JaCoCo plug-in for Eclipse. From the EclEmma project's + point of view there are at least the following three paths towards a JaCoCo + integration for Eclipse: +
+ I propose to follow option 3, which means migrate the existing EclEmma project + towards JaCoCo. Given the high exposure of EclEmma this options offers a set + of benefits: +
+ The other two options appear less attractive due to two main aspects: The + first point is the EMMA library itself. Given the issues described before and + the fact that EMMA fails with Java 7 byte code the future use of this great + but abandoned library is questionable. Therefore maintaining a EMMA-only + plug-in does not look reasonable in the long run. Users explicitly bound to + EMMA may continue using the EclEmma 1.x stream (see below). + + Providing a plugable architecture for different coverage libraries looks like + best practice at the first glance. This is how the overall Eclipse platform + has been successfully crafted. When looking at different code coverage + libraries features and integration strategies are very different. For + example EMMA requires a huge overhead for instrumentation of local class files + and hooks to tweak class paths. JaCoCo in contrast does not require this but + gives additional coverage metrics and source highlighting for branch coverage. + A code coverage framework would therefore either be +
+ On the other hand the Eclipse launch and debug framework already is a + plugable architecture that allows different integrations for different code + coverage technologies even today. + Functional Improvements+ For EclEmma 2.0 the following functional improvements are planned: + Branch Coverage
+ This additional metric will show coverage of all decision points in the
+ program flow due to Faster Launching+ Due the way how the JaCoCo coverage library works there will be no additional + delay any more when applications under test are launched. This is an + significant performance improvement especially for large applications and test + suites. + Less Invasive+ Certain launch types and test scenarios require so called in-place + instrumentation in EclEmma 1.x. With this option the original class files + get modified on disk and need to be restored with a clean build when switching + back to another launch mode. Also JAR files where excluded from coverage + analysis when in-place mode is activated. Without in-place + instrumentation the class path of the application under test was modified + which caused trouble for some applications. + + With EclElmma 2.0 class files on disk will never be modified and the class + path of an applications stays untouched. This will remove several hassles + especially for Eclipse application launches and JUnit plug-in tests. + Intermediate and Remote Coverage Analysis+ JaCoCo 2.0 (or more likely one of its subsequent versions) will support + intermediate coverage dumps on applications running locally or remote without + stopping the applications under test. This will also allow to reset the + collected coverage information for a running application. + Flexible Analysis Scope+ The scope of a coverage analysis can be modified at any time afterwards. While + in EclEmma 1.x the scope needs to be specified on the coverage launch dialog + before the application is launched, with EclEmma 2.0 the scope can be + altered at any time when the result of the coverage session is viewed. + The Plug-in Project Name+ Back in 2006 EclEmma originally was an acronym formed from the project + names Eclipse and EMMA. Today the name is widely used for code coverage in + Eclipse without an focus on the technology used internally. Therefore the name + should be kept, also for the plug-in Ids and Java package names. Which + directly leads to the next point. + Update from EclEmma 1.x to EclEmma 2.0+ Once EclEmma 2.0 has been stabilized and the first release is published + EclEmma users should be able to get the new JaCoCo based implementation simply + through the regular update site process. + System Requirements+ EclEmma 2.0 will raise the bar a little bit and has the following system + requirements: +
Future support for EMMA and EclEmma 1.x Maintenance+ From EclEmma 2.0 on EMMA will not be supported any more as a coverage engine. + The only supported backend will be JaCoCo. There are not plans for a + "plugable" architecture to facilitate different coverage engines. The + technologies are simply too different to efficiently integrate them based on a + common framework. + + Beside this we will try to maintain the EMMA based 1.x stream on a best effort + base but with no functional enhancements planned. There will be a separate + download for the 1.x versions. + Various Implementation Considerations+ For a new EclEmma 2.x the following ideas should be considered: +
References
|
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2017-03-28 in Commit + 1ce487ba + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + + +
+Developer Information+ This section provides information for EclEmma contributors and ISVs using the + EclEmma API. The project is hosted on the + GitHub platform, + its organization page is + https://github.com/jacoco. + The JaCoCo + and EclEmma Users Group is the place to discuss ideas, ask questions and + get in touch with the developers. + Trunk Builds+ The latest trunk build is always available at the update site URL + http://download.eclipselab.org/eclemma/trunk/update (not browseable). + EclEmma API
+ The Hacking EclEmma+ Interested to working with the EclEmma code base for new features and + improvements? No problem, with basic PDE skills you should get started within + a few minutes. Here is a quick start guide: + 1. Setup an Eclipse IDE for EclEmma
2. Get familiar with the code base+ The high-level design principles and some implementation strategies are + introduced in the architecture description. + Implementation details can be studied in the JavaDoc included with the + EclEmma source base. A good understanding of Eclipse' + launch + and debug framework will help to get behind the Coverage mode + implementation. + 3. Contribute back!+ So you finally created a cool new feature or fixed some bug? Great, contribute + it back to the official EclEmma releases! Open a + feature request + or create a + pull request + with your implementation. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2012-09-27 in Commit + 410aba54 + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+ + + + + + | + + + + + + + + + + + + + +
+Download+ The official releases builds are available for download below. Alternatively + EclEmma can be directly installed from the update site https://update.eclemma.org/. +
Previous Versions based on EMMA+ These EclEmma versions were based on the + EMMA code coverage tool. +
|
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2024-06-10 in Commit + 84369d1e + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + +
+Frequently Asked QuestionsUsage
Troubleshooting
UsageHow can I remove the coverage coloring from the Java editors again?+ If you remove the coverage session, also the coverage coloring will disappear. + For this, hit Remove Session or Remove All Sessions in the + Coverage view's toolbar. + How can I run {whateverapplication} with EclEmma?+ EclEmma is designed for Java programs launched within Eclipse. Java + applications that run in a different environment may be directly analyzed with + JaCoCo using for + example the Ant or Maven integrations. There are different supported launch + types, other plug-ins may define additional launch types which are not + supported by EclEmma. Check user documentation for currently supported launch types. + Does EclEmma support automated Ant or Maven builds?+ EclEmma is a Eclipse integration of the + JaCoCo code + coverage tool. JaCoCo comes with a set of + Ant tasks + and Maven goals + for automated builds. + How do I change the source code highlighting?+ The source code highlighting can be changed in the Eclipse Preference + dialog at General → Appearance → Editors → Text Editors + → Annotations. You can modify the highlighting style and color or use + the vertical rulers instead. + Do I need source code to use EclEmma?+ No, you can also get coverage information for e.g. third-party JARs. Just + make them part of your class path settings in Eclipse and select them on the + Coverage tab in the coverage launch dialog. If the library was compiled + with debug information, line coverage will be shown in the + Coverage view. In case the source is properly attached to the library + syntax highlighting will happen in the editors the same way as with you source + code. + Why is this line yellow?+ EclEmma annotates all lines which are partly covered in yellow. Partly covered + means that not all instructions and branches associated with this line have + been executed during the coverage session. In some cases it is not obvious why + the Java compiler creates extra byte code for a particular line of source code. + Such situations might be filtered by future versions of JaCoCo and EclEmma. + How can I exclude test classes from analysis?+ The analysis scope for coverage sessions can be defined in the + Coverage launch dialog on source folder (or library) granularity. As + test code is typically kept in separate source folders or projects this allows + to exclude your test classes from coverage analysis. + TroubleshootingWhy do I get the error message "No coverage data has been collected during this coverage session"?+ This happens when the Java process did not terminate properly, e.g. has been + manually killed with the Terminate button. Make sure your Java program + terminates on its own. Alternatively you can dump coverage data for the + running process before you terminate it. For this select the button Dump + Execution Data from the Coverage view's toolbar. + + Source code lines with exceptions show no coverage. Why?+ The underlying JaCoCo code coverage library determines code execution with so + called probes. Probes are inserted into the control flow at certain positions. + Code is considered as executed when a subsequent probe has been executed. In + case of exceptions such a sequence of instructions is aborted somewhere in the + middle and the corresponding line of source code is not marked as covered. + My application does not run with EclEmma!+ Does your application properly execute within Eclipse in normal run + mode? Please verify! If not, your app will most likely not execute in + coverage mode either. In this case first create a proper launch + configuration in Eclipse; then execute in coverage mode. + My Eclipse workbench window has no toolbar button for coverage launches!+ Even if EclEmma is installed properly, it will show its action sets only in + some predefined perspectives related to Java tasks. If you want to use the + coverage toolbar in other perspectives like Resource select + Customize Perspective... from the toolbar's context menu and check the + Java Code Coverage option on the Command Groups Availability tab. + Why are JUnit4 test cases with expected exceptions shown as not covered?
+ JUnit4 test cases with expected exceptions are shown as not covered even
+ though they were executed. The reason for this is that underlying JaCoCo code
+ coverage library only considers code as executed when certain probes are
+ executed. For successful test cases marked with The Coverage view stays empty and there is no source highlighting. Why?+ In Eclipse preferences there is an option Launch in debug mode when + workspace contains breakpoints under Run/Debug → + Launching. If this option is enabled and there are breakpoints in your + workspace coverage mode will not work, because it is automatically + replaced with debug mode. Set this option to Never if you want + to run code coverage analysis. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2017-06-14 in Commit + 6bec4798 + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + +
+Overview+ EclEmma is a free Java code coverage tool for + Eclipse, available under the + Eclipse Public License. It brings + code coverage analysis directly into the Eclipse workbench: +
+ Since version 2.0 EclEmma is based on the + JaCoCo code + coverage library. The Eclipse integration has its focus on supporting the + individual developer in an highly interactive way. For automated builds please + refer to JaCoCo + documentation for + integrations + with other tools. + + Originally EclEmma was inspired by and + technically based on the great + EMMA library + developed by Vlad Roubtsov. + + The update site for EclEmma is + https://update.eclemma.org/. EclEmma is also available via the Eclipse + Marketplace Client, + simply search for "EclEmma". + FeaturesLaunching+ EclEmma adds a so called launch mode to the Eclipse workbench. It is + called Coverage mode and works exactly like the existing Run and + Debug modes. The Coverage launch mode can be activated from the + Run menu or the workbench's toolbar: + + + + Simply launch your applications or unit + tests in the Coverage mode to collect coverage information. Currently + the following launch types are supported: +
Analysis+ On request or after your target application has terminated code coverage + information is automatically available in the Eclipse workbench: +
+ Additional features support analysis for your test coverage: +
Import/Export+ While EclEmma is primarily designed for test runs and analysis within the + Eclipse workbench, it provides some import/export features. + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2024-02-08 in Commit + e1ffb732 + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + +
+Installation+ EclEmma ships as a small set of Eclipse plug-ins under the + Eclipse Public License. The overall size of the + seven plug-ins is about 1 MByte. Like for all standard Eclipse plug-ins there + are different installation options. Using the marketplace or update site is + the recommended procedure. +
Prerequisites+ EclEmma requires Eclipse 3.8 or higher and Java 1.5 or higher. + It has no dependencies on a particular operating system. Of course your + Eclipse installation needs to contain the Java development tools (JDT) which + is included in the default SDK installation. + Option 1: Install from Eclipse Marketplace Client+ + + + + Since Eclipse 3.6 the + Eclipse Marketplace Client + allows direct installation of EclEmma from within Eclipse. Follow the steps + below or drag and drop the button above into a running Indigo workspace. + + 1. From your Eclipse menu select Help → Eclipse Marketplace. + + 2. Search for "EclEmma". + + 3. Hit Install for the entry "EclEmma Java Code Coverage". + + 4. Follow the steps in the installation wizard. + Option 2: Installation from Update Site+ The update site for EclEmma is https://update.eclemma.org/. Perform the + following steps to install EclEmma from the update site: + + 1. From your Eclipse menu select Help → Install New Software... + + 2. In the Install dialog enter https://update.eclemma.org/ at the + Work with field. + + + + 3. Check the latest EclEmma version and press Next + + 4. Follow the steps in the installation wizard. + Option 3: Manual Download and Installation
+ For manual installation please download the latest
+ EclEmma release. Unzip the archive into +<your eclipse installation>/ ++- dropins/ + +- eclemma-x.y.z/ + +- plugins/ + | +- ... + +- feature/ + +- ... + Verification+ The installation was successful if you can see the coverage launcher in the + toolbar of the Java perspective: + + + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2024-02-08 in Commit + e1ffb732 + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + + + +
+Installation of EclEmma 1.x+ Originally EclEmma was inspired by and technically based on the great + EMMA library + developed by Vlad Roubtsov. In case you explicitly need the EMMA backend you + can manually install a old EclEmma 1.x version. + + The EMMA based 1.x stream is maintained on a best effort base only and no + functional enhancements are planned for it. If you have specific requirements + currently only fulfilled by the EMMA version of EclEmma please + request this functionality for the new + JaCoCo backend. + Prerequisites+ EclEmma 1.x requires Eclipse 3.1 or higher and Java 1.4 or + higher. It has no dependencies on a particular operating system. Of course + your Eclipse installation needs to contain the Java development tools (JDT) + which is included in the default SDK installation. + Manual Download and Installation+ For manual installation please download the latest + EclEmma 1.x release. The downloaded archive contains these files: +
+ Simply unzip the archive into your Eclipse installation and restart Eclipse.
+ Since Eclipse 3.4 the Verification+ The installation was successful if you can see the coverage launcher in the + toolbar of the Java perspective: + + + + |
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2017-03-28 in Commit + 1ce487ba + | +
+ EclEmma 3.1.9 + | ++ Java Code Coverage for Eclipse + | ++ + + + | +
+ + + + + + | + + + + + + + + + + + +
+JaCoCo Java Code Coverage Library+ JaCoCo is a free code coverage library for Java, which has been created by the + EclEmma team based on the lessons learned from using and integrating existing + libraries for many years. + Snapshot Builds+ The master branch + of JaCoCo is automatically built and published. Due to the test driven + development approach every build is considered fully functional. See + change history + for latest features and bug fixes. SonarQube code quality metrics of the current + JaCoCo implementation are available on + SonarCloud.io. +
Release Builds+ The official releases builds are available for download below. JaCoCo is also + available from the + Maven repository. + Contact/Feedback+ Please don't hesitate to get in touch and provide feedback in the + JaCoCo and EclEmma Users + group. We're particular curious about +
|
Copyright © 2006, 2017 Mountainminds GmbH & Co. KG and Contributors | ++ Validate + XHTML/CSS · + Last Modified + 2024-04-06 in Commit + 46d3760d + | +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods | Missed | Classes |
Total | 1,439 of 28,962 | 95% | 185 of 2,396 | 92% | 250 | 2,772 | 369 | 6,717 | 75 | 1,542 | 16 | 308 |
org.jacoco.core | 97% | 91% | 145 | 1,543 | 125 | 3,640 | 19 | 747 | 2 | 147 | ||
org.jacoco.examples | 58% | 64% | 24 | 53 | 97 | 193 | 19 | 38 | 6 | 12 | ||
org.jacoco.agent.rt | 75% | 83% | 32 | 130 | 75 | 344 | 21 | 80 | 7 | 22 | ||
jacoco-maven-plugin | 90% | 82% | 35 | 193 | 49 | 465 | 8 | 116 | 1 | 23 | ||
org.jacoco.cli | 97% | 100% | 4 | 109 | 10 | 275 | 4 | 74 | 0 | 20 | ||
org.jacoco.report | 99% | 99% | 4 | 572 | 2 | 1,345 | 1 | 371 | 0 | 64 | ||
org.jacoco.ant | 98% | 99% | 4 | 162 | 8 | 428 | 3 | 110 | 0 | 19 | ||
org.jacoco.agent | 86% | 75% | 2 | 10 | 3 | 27 | 0 | 6 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods | Missed | Classes |
Total | 175 of 1,894 | 90% | 27 of 154 | 82% | 35 | 193 | 49 | 465 | 8 | 116 | 1 | 23 |
org.jacoco.maven | 90% | 82% | 35 | 193 | 49 | 465 | 8 | 116 | 1 | 23 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 2 of 233 | 99% | 4 of 40 | 90% | 4 | 28 | 1 | 59 | 0 | 8 |
getEffectivePropertyName() | 84% | 75% | 1 | 3 | 1 | 5 | 0 | 1 | ||
createAgentOptions() | 100% | 93% | 2 | 16 | 0 | 33 | 0 | 1 | ||
executeMojo() | 100% | n/a | 0 | 1 | 0 | 8 | 0 | 1 | ||
skipMojo() | 100% | 100% | 0 | 2 | 0 | 7 | 0 | 1 | ||
isPropertyNameSpecified() | 100% | 75% | 1 | 3 | 0 | 1 | 0 | 1 | ||
getAgentJarFile() | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
isEclipseTestPluginPackaging() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
AbstractAgentMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugins.annotations.Parameter; +import org.codehaus.plexus.util.StringUtils; +import org.jacoco.core.runtime.AgentOptions; + +/** + * Base class for preparing a property pointing to the JaCoCo runtime agent that + * can be passed as a VM argument to the application under test. + */ +public abstract class AbstractAgentMojo extends AbstractJacocoMojo { + + /** + * Name of the JaCoCo Agent artifact. + */ + static final String AGENT_ARTIFACT_NAME = "org.jacoco:org.jacoco.agent"; + /** + * Name of the property used in maven-osgi-test-plugin. + */ + static final String TYCHO_ARG_LINE = "tycho.testArgLine"; + /** + * Name of the property used in maven-surefire-plugin. + */ + static final String SUREFIRE_ARG_LINE = "argLine"; + /** + * Map of plugin artifacts. + */ + @Parameter(property = "plugin.artifactMap", required = true, readonly = true) + Map<String, Artifact> pluginArtifactMap; + /** + * Allows to specify property which will contains settings for JaCoCo Agent. + * If not specified, then "argLine" would be used for "jar" packaging and + * "tycho.testArgLine" for "eclipse-test-plugin". + */ + @Parameter(property = "jacoco.propertyName") + String propertyName; + /** + * If set to true and the execution data file already exists, coverage data + * is appended to the existing file. If set to false, an existing execution + * data file will be replaced. + */ + @Parameter(property = "jacoco.append") + Boolean append; + + /** + * A list of class names to include in instrumentation. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List<String> includes; + + /** + * A list of class names to exclude from instrumentation. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. Except + * for performance optimization or technical corner cases this option is + * normally not required. If you want to exclude classes from the report + * please configure the <code>report</code> goal accordingly. + */ + @Parameter + private List<String> excludes; + + /** + * A list of class loader names, that should be excluded from execution + * analysis. The list entries are separated by a colon (:) and may use + * wildcard characters (* and ?). This option might be required in case of + * special frameworks that conflict with JaCoCo code instrumentation, in + * particular class loaders that do not have access to the Java runtime + * classes. + */ + @Parameter(property = "jacoco.exclClassLoaders") + String exclClassLoaders; + /** + * Specifies whether also classes from the bootstrap classloader should be + * instrumented. Use this feature with caution, it needs heavy + * includes/excludes tuning. + */ + @Parameter(property = "jacoco.inclBootstrapClasses") + Boolean inclBootstrapClasses; + /** + * Specifies whether classes without source location should be instrumented. + */ + @Parameter(property = "jacoco.inclNoLocationClasses") + Boolean inclNoLocationClasses; + /** + * A session identifier that is written with the execution data. Without + * this parameter a random identifier is created by the agent. + */ + @Parameter(property = "jacoco.sessionId") + String sessionId; + /** + * If set to true coverage data will be written on VM shutdown. + */ + @Parameter(property = "jacoco.dumpOnExit") + Boolean dumpOnExit; + /** + * Output method to use for writing coverage data. Valid options are: + * <ul> + * <li>file: At VM termination execution data is written to a file.</li> + * <li>tcpserver: The agent listens for incoming connections on the TCP port + * specified by the {@link #address} and {@link #port}. Execution data is + * written to this TCP connection.</li> + * <li>tcpclient: At startup the agent connects to the TCP port specified by + * the {@link #address} and {@link #port}. Execution data is written to this + * TCP connection.</li> + * <li>none: Do not produce any output.</li> + * </ul> + */ + @Parameter(property = "jacoco.output") + String output; + /** + * IP address or hostname to bind to when the output method is tcpserver or + * connect to when the output method is tcpclient. In tcpserver mode the + * value "*" causes the agent to accept connections on any local address. + */ + @Parameter(property = "jacoco.address") + String address; + /** + * Port to bind to when the output method is tcpserver or connect to when + * the output method is tcpclient. In tcpserver mode the port must be + * available, which means that if multiple JaCoCo agents should run on the + * same machine, different ports have to be specified. + */ + @Parameter(property = "jacoco.port") + Integer port; + /** + * If a directory is specified for this parameter the JaCoCo agent dumps all + * class files it processes to the given location. This can be useful for + * debugging purposes or in case of dynamically created classes for example + * when scripting engines are used. + */ + @Parameter(property = "jacoco.classDumpDir") + File classDumpDir; + /** + * If set to true the agent exposes functionality via JMX. + */ + @Parameter(property = "jacoco.jmx") + Boolean jmx; + + @Override + public void executeMojo() { + final String name = getEffectivePropertyName(); + final Properties projectProperties = getProject().getProperties(); + final String oldValue = projectProperties.getProperty(name); + final String newValue = createAgentOptions() + .prependVMArguments(oldValue, getAgentJarFile()); + getLog().info(name + " set to " + newValue); + projectProperties.setProperty(name, newValue); + } + + @Override + protected void skipMojo() { + final String name = getEffectivePropertyName(); + final Properties projectProperties = getProject().getProperties(); + final String oldValue = projectProperties.getProperty(name); + if (oldValue == null) { + getLog().info(name + " set to empty"); + projectProperties.setProperty(name, ""); + } + } + + File getAgentJarFile() { + final Artifact jacocoAgentArtifact = pluginArtifactMap + .get(AGENT_ARTIFACT_NAME); + return jacocoAgentArtifact.getFile(); + } + + AgentOptions createAgentOptions() { + final AgentOptions agentOptions = new AgentOptions(); + agentOptions.setDestfile(getDestFile().getAbsolutePath()); + if (append != null) { + agentOptions.setAppend(append.booleanValue()); + } + if (includes != null && !includes.isEmpty()) { + agentOptions + .setIncludes(StringUtils.join(includes.iterator(), ":")); + } + if (excludes != null && !excludes.isEmpty()) { + agentOptions + .setExcludes(StringUtils.join(excludes.iterator(), ":")); + } + if (exclClassLoaders != null) { + agentOptions.setExclClassloader(exclClassLoaders); + } + if (inclBootstrapClasses != null) { + agentOptions.setInclBootstrapClasses( + inclBootstrapClasses.booleanValue()); + } + if (inclNoLocationClasses != null) { + agentOptions.setInclNoLocationClasses( + inclNoLocationClasses.booleanValue()); + } + if (sessionId != null) { + agentOptions.setSessionId(sessionId); + } + if (dumpOnExit != null) { + agentOptions.setDumpOnExit(dumpOnExit.booleanValue()); + } + if (output != null) { + agentOptions.setOutput(output); + } + if (address != null) { + agentOptions.setAddress(address); + } + if (port != null) { + agentOptions.setPort(port.intValue()); + } + if (classDumpDir != null) { + agentOptions.setClassDumpDir(classDumpDir.getAbsolutePath()); + } + if (jmx != null) { + agentOptions.setJmx(jmx.booleanValue()); + } + return agentOptions; + } + + String getEffectivePropertyName() { + if (isPropertyNameSpecified()) { + return propertyName; + } + if (isEclipseTestPluginPackaging()) { + return TYCHO_ARG_LINE; + } + return SUREFIRE_ARG_LINE; + } + + boolean isPropertyNameSpecified() { + return propertyName != null && !"".equals(propertyName); + } + + boolean isEclipseTestPluginPackaging() { + return "eclipse-test-plugin".equals(getProject().getPackaging()); + } + + /** + * @return the destFile + */ + abstract File getDestFile(); + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractJacocoMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractJacocoMojo.html new file mode 100644 index 00000000000..e120e04bdb8 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractJacocoMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 1 of 20 | 95% | 0 of 2 | 100% | 1 | 5 | 1 | 9 | 1 | 4 |
skipMojo() | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 | ||
execute() | 100% | 100% | 0 | 2 | 0 | 6 | 0 | 1 | ||
AbstractJacocoMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getProject() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +/** + * Base class for JaCoCo Mojos. + */ +public abstract class AbstractJacocoMojo extends AbstractMojo { + + /** + * Maven project. + */ + @Parameter(property = "project", readonly = true) + private MavenProject project; + + /** + * Flag used to suppress execution. + */ + @Parameter(property = "jacoco.skip", defaultValue = "false") + private boolean skip; + + public final void execute() + throws MojoExecutionException, MojoFailureException { + if (skip) { + getLog().info( + "Skipping JaCoCo execution because property jacoco.skip is set."); + skipMojo(); + return; + } + executeMojo(); + } + + /** + * Executes Mojo. + * + * @throws MojoExecutionException + * if an unexpected problem occurs. Throwing this exception + * causes a "BUILD ERROR" message to be displayed. + * @throws MojoFailureException + * if an expected problem (such as a compilation failure) + * occurs. Throwing this exception causes a "BUILD FAILURE" + * message to be displayed. + */ + protected abstract void executeMojo() + throws MojoExecutionException, MojoFailureException; + + /** + * Skips Mojo. + */ + protected void skipMojo() { + } + + /** + * @return Maven project + */ + protected final MavenProject getProject() { + return project; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractReportMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractReportMojo.html new file mode 100644 index 00000000000..8545aed353b --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AbstractReportMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 7 of 156 | 95% | 1 of 12 | 91% | 2 | 18 | 3 | 46 | 1 | 12 |
generate(Sink, Locale) | 0% | n/a | 1 | 1 | 2 | 2 | 1 | 1 | ||
generate(Sink, SinkFactory, Locale) | 87% | 50% | 1 | 2 | 1 | 4 | 0 | 1 | ||
executeReport(Locale) | 100% | n/a | 0 | 1 | 0 | 11 | 0 | 1 | ||
canGenerateReport() | 100% | 100% | 0 | 4 | 0 | 10 | 0 | 1 | ||
execute() | 100% | 100% | 0 | 2 | 0 | 8 | 0 | 1 | ||
addFormatters(ReportSupport, Locale) | 100% | 100% | 0 | 2 | 0 | 5 | 0 | 1 | ||
getDescription(Locale) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
AbstractReportMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getIncludes() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getExcludes() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
isExternalReport() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getCategoryName() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * troosan - add support for format selection + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import org.apache.maven.doxia.sink.SinkFactory; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.reporting.MavenMultiPageReport; +import org.apache.maven.reporting.MavenReportException; +import org.jacoco.report.IReportGroupVisitor; +import org.jacoco.report.IReportVisitor; + +/** + * Base class for creating a code coverage report for tests of a single project + * in multiple formats (HTML, XML, and CSV). + */ +public abstract class AbstractReportMojo extends AbstractMojo + implements MavenMultiPageReport { + + /** + * Encoding of the generated reports. + */ + @Parameter(property = "project.reporting.outputEncoding", defaultValue = "UTF-8") + String outputEncoding; + + /** + * A list of report formats to generate. Supported formats are HTML, XML and + * CSV. Defaults to all formats if no values are given. + * + * @since 0.8.7 + */ + @Parameter(defaultValue = "HTML,XML,CSV") + List<ReportFormat> formats; + + /** + * Name of the root node HTML report pages. + * + * @since 0.7.7 + */ + @Parameter(defaultValue = "${project.name}") + String title; + + /** + * Footer text used in HTML report pages. + * + * @since 0.7.7 + */ + @Parameter + String footer; + + /** + * Encoding of the source files. + */ + @Parameter(property = "project.build.sourceEncoding", defaultValue = "UTF-8") + String sourceEncoding; + + /** + * A list of class files to include in the report. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + List<String> includes; + + /** + * A list of class files to exclude from the report. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. + */ + @Parameter + List<String> excludes; + + /** + * Flag used to suppress execution. + */ + @Parameter(property = "jacoco.skip", defaultValue = "false") + boolean skip; + + /** + * Maven project. + */ + @Parameter(property = "project", readonly = true) + MavenProject project; + + public String getDescription(final Locale locale) { + return getName(locale) + " Coverage Report."; + } + + public boolean isExternalReport() { + return true; + } + + public String getCategoryName() { + return CATEGORY_PROJECT_REPORTS; + } + + /** + * Returns the list of class files to include in the report. + * + * @return class files to include, may contain wildcard characters + */ + List<String> getIncludes() { + return includes; + } + + /** + * Returns the list of class files to exclude from the report. + * + * @return class files to exclude, may contain wildcard characters + */ + List<String> getExcludes() { + return excludes; + } + + public boolean canGenerateReport() { + if (skip) { + getLog().info( + "Skipping JaCoCo execution because property jacoco.skip is set."); + return false; + } + if (!canGenerateReportRegardingDataFiles()) { + getLog().info( + "Skipping JaCoCo execution due to missing execution data file."); + return false; + } + if (!canGenerateReportRegardingClassesDirectory()) { + getLog().info( + "Skipping JaCoCo execution due to missing classes directory."); + return false; + } + return true; + } + + abstract boolean canGenerateReportRegardingDataFiles(); + + abstract boolean canGenerateReportRegardingClassesDirectory(); + + abstract File getOutputDirectory(); + + public void generate( + @SuppressWarnings("deprecation") final org.codehaus.doxia.sink.Sink sink, + final Locale locale) throws MavenReportException { + generate(sink, null, locale); + } + + public void generate(final org.apache.maven.doxia.sink.Sink sink, + final SinkFactory sinkFactory, final Locale locale) + throws MavenReportException { + if (!canGenerateReport()) { + return; + } + executeReport(locale); + } + + /** + * This method is called when the report generation is invoked directly as a + * standalone Mojo. + */ + public void execute() throws MojoExecutionException { + if (!canGenerateReport()) { + return; + } + try { + executeReport(Locale.getDefault()); + } catch (final MavenReportException e) { + throw new MojoExecutionException("An error has occurred in " + + getName(Locale.ENGLISH) + " report generation.", e); + } + } + + private void executeReport(final Locale locale) + throws MavenReportException { + try { + final ReportSupport support = new ReportSupport(getLog()); + loadExecutionData(support); + addFormatters(support, locale); + final IReportVisitor visitor = support.initRootVisitor(); + createReport(visitor, support); + visitor.visitEnd(); + } catch (final IOException e) { + throw new MavenReportException( + "Error while creating report: " + e.getMessage(), e); + } + } + + private void addFormatters(final ReportSupport support, final Locale locale) + throws IOException { + getOutputDirectory().mkdirs(); + for (final ReportFormat f : formats) { + support.addVisitor(f.createVisitor(this, locale)); + } + } + + abstract void loadExecutionData(final ReportSupport support) + throws IOException; + + abstract void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException; + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentITMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentITMojo.html new file mode 100644 index 00000000000..60e18b0e076 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentITMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 6 | 100% | 0 of 0 | n/a | 0 | 2 | 0 | 2 | 0 | 2 |
AgentITMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getDestFile() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * Same as <code>prepare-agent</code>, but provides default values suitable for + * integration-tests: + * <ul> + * <li>bound to <code>pre-integration-test</code> phase</li> + * <li>different <code>destFile</code></li> + * </ul> + * + * @since 0.6.4 + */ +@Mojo(name = "prepare-agent-integration", defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true) +public class AgentITMojo extends AbstractAgentMojo { + + /** + * Path to the output file for execution data. + */ + @Parameter(property = "jacoco.destFile", defaultValue = "${project.build.directory}/jacoco-it.exec") + private File destFile; + + /** + * @return the destFile + */ + @Override + File getDestFile() { + return destFile; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentMojo.html new file mode 100644 index 00000000000..e1cb6d044ca --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/AgentMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 6 | 100% | 0 of 0 | n/a | 0 | 2 | 0 | 2 | 0 | 2 |
AgentMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getDestFile() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + +/** + * <p> + * Prepares a property pointing to the JaCoCo runtime agent that can be passed + * as a VM argument to the application under test. Depending on the project + * packaging type by default a property with the following name is set: + * </p> + * + * <ul> + * <li>tycho.testArgLine for packaging type eclipse-test-plugin and</li> + * <li>argLine otherwise.</li> + * </ul> + * + * <p> + * If your project already defines VM arguments for test execution, be sure that + * they will include property defined by JaCoCo. + * </p> + * + * <p> + * One of the ways to do this in case of maven-surefire-plugin - is to use + * syntax for <a href= + * "http://maven.apache.org/surefire/maven-surefire-plugin/faq.html#late-property-evaluation">late + * property evaluation</a>: + * </p> + * + * <pre> + * <plugin> + * <groupId>org.apache.maven.plugins</groupId> + * <artifactId>maven-surefire-plugin</artifactId> + * <configuration> + * <argLine>@{argLine} -your -extra -arguments</argLine> + * </configuration> + * </plugin> + * </pre> + * + * <p> + * You can define empty property to avoid JVM startup error + * <code>Could not find or load main class @{argLine}</code> when using late + * property evaluation and jacoco-maven-plugin not executed. + * </p> + * + * <p> + * Another way is to define "argLine" as a Maven property rather than as part of + * the configuration of maven-surefire-plugin: + * </p> + * + * <pre> + * <properties> + * <argLine>-your -extra -arguments</argLine> + * </properties> + * ... + * <plugin> + * <groupId>org.apache.maven.plugins</groupId> + * <artifactId>maven-surefire-plugin</artifactId> + * <configuration> + * <!-- no argLine here --> + * </configuration> + * </plugin> + * </pre> + * + * <p> + * Resulting coverage information is collected during execution and by default + * written to a file when the process terminates. + * </p> + * + * @since 0.5.3 + */ +@Mojo(name = "prepare-agent", defaultPhase = LifecyclePhase.INITIALIZE, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true) +public class AgentMojo extends AbstractAgentMojo { + + /** + * Path to the output file for execution data. + */ + @Parameter(property = "jacoco.destFile", defaultValue = "${project.build.directory}/jacoco.exec") + private File destFile; + + /** + * @return the destFile + */ + @Override + File getDestFile() { + return destFile; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/CheckMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/CheckMojo.html new file mode 100644 index 00000000000..4a6788286b0 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/CheckMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 43 of 151 | 71% | 3 of 12 | 75% | 3 | 11 | 8 | 38 | 0 | 5 |
canCheckCoverage() | 38% | 50% | 2 | 3 | 4 | 9 | 0 | 1 | ||
executeCheck() | 83% | 100% | 0 | 4 | 3 | 21 | 0 | 1 | ||
executeMojo() | 85% | 50% | 1 | 2 | 1 | 4 | 0 | 1 | ||
onViolation(ICoverageNode, Rule, Limit, String) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
CheckMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * Marc Hoffmann - redesign using report APIs + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.jacoco.core.analysis.ICoverageNode; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.check.IViolationsOutput; +import org.jacoco.report.check.Limit; +import org.jacoco.report.check.Rule; + +/** + * Checks that the code coverage metrics are being met. + * + * @since 0.6.1 + */ +@Mojo(name = "check", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) +public class CheckMojo extends AbstractJacocoMojo implements IViolationsOutput { + + private static final String MSG_SKIPPING = "Skipping JaCoCo execution due to missing execution data file:"; + private static final String CHECK_SUCCESS = "All coverage checks have been met."; + private static final String CHECK_FAILED = "Coverage checks have not been met. See log for details."; + + /** + * <p> + * Check configuration used to specify rules on element types (BUNDLE, + * PACKAGE, CLASS, SOURCEFILE or METHOD) with a list of limits. Each limit + * applies to a certain counter (INSTRUCTION, LINE, BRANCH, COMPLEXITY, + * METHOD, CLASS) and defines a minimum or maximum for the corresponding + * value (TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO, MISSEDRATIO). + * If a limit refers to a ratio it must be in the range from 0.0 to 1.0 + * where the number of decimal places will also determine the precision in + * error messages. A limit ratio may optionally be declared as a percentage + * where 0.80 and 80% represent the same value. + * </p> + * + * <p> + * If not specified the following defaults are assumed: + * </p> + * + * <ul> + * <li>rule element: BUNDLE</li> + * <li>limit counter: INSTRUCTION</li> + * <li>limit value: COVEREDRATIO</li> + * </ul> + * + * <p> + * This example requires an overall instruction coverage of 80% and no class + * must be missed: + * </p> + * + * <pre> + * {@code + * <rules> + * <rule> + * <element>BUNDLE</element> + * <limits> + * <limit> + * <counter>INSTRUCTION</counter> + * <value>COVEREDRATIO</value> + * <minimum>0.80</minimum> + * </limit> + * <limit> + * <counter>CLASS</counter> + * <value>MISSEDCOUNT</value> + * <maximum>0</maximum> + * </limit> + * </limits> + * </rule> + * </rules>} + * </pre> + * + * <p> + * This example requires a line coverage minimum of 50% for every class + * except test classes: + * </p> + * + * <pre> + * {@code + * <rules> + * <rule> + * <element>CLASS</element> + * <excludes> + * <exclude>*Test</exclude> + * </excludes> + * <limits> + * <limit> + * <counter>LINE</counter> + * <value>COVEREDRATIO</value> + * <minimum>50%</minimum> + * </limit> + * </limits> + * </rule> + * </rules>} + * </pre> + */ + @Parameter(required = true) + private List<RuleConfiguration> rules; + + /** + * Halt the build if any of the checks fail. + */ + @Parameter(property = "jacoco.haltOnFailure", defaultValue = "true", required = true) + private boolean haltOnFailure; + + /** + * File with execution data. + */ + @Parameter(defaultValue = "${project.build.directory}/jacoco.exec") + private File dataFile; + + /** + * A list of class files to include into analysis. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List<String> includes; + + /** + * A list of class files to exclude from analysis. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. + */ + @Parameter + private List<String> excludes; + + private boolean violations; + + private boolean canCheckCoverage() { + if (!dataFile.exists()) { + getLog().info(MSG_SKIPPING + dataFile); + return false; + } + final File classesDirectory = new File( + getProject().getBuild().getOutputDirectory()); + if (!classesDirectory.exists()) { + getLog().info( + "Skipping JaCoCo execution due to missing classes directory:" + + classesDirectory); + return false; + } + return true; + } + + @Override + public void executeMojo() throws MojoExecutionException { + if (!canCheckCoverage()) { + return; + } + executeCheck(); + } + + private void executeCheck() throws MojoExecutionException { + violations = false; + + final ReportSupport support = new ReportSupport(getLog()); + + final List<Rule> checkerrules = new ArrayList<Rule>(); + for (final RuleConfiguration r : rules) { + checkerrules.add(r.rule); + } + support.addRulesChecker(checkerrules, this); + + try { + final IReportVisitor visitor = support.initRootVisitor(); + support.loadExecutionData(dataFile); + support.processProject(visitor, getProject(), includes, excludes); + visitor.visitEnd(); + } catch (final IOException e) { + throw new MojoExecutionException( + "Error while checking code coverage: " + e.getMessage(), e); + } + if (violations) { + if (this.haltOnFailure) { + throw new MojoExecutionException(CHECK_FAILED); + } else { + this.getLog().warn(CHECK_FAILED); + } + } else { + this.getLog().info(CHECK_SUCCESS); + } + } + + public void onViolation(final ICoverageNode node, final Rule rule, + final Limit limit, final String message) { + this.getLog().warn(message); + violations = true; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/DumpMojo$1.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/DumpMojo$1.html new file mode 100644 index 00000000000..01f09067ad8 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/DumpMojo$1.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 31 | 100% | 0 of 0 | n/a | 0 | 3 | 0 | 6 | 0 | 3 |
onConnecting(InetAddress, int) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
onConnectionFailure(IOException) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
{...} | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 7 of 58 | 87% | 1 of 2 | 50% | 1 | 3 | 2 | 14 | 0 | 2 |
executeMojo() | 87% | 50% | 1 | 2 | 2 | 13 | 0 | 1 | ||
DumpMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Chas Honton, Marc R. Hoffmann - initial implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import static java.lang.String.format; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.jacoco.core.tools.ExecDumpClient; +import org.jacoco.core.tools.ExecFileLoader; + +/** + * <p> + * Request a dump over TCP/IP from a JaCoCo agent running in + * <code>tcpserver</code> mode. + * </p> + * + * <p> + * Note concerning parallel builds: While the dump goal as such is thread safe, + * it has to be considered that TCP/IP server ports of the agents are a shared + * resource. + * </p> + * + * @since 0.6.4 + */ +@Mojo(name = "dump", defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST, threadSafe = true) +public class DumpMojo extends AbstractJacocoMojo { + + /** + * Path to the output file for execution data. + */ + @Parameter(property = "jacoco.destFile", defaultValue = "${project.build.directory}/jacoco.exec") + private File destFile; + + /** + * If set to true and the execution data file already exists, coverage data + * is appended to the existing file. If set to false, an existing execution + * data file will be replaced. + */ + @Parameter(property = "jacoco.append", defaultValue = "true") + private boolean append; + + /** + * Sets whether execution data should be downloaded from the remote host. + */ + @Parameter(property = "jacoco.dump", defaultValue = "true") + private boolean dump; + + /** + * Sets whether a reset command should be sent after the execution data has + * been dumped. + */ + @Parameter(property = "jacoco.reset", defaultValue = "false") + private boolean reset; + + /** + * IP address or hostname to connect to. + */ + @Parameter(property = "jacoco.address") + private String address; + + /** + * Port number to connect to. If multiple JaCoCo agents should run on the + * same machine, different ports have to be specified for the agents. + */ + @Parameter(property = "jacoco.port", defaultValue = "6300") + private int port; + + /** + * Number of retries which the goal will attempt to establish a connection. + * This can be used to wait until the target JVM is successfully launched. + */ + @Parameter(property = "jacoco.retryCount", defaultValue = "10") + private int retryCount; + + @Override + public void executeMojo() throws MojoExecutionException { + final ExecDumpClient client = new ExecDumpClient() { + @Override + protected void onConnecting(final InetAddress address, + final int port) { + getLog().info(format("Connecting to %s:%s", address, + Integer.valueOf(port))); + } + + @Override + protected void onConnectionFailure(final IOException exception) { + getLog().info(exception.getMessage()); + } + }; + client.setDump(dump); + client.setReset(reset); + client.setRetryCount(retryCount); + + try { + final ExecFileLoader loader = client.dump(address, port); + if (dump) { + getLog().info(format("Dumping execution data to %s", + destFile.getAbsolutePath())); + loader.save(destFile, append); + } + } catch (final IOException e) { + throw new MojoExecutionException("Unable to dump coverage data", e); + } + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/FileFilter.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/FileFilter.html new file mode 100644 index 00000000000..59d63648574 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/FileFilter.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 50 | 100% | 1 of 4 | 75% | 1 | 8 | 0 | 12 | 0 | 6 |
buildPattern(List, String) | 100% | 75% | 1 | 3 | 0 | 4 | 0 | 1 | ||
FileFilter(List, List) | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
getFileNames(File) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getFiles(File) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getIncludes() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getExcludes() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.StringUtils; + +/** + * A file filter using includes/excludes patterns. + */ +public class FileFilter { + + private static final String DEFAULT_INCLUDES = "**"; + private static final String DEFAULT_EXCLUDES = ""; + + private final List<String> includes; + private final List<String> excludes; + + /** + * Construct a new FileFilter + * + * @param includes + * list of includes patterns + * @param excludes + * list of excludes patterns + */ + public FileFilter(final List<String> includes, + final List<String> excludes) { + this.includes = includes; + this.excludes = excludes; + } + + /** + * Returns a list of file names. + * + * @param directory + * the directory to scan + * @return a list of files + * @throws IOException + * if file system access fails + */ + public List<String> getFileNames(final File directory) throws IOException { + return FileUtils.getFileNames(directory, getIncludes(), getExcludes(), + false); + } + + /** + * Returns a list of files. + * + * @param directory + * the directory to scan + * @return a list of files + * @throws IOException + * if file system access fails + */ + public List<File> getFiles(final File directory) throws IOException { + return FileUtils.getFiles(directory, getIncludes(), getExcludes()); + } + + /** + * Get the includes pattern + * + * @return the pattern + */ + public String getIncludes() { + return this.buildPattern(this.includes, DEFAULT_INCLUDES); + } + + /** + * Get the excludes pattern + * + * @return the pattern + */ + public String getExcludes() { + return this.buildPattern(this.excludes, DEFAULT_EXCLUDES); + } + + private String buildPattern(final List<String> patterns, + final String defaultPattern) { + String pattern = defaultPattern; + if (patterns != null && !patterns.isEmpty()) { + pattern = StringUtils.join(patterns.iterator(), ","); + } + return pattern; + } +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/InstrumentMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/InstrumentMojo.html new file mode 100644 index 00000000000..7183faddae1 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/InstrumentMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 14 of 125 | 88% | 1 of 6 | 83% | 1 | 5 | 4 | 31 | 0 | 2 |
executeMojo() | 88% | 83% | 1 | 4 | 4 | 30 | 0 | 1 | ||
InstrumentMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.IOUtil; +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.OfflineInstrumentationAccessGenerator; + +/** + * Performs offline instrumentation. Note that after execution of test you must + * restore original classes with help of "restore-instrumented-classes" goal. + * <p> + * <strong>Warning:</strong> The preferred way for code coverage analysis with + * JaCoCo is on-the-fly instrumentation. Offline instrumentation has several + * drawbacks and should only be used if a specific scenario explicitly requires + * this mode. Please consult <a href="offline.html">documentation</a> about + * offline instrumentation before using this mode. + * </p> + * + * @since 0.6.2 + */ +@Mojo(name = "instrument", defaultPhase = LifecyclePhase.PROCESS_CLASSES, threadSafe = true) +public class InstrumentMojo extends AbstractJacocoMojo { + + /** + * A list of class files to include in instrumentation. May use wildcard + * characters (* and ?). When not specified everything will be included. + */ + @Parameter + private List<String> includes; + + /** + * A list of class files to exclude from instrumentation. May use wildcard + * characters (* and ?). When not specified nothing will be excluded. Except + * for performance optimization or technical corner cases this option is + * normally not required. If you want to exclude classes from the report + * please configure the <code>report</code> goal accordingly. + */ + @Parameter + private List<String> excludes; + + @Override + public void executeMojo() + throws MojoExecutionException, MojoFailureException { + final File originalClassesDir = new File( + getProject().getBuild().getDirectory(), + "generated-classes/jacoco"); + originalClassesDir.mkdirs(); + final File classesDir = new File( + getProject().getBuild().getOutputDirectory()); + if (!classesDir.exists()) { + getLog().info( + "Skipping JaCoCo execution due to missing classes directory:" + + classesDir); + return; + } + + final List<String> fileNames; + try { + fileNames = new FileFilter(includes, excludes) + .getFileNames(classesDir); + } catch (final IOException e1) { + throw new MojoExecutionException( + "Unable to get list of files to instrument.", e1); + } + + final Instrumenter instrumenter = new Instrumenter( + new OfflineInstrumentationAccessGenerator()); + for (final String fileName : fileNames) { + if (fileName.endsWith(".class")) { + final File source = new File(classesDir, fileName); + final File backup = new File(originalClassesDir, fileName); + InputStream input = null; + OutputStream output = null; + try { + FileUtils.copyFile(source, backup); + input = new FileInputStream(backup); + output = new FileOutputStream(source); + instrumenter.instrument(input, output, source.getPath()); + } catch (final IOException e2) { + throw new MojoExecutionException( + "Unable to instrument file.", e2); + } finally { + IOUtil.close(input); + IOUtil.close(output); + } + } + } + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/MergeMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/MergeMojo.html new file mode 100644 index 00000000000..24216606da7 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/MergeMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 44 of 159 | 72% | 5 of 14 | 64% | 5 | 13 | 12 | 40 | 0 | 6 |
save(ExecFileLoader) | 54% | 50% | 1 | 2 | 5 | 11 | 0 | 1 | ||
load(ExecFileLoader) | 79% | 83% | 1 | 4 | 4 | 16 | 0 | 1 | ||
canMergeReports() | 60% | 50% | 2 | 3 | 2 | 4 | 0 | 1 | ||
executeMojo() | 85% | 50% | 1 | 2 | 1 | 4 | 0 | 1 | ||
executeMerge() | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
MergeMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Mads Mohr Christensen - implementation of MergeMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.shared.model.fileset.FileSet; +import org.apache.maven.shared.model.fileset.util.FileSetManager; +import org.jacoco.core.tools.ExecFileLoader; + +/** + * Mojo for merging a set of execution data files (*.exec) into a single file + * + * @since 0.6.4 + */ +@Mojo(name = "merge", defaultPhase = LifecyclePhase.GENERATE_RESOURCES, threadSafe = true) +public class MergeMojo extends AbstractJacocoMojo { + + private static final String MSG_SKIPPING = "Skipping JaCoCo merge execution due to missing execution data files"; + + /** + * Path to the output file for execution data. + */ + @Parameter(property = "jacoco.destFile", defaultValue = "${project.build.directory}/jacoco.exec") + private File destFile; + + /** + * This mojo accepts any number of execution data file sets. + * + * <pre> + * <code> + * <fileSets> + * <fileSet> + * <directory>${project.build.directory}</directory> + * <includes> + * <include>*.exec</include> + * </includes> + * </fileSet> + * </fileSets> + * </code> + * </pre> + */ + @Parameter(required = true) + private List<FileSet> fileSets; + + @Override + protected void executeMojo() + throws MojoExecutionException, MojoFailureException { + if (!canMergeReports()) { + return; + } + executeMerge(); + } + + private boolean canMergeReports() { + if (fileSets == null || fileSets.isEmpty()) { + getLog().info(MSG_SKIPPING); + return false; + } + return true; + } + + private void executeMerge() throws MojoExecutionException { + final ExecFileLoader loader = new ExecFileLoader(); + + load(loader); + save(loader); + } + + private void load(final ExecFileLoader loader) + throws MojoExecutionException { + final FileSetManager fileSetManager = new FileSetManager(); + for (final FileSet fileSet : fileSets) { + for (final String includedFilename : fileSetManager + .getIncludedFiles(fileSet)) { + final File inputFile = new File(fileSet.getDirectory(), + includedFilename); + if (inputFile.isDirectory()) { + continue; + } + try { + getLog().info("Loading execution data file " + + inputFile.getAbsolutePath()); + loader.load(inputFile); + } catch (final IOException e) { + throw new MojoExecutionException( + "Unable to read " + inputFile.getAbsolutePath(), e); + } + } + } + } + + private void save(final ExecFileLoader loader) + throws MojoExecutionException { + if (loader.getExecutionDataStore().getContents().isEmpty()) { + getLog().info(MSG_SKIPPING); + return; + } + getLog().info("Writing merged execution data to " + + destFile.getAbsolutePath()); + try { + loader.save(destFile, false); + } catch (final IOException e) { + throw new MojoExecutionException( + "Unable to write merged file " + destFile.getAbsolutePath(), + e); + } + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportAggregateMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportAggregateMojo.html new file mode 100644 index 00000000000..3538395d3bd --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportAggregateMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 12 of 264 | 95% | 2 of 28 | 92% | 3 | 28 | 4 | 58 | 1 | 14 |
findProjectFromReactor(Dependency) | 87% | 100% | 0 | 5 | 2 | 14 | 0 | 1 | ||
setReportOutputDirectory(File) | 84% | 50% | 2 | 3 | 1 | 5 | 0 | 1 | ||
getReportOutputDirectory() | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 | ||
loadExecutionData(ReportSupport) | 100% | 100% | 0 | 3 | 0 | 8 | 0 | 1 | ||
createReport(IReportGroupVisitor, ReportSupport) | 100% | 100% | 0 | 3 | 0 | 7 | 0 | 1 | ||
findDependencies(String[]) | 100% | 100% | 0 | 4 | 0 | 10 | 0 | 1 | ||
loadExecutionData(ReportSupport, FileFilter, File) | 100% | 100% | 0 | 2 | 0 | 4 | 0 | 1 | ||
processProject(ReportSupport, IReportGroupVisitor, MavenProject) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
ReportAggregateMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
canGenerateReportRegardingDataFiles() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
canGenerateReportRegardingClassesDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputName() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getName(Locale) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * John Oliver, Marc R. Hoffmann, Jan Wloka - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; +import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; +import org.apache.maven.artifact.versioning.VersionRange; +import org.apache.maven.model.Dependency; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.jacoco.report.IReportGroupVisitor; + +/** + * <p> + * Creates a structured code coverage report (HTML, XML, and CSV) from multiple + * projects within reactor. The report is created from all modules this project + * depends on, and optionally this project itself. From those projects class and + * source files as well as JaCoCo execution data files will be collected. In + * addition execution data is collected from the project itself. This also + * allows to create coverage reports when tests are in separate projects than + * the code under test, for example in case of integration tests. + * </p> + * + * <p> + * Using the dependency scope allows to distinguish projects which contribute + * execution data but should not become part of the report: + * </p> + * + * <ul> + * <li><code>compile</code>, <code>runtime</code>, <code>provided</code>: + * Project source and execution data is included in the report.</li> + * <li><code>test</code>: Only execution data is considered for the report.</li> + * </ul> + * + * @since 0.7.7 + */ +@Mojo(name = "report-aggregate", threadSafe = true) +public class ReportAggregateMojo extends AbstractReportMojo { + + /** + * A list of execution data files to include in the report from each + * project. May use wildcard characters (* and ?). When not specified all + * *.exec files from the target folder will be included. + */ + @Parameter + List<String> dataFileIncludes; + + /** + * A list of execution data files to exclude from the report. May use + * wildcard characters (* and ?). When not specified nothing will be + * excluded. + */ + @Parameter + List<String> dataFileExcludes; + + /** + * Output directory for the reports. Note that this parameter is only + * relevant if the goal is run from the command line or from the default + * build lifecycle. If the goal is run indirectly as part of a site + * generation, the output directory configured in the Maven Site Plugin is + * used instead. + */ + @Parameter(defaultValue = "${project.reporting.outputDirectory}/jacoco-aggregate") + private File outputDirectory; + + /** + * Include this project in the report. If true then this projects class and + * source files as well as JaCoCo execution data files will be collected. + * + * @since 0.8.9 + */ + @Parameter(defaultValue = "false") + private boolean includeCurrentProject; + + /** + * The projects in the reactor. + */ + @Parameter(property = "reactorProjects", readonly = true) + private List<MavenProject> reactorProjects; + + @Override + boolean canGenerateReportRegardingDataFiles() { + return true; + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return true; + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + // https://issues.apache.org/jira/browse/MNG-5440 + if (dataFileIncludes == null) { + dataFileIncludes = Arrays.asList("target/*.exec"); + } + + final FileFilter filter = new FileFilter(dataFileIncludes, + dataFileExcludes); + loadExecutionData(support, filter, project.getBasedir()); + for (final MavenProject dependency : findDependencies( + Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, + Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST)) { + loadExecutionData(support, filter, dependency.getBasedir()); + } + } + + private void loadExecutionData(final ReportSupport support, + final FileFilter filter, final File basedir) throws IOException { + for (final File execFile : filter.getFiles(basedir)) { + support.loadExecutionData(execFile); + } + } + + @Override + File getOutputDirectory() { + return outputDirectory; + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + final IReportGroupVisitor group = visitor.visitGroup(title); + if (includeCurrentProject) { + processProject(support, group, project); + } + for (final MavenProject dependency : findDependencies( + Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, + Artifact.SCOPE_PROVIDED)) { + processProject(support, group, dependency); + } + } + + private void processProject(final ReportSupport support, + final IReportGroupVisitor group, final MavenProject project) + throws IOException { + support.processProject(group, project.getArtifactId(), project, + getIncludes(), getExcludes(), sourceEncoding); + } + + public File getReportOutputDirectory() { + return outputDirectory; + } + + public void setReportOutputDirectory(final File reportOutputDirectory) { + if (reportOutputDirectory != null && !reportOutputDirectory + .getAbsolutePath().endsWith("jacoco-aggregate")) { + outputDirectory = new File(reportOutputDirectory, + "jacoco-aggregate"); + } else { + outputDirectory = reportOutputDirectory; + } + } + + public String getOutputName() { + return "jacoco-aggregate/index"; + } + + public String getName(final Locale locale) { + return "JaCoCo Aggregate"; + } + + private List<MavenProject> findDependencies(final String... scopes) { + final List<MavenProject> result = new ArrayList<MavenProject>(); + final List<String> scopeList = Arrays.asList(scopes); + for (final Object dependencyObject : project.getDependencies()) { + final Dependency dependency = (Dependency) dependencyObject; + if (scopeList.contains(dependency.getScope())) { + final MavenProject project = findProjectFromReactor(dependency); + if (project != null) { + result.add(project); + } + } + } + return result; + } + + /** + * Note that if dependency specified using version range and reactor + * contains multiple modules with same artifactId and groupId but of + * different versions, then first dependency which matches range will be + * selected. For example in case of range <code>[0,2]</code> if version 1 is + * before version 2 in reactor, then version 1 will be selected. + */ + private MavenProject findProjectFromReactor(final Dependency d) { + final VersionRange depVersionAsRange; + try { + depVersionAsRange = VersionRange + .createFromVersionSpec(d.getVersion()); + } catch (final InvalidVersionSpecificationException e) { + throw new AssertionError(e); + } + + for (final MavenProject p : reactorProjects) { + final DefaultArtifactVersion pv = new DefaultArtifactVersion( + p.getVersion()); + if (p.getGroupId().equals(d.getGroupId()) + && p.getArtifactId().equals(d.getArtifactId()) + && depVersionAsRange.containsVersion(pv)) { + return p; + } + } + return null; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportFormat$1.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportFormat$1.html new file mode 100644 index 00000000000..6f759fa0538 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportFormat$1.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 4 of 32 | 87% | 1 of 2 | 50% | 1 | 3 | 1 | 8 | 0 | 2 |
createVisitor(AbstractReportMojo, Locale) | 84% | 50% | 1 | 2 | 1 | 7 | 0 | 1 | ||
{...} | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 26 | 100% | 0 of 0 | n/a | 0 | 2 | 0 | 5 | 0 | 2 |
createVisitor(AbstractReportMojo, Locale) | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
{...} | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 26 | 100% | 0 of 0 | n/a | 0 | 2 | 0 | 5 | 0 | 2 |
createVisitor(AbstractReportMojo, Locale) | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
{...} | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 0 of 21 | 100% | 0 of 0 | n/a | 0 | 1 | 0 | 4 | 0 | 1 |
static {...} | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Marc R. Hoffmann - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Locale; + +import org.jacoco.report.FileMultiReportOutput; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.csv.CSVFormatter; +import org.jacoco.report.html.HTMLFormatter; +import org.jacoco.report.xml.XMLFormatter; + +/** + * Configurable output formats for the report goals. + */ +public enum ReportFormat { + + /** + * Multi-page html report. + */ + HTML() { + @Override + IReportVisitor createVisitor(final AbstractReportMojo mojo, + final Locale locale) throws IOException { + final HTMLFormatter htmlFormatter = new HTMLFormatter(); + htmlFormatter.setOutputEncoding(mojo.outputEncoding); + htmlFormatter.setLocale(locale); + if (mojo.footer != null) { + htmlFormatter.setFooterText(mojo.footer); + } + return htmlFormatter.createVisitor( + new FileMultiReportOutput(mojo.getOutputDirectory())); + } + }, + + /** + * Single-file XML report. + */ + XML() { + @Override + IReportVisitor createVisitor(final AbstractReportMojo mojo, + final Locale locale) throws IOException { + final XMLFormatter xml = new XMLFormatter(); + xml.setOutputEncoding(mojo.outputEncoding); + return xml.createVisitor(new FileOutputStream( + new File(mojo.getOutputDirectory(), "jacoco.xml"))); + } + }, + + /** + * Single-file CSV report. + */ + CSV() { + @Override + IReportVisitor createVisitor(final AbstractReportMojo mojo, + final Locale locale) throws IOException { + final CSVFormatter csv = new CSVFormatter(); + csv.setOutputEncoding(mojo.outputEncoding); + return csv.createVisitor(new FileOutputStream( + new File(mojo.getOutputDirectory(), "jacoco.csv"))); + } + }; + + abstract IReportVisitor createVisitor(AbstractReportMojo mojo, + final Locale locale) throws IOException; + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportITMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportITMojo.html new file mode 100644 index 00000000000..372b4d1ea9f --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportITMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 6 of 64 | 90% | 2 of 4 | 50% | 3 | 12 | 2 | 17 | 1 | 10 |
setReportOutputDirectory(File) | 84% | 50% | 2 | 3 | 1 | 5 | 0 | 1 | ||
getReportOutputDirectory() | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 | ||
createReport(IReportGroupVisitor, ReportSupport) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
canGenerateReportRegardingClassesDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
loadExecutionData(ReportSupport) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
canGenerateReportRegardingDataFiles() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
ReportITMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputName() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getName(Locale) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.jacoco.report.IReportGroupVisitor; + +/** + * Same as <code>report</code>, but provides default values suitable for + * integration-tests: + * <ul> + * <li>bound to <code>report-integration</code> phase</li> + * <li>different <code>dataFile</code></li> + * </ul> + * + * @since 0.6.4 + */ +@Mojo(name = "report-integration", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) +public class ReportITMojo extends AbstractReportMojo { + + /** + * Output directory for the reports. Note that this parameter is only + * relevant if the goal is run from the command line or from the default + * build lifecycle. If the goal is run indirectly as part of a site + * generation, the output directory configured in the Maven Site Plugin is + * used instead. + */ + @Parameter(defaultValue = "${project.reporting.outputDirectory}/jacoco-it") + private File outputDirectory; + + /** + * File with execution data. + */ + @Parameter(defaultValue = "${project.build.directory}/jacoco-it.exec") + private File dataFile; + + @Override + boolean canGenerateReportRegardingDataFiles() { + return dataFile.exists(); + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return new File(project.getBuild().getOutputDirectory()).exists(); + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + support.loadExecutionData(dataFile); + } + + @Override + File getOutputDirectory() { + return outputDirectory; + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + support.processProject(visitor, title, project, getIncludes(), + getExcludes(), sourceEncoding); + } + + public File getReportOutputDirectory() { + return outputDirectory; + } + + public void setReportOutputDirectory(final File reportOutputDirectory) { + if (reportOutputDirectory != null && !reportOutputDirectory + .getAbsolutePath().endsWith("jacoco-it")) { + outputDirectory = new File(reportOutputDirectory, "jacoco-it"); + } else { + outputDirectory = reportOutputDirectory; + } + } + + public String getOutputName() { + return "jacoco-it/index"; + } + + public String getName(final Locale locale) { + return "JaCoCo IT"; + } +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportMojo.html new file mode 100644 index 00000000000..4929a33d71d --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 6 of 64 | 90% | 2 of 4 | 50% | 3 | 12 | 2 | 17 | 1 | 10 |
setReportOutputDirectory(File) | 84% | 50% | 2 | 3 | 1 | 5 | 0 | 1 | ||
getReportOutputDirectory() | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 | ||
createReport(IReportGroupVisitor, ReportSupport) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
canGenerateReportRegardingClassesDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
loadExecutionData(ReportSupport) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
canGenerateReportRegardingDataFiles() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
ReportMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputDirectory() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getOutputName() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 | ||
getName(Locale) | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.jacoco.report.IReportGroupVisitor; + +/** + * Creates a code coverage report for tests of a single project in multiple + * formats (HTML, XML, and CSV). + * + * @since 0.5.3 + */ +@Mojo(name = "report", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true) +public class ReportMojo extends AbstractReportMojo { + + /** + * Output directory for the reports. Note that this parameter is only + * relevant if the goal is run from the command line or from the default + * build lifecycle. If the goal is run indirectly as part of a site + * generation, the output directory configured in the Maven Site Plugin is + * used instead. + */ + @Parameter(defaultValue = "${project.reporting.outputDirectory}/jacoco") + private File outputDirectory; + + /** + * File with execution data. + */ + @Parameter(property = "jacoco.dataFile", defaultValue = "${project.build.directory}/jacoco.exec") + private File dataFile; + + @Override + boolean canGenerateReportRegardingDataFiles() { + return dataFile.exists(); + } + + @Override + boolean canGenerateReportRegardingClassesDirectory() { + return new File(project.getBuild().getOutputDirectory()).exists(); + } + + @Override + void loadExecutionData(final ReportSupport support) throws IOException { + support.loadExecutionData(dataFile); + } + + @Override + File getOutputDirectory() { + return outputDirectory; + } + + @Override + void createReport(final IReportGroupVisitor visitor, + final ReportSupport support) throws IOException { + support.processProject(visitor, title, project, getIncludes(), + getExcludes(), sourceEncoding); + } + + public File getReportOutputDirectory() { + return outputDirectory; + } + + public void setReportOutputDirectory(final File reportOutputDirectory) { + if (reportOutputDirectory != null && !reportOutputDirectory + .getAbsolutePath().endsWith("jacoco")) { + outputDirectory = new File(reportOutputDirectory, "jacoco"); + } else { + outputDirectory = reportOutputDirectory; + } + } + + public String getOutputName() { + return "jacoco/index"; + } + + public String getName(final Locale locale) { + return "JaCoCo"; + } +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportSupport$NoSourceLocator.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportSupport$NoSourceLocator.html new file mode 100644 index 00000000000..84e19a63a52 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/ReportSupport$NoSourceLocator.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 4 of 4 | 0% | 0 of 0 | n/a | 2 | 2 | 2 | 2 | 2 | 2 |
getSourceFile(String, String) | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 | ||
getTabWidth() | 0% | n/a | 1 | 1 | 1 | 1 | 1 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 3 of 65 | 95% | 3 of 8 | 62% | 3 | 7 | 2 | 14 | 0 | 3 |
getSourceFile(String, String) | 94% | 62% | 3 | 5 | 2 | 9 | 0 | 1 | ||
ReportSupport.SourceFileCollection(MavenProject, String) | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
getTabWidth() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 7 of 266 | 97% | 1 of 16 | 93% | 1 | 19 | 1 | 59 | 0 | 11 |
resolvePath(MavenProject, String) | 58% | 50% | 1 | 2 | 1 | 4 | 0 | 1 | ||
logBundleInfo(IBundleCoverage, Collection) | 100% | 100% | 0 | 5 | 0 | 14 | 0 | 1 | ||
processProject(IReportGroupVisitor, String, MavenProject, List, List, ISourceFileLocator) | 100% | 100% | 0 | 3 | 0 | 14 | 0 | 1 | ||
getCompileSourceRoots(MavenProject) | 100% | 100% | 0 | 2 | 0 | 5 | 0 | 1 | ||
initRootVisitor() | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
ReportSupport(Log) | 100% | n/a | 0 | 1 | 0 | 5 | 0 | 1 | ||
loadExecutionData(File) | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
addRulesChecker(List, IViolationsOutput) | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | ||
processProject(IReportGroupVisitor, MavenProject, List, List) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
processProject(IReportGroupVisitor, String, MavenProject, List, List, String) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
addVisitor(IReportVisitor) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * + *******************************************************************************/ +package org.jacoco.maven; + +import static java.lang.String.format; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.maven.plugin.logging.Log; +import org.apache.maven.project.MavenProject; +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.tools.ExecFileLoader; +import org.jacoco.report.IReportGroupVisitor; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.ISourceFileLocator; +import org.jacoco.report.MultiReportVisitor; +import org.jacoco.report.check.IViolationsOutput; +import org.jacoco.report.check.Rule; +import org.jacoco.report.check.RulesChecker; + +/** + * Encapsulates the tasks to create reports for Maven projects. Instances are + * supposed to be used in the following sequence: + * + * <ol> + * <li>Create an instance</li> + * <li>Load one or multiple exec files with + * <code>loadExecutionData()</code></li> + * <li>Add one or multiple formatters with <code>addXXX()</code> methods</li> + * <li>Create the root visitor with <code>initRootVisitor()</code></li> + * <li>Process one or multiple projects with <code>processProject()</code></li> + * </ol> + */ +final class ReportSupport { + + private final Log log; + private final ExecFileLoader loader; + private final List<IReportVisitor> formatters; + + /** + * Construct a new instance with the given log output. + * + * @param log + * for log output + */ + public ReportSupport(final Log log) { + this.log = log; + this.loader = new ExecFileLoader(); + this.formatters = new ArrayList<IReportVisitor>(); + } + + /** + * Loads the given execution data file. + * + * @param execFile + * execution data file to load + * @throws IOException + * if the file can't be loaded + */ + public void loadExecutionData(final File execFile) throws IOException { + log.info("Loading execution data file " + execFile); + loader.load(execFile); + } + + public void addVisitor(final IReportVisitor visitor) { + formatters.add(visitor); + } + + public void addRulesChecker(final List<Rule> rules, + final IViolationsOutput output) { + final RulesChecker checker = new RulesChecker(); + checker.setRules(rules); + formatters.add(checker.createVisitor(output)); + } + + public IReportVisitor initRootVisitor() throws IOException { + final IReportVisitor visitor = new MultiReportVisitor(formatters); + visitor.visitInfo(loader.getSessionInfoStore().getInfos(), + loader.getExecutionDataStore().getContents()); + return visitor; + } + + /** + * Calculates coverage for the given project and emits it to the report + * group without source references + * + * @param visitor + * group visitor to emit the project's coverage to + * @param project + * the MavenProject + * @param includes + * list of includes patterns + * @param excludes + * list of excludes patterns + * @throws IOException + * if class files can't be read + */ + public void processProject(final IReportGroupVisitor visitor, + final MavenProject project, final List<String> includes, + final List<String> excludes) throws IOException { + processProject(visitor, project.getArtifactId(), project, includes, + excludes, new NoSourceLocator()); + } + + /** + * Calculates coverage for the given project and emits it to the report + * group including source references + * + * @param visitor + * group visitor to emit the project's coverage to + * @param bundleName + * name for this project in the report + * @param project + * the MavenProject + * @param includes + * list of includes patterns + * @param excludes + * list of excludes patterns + * @param srcEncoding + * encoding of the source files within this project + * @throws IOException + * if class files can't be read + */ + public void processProject(final IReportGroupVisitor visitor, + final String bundleName, final MavenProject project, + final List<String> includes, final List<String> excludes, + final String srcEncoding) throws IOException { + processProject(visitor, bundleName, project, includes, excludes, + new SourceFileCollection(project, srcEncoding)); + } + + private void processProject(final IReportGroupVisitor visitor, + final String bundleName, final MavenProject project, + final List<String> includes, final List<String> excludes, + final ISourceFileLocator locator) throws IOException { + final CoverageBuilder builder = new CoverageBuilder(); + final File classesDir = new File( + project.getBuild().getOutputDirectory()); + + if (classesDir.isDirectory()) { + final Analyzer analyzer = new Analyzer( + loader.getExecutionDataStore(), builder); + final FileFilter filter = new FileFilter(includes, excludes); + for (final File file : filter.getFiles(classesDir)) { + analyzer.analyzeAll(file); + } + } + + final IBundleCoverage bundle = builder.getBundle(bundleName); + logBundleInfo(bundle, builder.getNoMatchClasses()); + + visitor.visitBundle(bundle, locator); + } + + private void logBundleInfo(final IBundleCoverage bundle, + final Collection<IClassCoverage> nomatch) { + log.info(format("Analyzed bundle '%s' with %s classes", + bundle.getName(), + Integer.valueOf(bundle.getClassCounter().getTotalCount()))); + if (!nomatch.isEmpty()) { + log.warn(format( + "Classes in bundle '%s' do not match with execution data. " + + "For report generation the same class files must be used as at runtime.", + bundle.getName())); + for (final IClassCoverage c : nomatch) { + log.warn(format("Execution data for class %s does not match.", + c.getName())); + } + } + if (bundle.containsCode() + && bundle.getLineCounter().getTotalCount() == 0) { + log.warn( + "To enable source code annotation class files have to be compiled with debug information."); + } + } + + private static class NoSourceLocator implements ISourceFileLocator { + + public Reader getSourceFile(final String packageName, + final String fileName) { + return null; + } + + public int getTabWidth() { + return 0; + } + } + + private static class SourceFileCollection implements ISourceFileLocator { + + private final List<File> sourceRoots; + private final String encoding; + + public SourceFileCollection(final MavenProject project, + final String encoding) { + this.sourceRoots = getCompileSourceRoots(project); + this.encoding = encoding; + } + + public Reader getSourceFile(final String packageName, + final String fileName) throws IOException { + final String r; + if (packageName.length() > 0) { + r = packageName + '/' + fileName; + } else { + r = fileName; + } + for (final File sourceRoot : sourceRoots) { + final File file = new File(sourceRoot, r); + if (file.exists() && file.isFile()) { + return new InputStreamReader(new FileInputStream(file), + encoding); + } + } + return null; + } + + public int getTabWidth() { + return 4; + } + } + + private static List<File> getCompileSourceRoots( + final MavenProject project) { + final List<File> result = new ArrayList<File>(); + for (final Object path : project.getCompileSourceRoots()) { + result.add(resolvePath(project, (String) path)); + } + return result; + } + + private static File resolvePath(final MavenProject project, + final String path) { + File file = new File(path); + if (!file.isAbsolute()) { + file = new File(project.getBasedir(), path); + } + return file; + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RestoreMojo.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RestoreMojo.html new file mode 100644 index 00000000000..df1b4535470 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RestoreMojo.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 7 of 32 | 78% | 0 of 0 | n/a | 0 | 2 | 2 | 10 | 0 | 2 |
executeMojo() | 75% | n/a | 0 | 1 | 2 | 9 | 0 | 1 | ||
RestoreMojo() | 100% | n/a | 0 | 1 | 0 | 1 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.io.File; +import java.io.IOException; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.codehaus.plexus.util.FileUtils; + +/** + * Restores original classes as they were before offline instrumentation. + * + * @since 0.6.2 + */ +@Mojo(name = "restore-instrumented-classes", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, threadSafe = true) +public class RestoreMojo extends AbstractJacocoMojo { + + @Override + protected void executeMojo() + throws MojoExecutionException, MojoFailureException { + final File originalClassesDir = new File( + getProject().getBuild().getDirectory(), + "generated-classes/jacoco"); + final File classesDir = new File( + getProject().getBuild().getOutputDirectory()); + try { + FileUtils.copyDirectoryStructure(originalClassesDir, classesDir); + } catch (final IOException e) { + throw new MojoFailureException("Unable to restore classes.", e); + } + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RuleConfiguration.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RuleConfiguration.html new file mode 100644 index 00000000000..497ad650421 --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/RuleConfiguration.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods |
Total | 8 of 35 | 77% | 0 of 0 | n/a | 1 | 5 | 2 | 11 | 1 | 5 |
setExcludes(List) | 0% | n/a | 1 | 1 | 2 | 2 | 1 | 1 | ||
RuleConfiguration() | 100% | n/a | 0 | 1 | 0 | 3 | 0 | 1 | ||
setIncludes(List) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
setElement(String) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 | ||
setLimits(List) | 100% | n/a | 0 | 1 | 0 | 2 | 0 | 1 |
/******************************************************************************* + * Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors + * This program and the accompanying materials are made available under + * the terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * Kyle Lieber - implementation of CheckMojo + * Marc Hoffmann - redesign using report APIs + * + *******************************************************************************/ +package org.jacoco.maven; + +import java.util.List; + +import org.codehaus.plexus.util.StringUtils; +import org.jacoco.core.analysis.ICoverageNode.ElementType; +import org.jacoco.report.check.Limit; +import org.jacoco.report.check.Rule; + +/** + * Wrapper for {@link Rule} objects to allow Maven style includes/excludes lists + * + */ +public class RuleConfiguration { + + final Rule rule; + + /** + * Create a new configuration instance. + */ + public RuleConfiguration() { + rule = new Rule(); + } + + /** + * @param element + * element type this rule applies to TODO: use ElementType + * directly once Maven 3 is required. + */ + public void setElement(final String element) { + rule.setElement(ElementType.valueOf(element)); + } + + /** + * @param includes + * includes patterns + */ + public void setIncludes(final List<String> includes) { + rule.setIncludes(StringUtils.join(includes.iterator(), ":")); + } + + /** + * + * @param excludes + * excludes patterns + */ + public void setExcludes(final List<String> excludes) { + rule.setExcludes(StringUtils.join(excludes.iterator(), ":")); + } + + /** + * @param limits + * list of {@link Limit}s configured for this rule + */ + public void setLimits(final List<Limit> limits) { + rule.setLimits(limits); + } + +} +\ No newline at end of file diff --git a/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/index.html b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/index.html new file mode 100644 index 00000000000..a8d784e14bb --- /dev/null +++ b/jacoco/trunk/coverage/jacoco-maven-plugin/org.jacoco.maven/index.html @@ -0,0 +1 @@ +
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods | Missed | Classes |
Total | 175 of 1,894 | 90% | 27 of 154 | 82% | 35 | 193 | 49 | 465 | 8 | 116 | 1 | 23 |
MergeMojo | 72% | 64% | 5 | 13 | 12 | 40 | 0 | 6 | 0 | 1 | ||
CheckMojo | 71% | 75% | 3 | 11 | 8 | 38 | 0 | 5 | 0 | 1 | ||
InstrumentMojo | 88% | 83% | 1 | 5 | 4 | 31 | 0 | 2 | 0 | 1 | ||
ReportAggregateMojo | 95% | 92% | 3 | 28 | 4 | 58 | 1 | 14 | 0 | 1 | ||
RuleConfiguration | 77% | n/a | 1 | 5 | 2 | 11 | 1 | 5 | 0 | 1 | ||
ReportSupport | 97% | 93% | 1 | 19 | 1 | 59 | 0 | 11 | 0 | 1 | ||
AbstractReportMojo | 95% | 91% | 2 | 18 | 3 | 46 | 1 | 12 | 0 | 1 | ||
DumpMojo | 87% | 50% | 1 | 3 | 2 | 14 | 0 | 2 | 0 | 1 | ||
RestoreMojo | 78% | n/a | 0 | 2 | 2 | 10 | 0 | 2 | 0 | 1 | ||
ReportITMojo | 90% | 50% | 3 | 12 | 2 | 17 | 1 | 10 | 0 | 1 | ||
ReportMojo | 90% | 50% | 3 | 12 | 2 | 17 | 1 | 10 | 0 | 1 | ||
ReportFormat.new ReportFormat() {...} | 87% | 50% | 1 | 3 | 1 | 8 | 0 | 2 | 0 | 1 | ||
ReportSupport.NoSourceLocator | 0% | n/a | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | ||
ReportSupport.SourceFileCollection | 95% | 62% | 3 | 7 | 2 | 14 | 0 | 3 | 0 | 1 | ||
AbstractAgentMojo | 99% | 90% | 4 | 28 | 1 | 59 | 0 | 8 | 0 | 1 | ||
AbstractJacocoMojo | 95% | 100% | 1 | 5 | 1 | 9 | 1 | 4 | 0 | 1 | ||
FileFilter | 100% | 75% | 1 | 8 | 0 | 12 | 0 | 6 | 0 | 1 | ||
DumpMojo.new ExecDumpClient() {...} | 100% | n/a | 0 | 3 | 0 | 6 | 0 | 3 | 0 | 1 | ||
ReportFormat.new ReportFormat() {...} | 100% | n/a | 0 | 2 | 0 | 5 | 0 | 2 | 0 | 1 | ||
ReportFormat.new ReportFormat() {...} | 100% | n/a | 0 | 2 | 0 | 5 | 0 | 2 | 0 | 1 | ||
ReportFormat | 100% | n/a | 0 | 1 | 0 | 4 | 0 | 1 | 0 | 1 | ||
AgentMojo | 100% | n/a | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 1 | ||
AgentITMojo | 100% | n/a | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 1 |
Element | Missed Instructions | Cov. | Missed Branches | Cov. | Missed | Cxty | Missed | Lines | Missed | Methods | Missed | Classes |
Total | 175 of 1,894 | 90% | 27 of 154 | 82% | 35 | 193 | 49 | 465 | 8 | 116 | 1 | 23 |
MergeMojo.java | 72% | 64% | 5 | 13 | 12 | 40 | 0 | 6 | 0 | 1 | ||
CheckMojo.java | 71% | 75% | 3 | 11 | 8 | 38 | 0 | 5 | 0 | 1 | ||
ReportSupport.java | 95% | 83% | 6 | 28 | 5 | 75 | 2 | 16 | 1 | 3 | ||
InstrumentMojo.java | 88% | 83% | 1 | 5 | 4 | 31 | 0 | 2 | 0 | 1 | ||
ReportAggregateMojo.java | 95% | 92% | 3 | 28 | 4 | 58 | 1 | 14 | 0 | 1 | ||
RuleConfiguration.java | 77% | n/a | 1 | 5 | 2 | 11 | 1 | 5 | 0 | 1 | ||
AbstractReportMojo.java | 95% | 91% | 2 | 18 | 3 | 46 | 1 | 12 | 0 | 1 | ||
DumpMojo.java | 92% | 50% | 1 | 6 | 2 | 19 | 0 | 5 | 0 | 2 | ||
RestoreMojo.java | 78% | n/a | 0 | 2 | 2 | 10 | 0 | 2 | 0 | 1 | ||
ReportITMojo.java | 90% | 50% | 3 | 12 | 2 | 17 | 1 | 10 | 0 | 1 | ||
ReportMojo.java | 90% | 50% | 3 | 12 | 2 | 17 | 1 | 10 | 0 | 1 | ||
ReportFormat.java | 96% | 50% | 1 | 8 | 1 | 19 | 0 | 7 | 0 | 4 | ||
AbstractAgentMojo.java | 99% | 90% | 4 | 28 | 1 | 59 | 0 | 8 | 0 | 1 | ||
AbstractJacocoMojo.java | 95% | 100% | 1 | 5 | 1 | 9 | 1 | 4 | 0 | 1 | ||
FileFilter.java | 100% | 75% | 1 | 8 | 0 | 12 | 0 | 6 | 0 | 1 | ||
AgentMojo.java | 100% | n/a | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 1 | ||
AgentITMojo.java | 100% | n/a | 0 | 2 | 0 | 2 | 0 | 2 | 0 | 1 |
+ * + * For a fairly comprehensive set of languages see the + * README + * file that came with this source. At a minimum, the lexer should work on a + * number of languages including C and friends, Java, Python, Bash, SQL, HTML, + * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk + * and a subset of Perl, but, because of commenting conventions, doesn't work on + * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. + *
+ * Usage:
} and {@code } tags in your source with
+ * {@code class=prettyprint.}
+ * You can also use the (html deprecated) {@code } tag, but the pretty
+ * printer needs to do more substantial DOM manipulations to support that, so
+ * some css styles may not be preserved.
+ *
} or {@code } element to specify the
+ * language, as in {@code }. Any class that
+ * starts with "lang-" followed by a file extension, specifies the file type.
+ * See the "lang-*.js" files in this directory for code that implements
+ * per-language file handlers.
+ *
+ * Change log:
+ * cbeust, 2006/08/22
+ *
+ * Java annotations (start with "@") are now captured as literals ("lit")
+ *
+ * @requires console
+ */
+
+// JSLint declarations
+/*global console, document, navigator, setTimeout, window */
+
+/**
+ * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
+ * UI events.
+ * If set to {@code false}, {@code prettyPrint()} is synchronous.
+ */
+window['PR_SHOULD_USE_CONTINUATION'] = true;
+
+/** the number of characters between tab columns */
+window['PR_TAB_WIDTH'] = 8;
+
+/** Walks the DOM returning a properly escaped version of innerHTML.
+ * @param {Node} node
+ * @param {Array.} out output buffer that receives chunks of HTML.
+ */
+window['PR_normalizedHtml']
+
+/** Contains functions for creating and registering new language handlers.
+ * @type {Object}
+ */
+ = window['PR']
+
+/** Pretty print a chunk of code.
+ *
+ * @param {string} sourceCodeHtml code as html
+ * @return {string} code as html, but prettier
+ */
+ = window['prettyPrintOne']
+/** Find all the {@code } and {@code } tags in the DOM with
+ * {@code class=prettyprint} and prettify them.
+ * @param {Function?} opt_whenDone if specified, called when the last entry
+ * has been finished.
+ */
+ = window['prettyPrint'] = void 0;
+
+/** browser detection. @extern @returns false if not IE, otherwise the major version. */
+window['_pr_isIE6'] = function () {
+ var ieVersion = navigator && navigator.userAgent &&
+ navigator.userAgent.match(/\bMSIE ([678])\./);
+ ieVersion = ieVersion ? +ieVersion[1] : false;
+ window['_pr_isIE6'] = function () { return ieVersion; };
+ return ieVersion;
+};
+
+
+(function () {
+ // Keyword lists for various languages.
+ var FLOW_CONTROL_KEYWORDS =
+ "break continue do else for if return while ";
+ var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
+ "double enum extern float goto int long register short signed sizeof " +
+ "static struct switch typedef union unsigned void volatile ";
+ var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
+ "new operator private protected public this throw true try typeof ";
+ var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
+ "concept concept_map const_cast constexpr decltype " +
+ "dynamic_cast explicit export friend inline late_check " +
+ "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
+ "template typeid typename using virtual wchar_t where ";
+ var JAVA_KEYWORDS = COMMON_KEYWORDS +
+ "abstract boolean byte extends final finally implements import " +
+ "instanceof null native package strictfp super synchronized throws " +
+ "transient ";
+ var CSHARP_KEYWORDS = JAVA_KEYWORDS +
+ "as base by checked decimal delegate descending event " +
+ "fixed foreach from group implicit in interface internal into is lock " +
+ "object out override orderby params partial readonly ref sbyte sealed " +
+ "stackalloc string select uint ulong unchecked unsafe ushort var ";
+ var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
+ "debugger eval export function get null set undefined var with " +
+ "Infinity NaN ";
+ var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
+ "goto if import last local my next no our print package redo require " +
+ "sub undef unless until use wantarray while BEGIN END ";
+ var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
+ "elif except exec finally from global import in is lambda " +
+ "nonlocal not or pass print raise try with yield " +
+ "False True None ";
+ var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
+ " defined elsif end ensure false in module next nil not or redo rescue " +
+ "retry self super then true undef unless until when yield BEGIN END ";
+ var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
+ "function in local set then until ";
+ var ALL_KEYWORDS = (
+ CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
+ PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
+
+ // token style names. correspond to css classes
+ /** token style for a string literal */
+ var PR_STRING = 'str';
+ /** token style for a keyword */
+ var PR_KEYWORD = 'kwd';
+ /** token style for a comment */
+ var PR_COMMENT = 'com';
+ /** token style for a type */
+ var PR_TYPE = 'typ';
+ /** token style for a literal value. e.g. 1, null, true. */
+ var PR_LITERAL = 'lit';
+ /** token style for a punctuation string. */
+ var PR_PUNCTUATION = 'pun';
+ /** token style for a punctuation string. */
+ var PR_PLAIN = 'pln';
+
+ /** token style for an sgml tag. */
+ var PR_TAG = 'tag';
+ /** token style for a markup declaration such as a DOCTYPE. */
+ var PR_DECLARATION = 'dec';
+ /** token style for embedded source. */
+ var PR_SOURCE = 'src';
+ /** token style for an sgml attribute name. */
+ var PR_ATTRIB_NAME = 'atn';
+ /** token style for an sgml attribute value. */
+ var PR_ATTRIB_VALUE = 'atv';
+
+ /**
+ * A class that indicates a section of markup that is not code, e.g. to allow
+ * embedding of line numbers within code listings.
+ */
+ var PR_NOCODE = 'nocode';
+
+ /** A set of tokens that can precede a regular expression literal in
+ * javascript.
+ * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
+ * list, but I've removed ones that might be problematic when seen in
+ * languages that don't support regular expression literals.
+ *
+ * Specifically, I've removed any keywords that can't precede a regexp
+ * literal in a syntactically legal javascript program, and I've removed the
+ * "in" keyword since it's not a keyword in many languages, and might be used
+ * as a count of inches.
+ *
+ *
The link a above does not accurately describe EcmaScript rules since
+ * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
+ * very well in practice.
+ *
+ * @private
+ */
+ var REGEXP_PRECEDER_PATTERN = function () {
+ var preceders = [
+ "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
+ "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
+ "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
+ "<", "<<", "<<=", "<=", "=", "==", "===", ">",
+ ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
+ "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
+ "||=", "~" /* handles =~ and !~ */,
+ "break", "case", "continue", "delete",
+ "do", "else", "finally", "instanceof",
+ "return", "throw", "try", "typeof"
+ ];
+ var pattern = '(?:^^|[+-]';
+ for (var i = 0; i < preceders.length; ++i) {
+ pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
+ }
+ pattern += ')\\s*'; // matches at end, and matches empty string
+ return pattern;
+ // CAVEAT: this does not properly handle the case where a regular
+ // expression immediately follows another since a regular expression may
+ // have flags for case-sensitivity and the like. Having regexp tokens
+ // adjacent is not valid in any language I'm aware of, so I'm punting.
+ // TODO: maybe style special characters inside a regexp as punctuation.
+ }();
+
+ // Define regexps here so that the interpreter doesn't have to create an
+ // object each time the function containing them is called.
+ // The language spec requires a new object created even if you don't access
+ // the $1 members.
+ var pr_amp = /&/g;
+ var pr_lt = //g;
+ var pr_quot = /\"/g;
+ /** like textToHtml but escapes double quotes to be attribute safe. */
+ function attribToHtml(str) {
+ return str.replace(pr_amp, '&')
+ .replace(pr_lt, '<')
+ .replace(pr_gt, '>')
+ .replace(pr_quot, '"');
+ }
+
+ /** escapest html special characters to html. */
+ function textToHtml(str) {
+ return str.replace(pr_amp, '&')
+ .replace(pr_lt, '<')
+ .replace(pr_gt, '>');
+ }
+
+
+ var pr_ltEnt = /</g;
+ var pr_gtEnt = />/g;
+ var pr_aposEnt = /'/g;
+ var pr_quotEnt = /"/g;
+ var pr_ampEnt = /&/g;
+ var pr_nbspEnt = / /g;
+ /** unescapes html to plain text. */
+ function htmlToText(html) {
+ var pos = html.indexOf('&');
+ if (pos < 0) { return html; }
+ // Handle numeric entities specially. We can't use functional substitution
+ // since that doesn't work in older versions of Safari.
+ // These should be rare since most browsers convert them to normal chars.
+ for (--pos; (pos = html.indexOf('', pos + 1)) >= 0;) {
+ var end = html.indexOf(';', pos);
+ if (end >= 0) {
+ var num = html.substring(pos + 3, end);
+ var radix = 10;
+ if (num && num.charAt(0) === 'x') {
+ num = num.substring(1);
+ radix = 16;
+ }
+ var codePoint = parseInt(num, radix);
+ if (!isNaN(codePoint)) {
+ html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
+ html.substring(end + 1));
+ }
+ }
+ }
+
+ return html.replace(pr_ltEnt, '<')
+ .replace(pr_gtEnt, '>')
+ .replace(pr_aposEnt, "'")
+ .replace(pr_quotEnt, '"')
+ .replace(pr_nbspEnt, ' ')
+ .replace(pr_ampEnt, '&');
+ }
+
+ /** is the given node's innerHTML normally unescaped? */
+ function isRawContent(node) {
+ return 'XMP' === node.tagName;
+ }
+
+ var newlineRe = /[\r\n]/g;
+ /**
+ * Are newlines and adjacent spaces significant in the given node's innerHTML?
+ */
+ function isPreformatted(node, content) {
+ // PRE means preformatted, and is a very common case, so don't create
+ // unnecessary computed style objects.
+ if ('PRE' === node.tagName) { return true; }
+ if (!newlineRe.test(content)) { return true; } // Don't care
+ var whitespace = '';
+ // For disconnected nodes, IE has no currentStyle.
+ if (node.currentStyle) {
+ whitespace = node.currentStyle.whiteSpace;
+ } else if (window.getComputedStyle) {
+ // Firefox makes a best guess if node is disconnected whereas Safari
+ // returns the empty string.
+ whitespace = window.getComputedStyle(node, null).whiteSpace;
+ }
+ return !whitespace || whitespace === 'pre';
+ }
+
+ function normalizedHtml(node, out, opt_sortAttrs) {
+ switch (node.nodeType) {
+ case 1: // an element
+ var name = node.tagName.toLowerCase();
+
+ out.push('<', name);
+ var attrs = node.attributes;
+ var n = attrs.length;
+ if (n) {
+ if (opt_sortAttrs) {
+ var sortedAttrs = [];
+ for (var i = n; --i >= 0;) { sortedAttrs[i] = attrs[i]; }
+ sortedAttrs.sort(function (a, b) {
+ return (a.name < b.name) ? -1 : a.name === b.name ? 0 : 1;
+ });
+ attrs = sortedAttrs;
+ }
+ for (var i = 0; i < n; ++i) {
+ var attr = attrs[i];
+ if (!attr.specified) { continue; }
+ out.push(' ', attr.name.toLowerCase(),
+ '="', attribToHtml(attr.value), '"');
+ }
+ }
+ out.push('>');
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ normalizedHtml(child, out, opt_sortAttrs);
+ }
+ if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
+ out.push('<\/', name, '>');
+ }
+ break;
+ case 3: case 4: // text
+ out.push(textToHtml(node.nodeValue));
+ break;
+ }
+ }
+
+ /**
+ * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
+ * matches the union o the sets o strings matched d by the input RegExp.
+ * Since it matches globally, if the input strings have a start-of-input
+ * anchor (/^.../), it is ignored for the purposes of unioning.
+ * @param {Array.} regexs non multiline, non-global regexs.
+ * @return {RegExp} a global regex.
+ */
+ function combinePrefixPatterns(regexs) {
+ var capturedGroupIndex = 0;
+
+ var needToFoldCase = false;
+ var ignoreCase = false;
+ for (var i = 0, n = regexs.length; i < n; ++i) {
+ var regex = regexs[i];
+ if (regex.ignoreCase) {
+ ignoreCase = true;
+ } else if (/[a-z]/i.test(regex.source.replace(
+ /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
+ needToFoldCase = true;
+ ignoreCase = false;
+ break;
+ }
+ }
+
+ function decodeEscape(charsetPart) {
+ if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
+ switch (charsetPart.charAt(1)) {
+ case 'b': return 8;
+ case 't': return 9;
+ case 'n': return 0xa;
+ case 'v': return 0xb;
+ case 'f': return 0xc;
+ case 'r': return 0xd;
+ case 'u': case 'x':
+ return parseInt(charsetPart.substring(2), 16)
+ || charsetPart.charCodeAt(1);
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ return parseInt(charsetPart.substring(1), 8);
+ default: return charsetPart.charCodeAt(1);
+ }
+ }
+
+ function encodeEscape(charCode) {
+ if (charCode < 0x20) {
+ return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
+ }
+ var ch = String.fromCharCode(charCode);
+ if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
+ ch = '\\' + ch;
+ }
+ return ch;
+ }
+
+ function caseFoldCharset(charSet) {
+ var charsetParts = charSet.substring(1, charSet.length - 1).match(
+ new RegExp(
+ '\\\\u[0-9A-Fa-f]{4}'
+ + '|\\\\x[0-9A-Fa-f]{2}'
+ + '|\\\\[0-3][0-7]{0,2}'
+ + '|\\\\[0-7]{1,2}'
+ + '|\\\\[\\s\\S]'
+ + '|-'
+ + '|[^-\\\\]',
+ 'g'));
+ var groups = [];
+ var ranges = [];
+ var inverse = charsetParts[0] === '^';
+ for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
+ var p = charsetParts[i];
+ switch (p) {
+ case '\\B': case '\\b':
+ case '\\D': case '\\d':
+ case '\\S': case '\\s':
+ case '\\W': case '\\w':
+ groups.push(p);
+ continue;
+ }
+ var start = decodeEscape(p);
+ var end;
+ if (i + 2 < n && '-' === charsetParts[i + 1]) {
+ end = decodeEscape(charsetParts[i + 2]);
+ i += 2;
+ } else {
+ end = start;
+ }
+ ranges.push([start, end]);
+ // If the range might intersect letters, then expand it.
+ if (!(end < 65 || start > 122)) {
+ if (!(end < 65 || start > 90)) {
+ ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
+ }
+ if (!(end < 97 || start > 122)) {
+ ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
+ }
+ }
+ }
+
+ // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
+ // -> [[1, 12], [14, 14], [16, 17]]
+ ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); });
+ var consolidatedRanges = [];
+ var lastRange = [NaN, NaN];
+ for (var i = 0; i < ranges.length; ++i) {
+ var range = ranges[i];
+ if (range[0] <= lastRange[1] + 1) {
+ lastRange[1] = Math.max(lastRange[1], range[1]);
+ } else {
+ consolidatedRanges.push(lastRange = range);
+ }
+ }
+
+ var out = ['['];
+ if (inverse) { out.push('^'); }
+ out.push.apply(out, groups);
+ for (var i = 0; i < consolidatedRanges.length; ++i) {
+ var range = consolidatedRanges[i];
+ out.push(encodeEscape(range[0]));
+ if (range[1] > range[0]) {
+ if (range[1] + 1 > range[0]) { out.push('-'); }
+ out.push(encodeEscape(range[1]));
+ }
+ }
+ out.push(']');
+ return out.join('');
+ }
+
+ function allowAnywhereFoldCaseAndRenumberGroups(regex) {
+ // Split into character sets, escape sequences, punctuation strings
+ // like ('(', '(?:', ')', '^'), and runs of characters that do not
+ // include any of the above.
+ var parts = regex.source.match(
+ new RegExp(
+ '(?:'
+ + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set
+ + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape
+ + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape
+ + '|\\\\[0-9]+' // a back-reference or octal escape
+ + '|\\\\[^ux0-9]' // other escape sequence
+ + '|\\(\\?[:!=]' // start of a non-capturing group
+ + '|[\\(\\)\\^]' // start/emd of a group, or line start
+ + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters
+ + ')',
+ 'g'));
+ var n = parts.length;
+
+ // Maps captured group numbers to the number they will occupy in
+ // the output or to -1 if that has not been determined, or to
+ // undefined if they need not be capturing in the output.
+ var capturedGroups = [];
+
+ // Walk over and identify back references to build the capturedGroups
+ // mapping.
+ for (var i = 0, groupIndex = 0; i < n; ++i) {
+ var p = parts[i];
+ if (p === '(') {
+ // groups are 1-indexed, so max group index is count of '('
+ ++groupIndex;
+ } else if ('\\' === p.charAt(0)) {
+ var decimalValue = +p.substring(1);
+ if (decimalValue && decimalValue <= groupIndex) {
+ capturedGroups[decimalValue] = -1;
+ }
+ }
+ }
+
+ // Renumber groups and reduce capturing groups to non-capturing groups
+ // where possible.
+ for (var i = 1; i < capturedGroups.length; ++i) {
+ if (-1 === capturedGroups[i]) {
+ capturedGroups[i] = ++capturedGroupIndex;
+ }
+ }
+ for (var i = 0, groupIndex = 0; i < n; ++i) {
+ var p = parts[i];
+ if (p === '(') {
+ ++groupIndex;
+ if (capturedGroups[groupIndex] === undefined) {
+ parts[i] = '(?:';
+ }
+ } else if ('\\' === p.charAt(0)) {
+ var decimalValue = +p.substring(1);
+ if (decimalValue && decimalValue <= groupIndex) {
+ parts[i] = '\\' + capturedGroups[groupIndex];
+ }
+ }
+ }
+
+ // Remove any prefix anchors so that the output will match anywhere.
+ // ^^ really does mean an anchored match though.
+ for (var i = 0, groupIndex = 0; i < n; ++i) {
+ if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
+ }
+
+ // Expand letters to groupts to handle mixing of case-sensitive and
+ // case-insensitive patterns if necessary.
+ if (regex.ignoreCase && needToFoldCase) {
+ for (var i = 0; i < n; ++i) {
+ var p = parts[i];
+ var ch0 = p.charAt(0);
+ if (p.length >= 2 && ch0 === '[') {
+ parts[i] = caseFoldCharset(p);
+ } else if (ch0 !== '\\') {
+ // TODO: handle letters in numeric escapes.
+ parts[i] = p.replace(
+ /[a-zA-Z]/g,
+ function (ch) {
+ var cc = ch.charCodeAt(0);
+ return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
+ });
+ }
+ }
+ }
+
+ return parts.join('');
+ }
+
+ var rewritten = [];
+ for (var i = 0, n = regexs.length; i < n; ++i) {
+ var regex = regexs[i];
+ if (regex.global || regex.multiline) { throw new Error('' + regex); }
+ rewritten.push(
+ '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
+ }
+
+ return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
+ }
+
+ var PR_innerHtmlWorks = null;
+ function getInnerHtml(node) {
+ // inner html is hopelessly broken in Safari 2.0.4 when the content is
+ // an html description of well formed XML and the containing tag is a PRE
+ // tag, so we detect that case and emulate innerHTML.
+ if (null === PR_innerHtmlWorks) {
+ var testNode = document.createElement('PRE');
+ testNode.appendChild(
+ document.createTextNode('\n '));
+ PR_innerHtmlWorks = !/)[\r\n]+/g, '$1')
+ .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
+ }
+ return content;
+ }
+
+ var out = [];
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ normalizedHtml(child, out);
+ }
+ return out.join('');
+ }
+
+ /** returns a function that expand tabs to spaces. This function can be fed
+ * successive chunks of text, and will maintain its own internal state to
+ * keep track of how tabs are expanded.
+ * @return {function (string) : string} a function that takes
+ * plain text and return the text with tabs expanded.
+ * @private
+ */
+ function makeTabExpander(tabWidth) {
+ var SPACES = ' ';
+ var charInLine = 0;
+
+ return function (plainText) {
+ // walk over each character looking for tabs and newlines.
+ // On tabs, expand them. On newlines, reset charInLine.
+ // Otherwise increment charInLine
+ var out = null;
+ var pos = 0;
+ for (var i = 0, n = plainText.length; i < n; ++i) {
+ var ch = plainText.charAt(i);
+
+ switch (ch) {
+ case '\t':
+ if (!out) { out = []; }
+ out.push(plainText.substring(pos, i));
+ // calculate how much space we need in front of this part
+ // nSpaces is the amount of padding -- the number of spaces needed
+ // to move us to the next column, where columns occur at factors of
+ // tabWidth.
+ var nSpaces = tabWidth - (charInLine % tabWidth);
+ charInLine += nSpaces;
+ for (; nSpaces >= 0; nSpaces -= SPACES.length) {
+ out.push(SPACES.substring(0, nSpaces));
+ }
+ pos = i + 1;
+ break;
+ case '\n':
+ charInLine = 0;
+ break;
+ default:
+ ++charInLine;
+ }
+ }
+ if (!out) { return plainText; }
+ out.push(plainText.substring(pos));
+ return out.join('');
+ };
+ }
+
+ var pr_chunkPattern = new RegExp(
+ '[^<]+' // A run of characters other than '<'
+ + '|<\!--[\\s\\S]*?--\>' // an HTML comment
+ + '|' // a CDATA section
+ // a probable tag that should not be highlighted
+ + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
+ + '|<', // A '<' that does not begin a larger chunk
+ 'g');
+ var pr_commentPrefix = /^<\!--/;
+ var pr_cdataPrefix = /^) into their textual equivalent.
+ *
+ * @param {string} s html where whitespace is considered significant.
+ * @return {Object} source code and extracted tags.
+ * @private
+ */
+ function extractTags(s) {
+ // since the pattern has the 'g' modifier and defines no capturing groups,
+ // this will return a list of all chunks which we then classify and wrap as
+ // PR_Tokens
+ var matches = s.match(pr_chunkPattern);
+ var sourceBuf = [];
+ var sourceBufLen = 0;
+ var extractedTags = [];
+ if (matches) {
+ for (var i = 0, n = matches.length; i < n; ++i) {
+ var match = matches[i];
+ if (match.length > 1 && match.charAt(0) === '<') {
+ if (pr_commentPrefix.test(match)) { continue; }
+ if (pr_cdataPrefix.test(match)) {
+ // strip CDATA prefix and suffix. Don't unescape since it's CDATA
+ sourceBuf.push(match.substring(9, match.length - 3));
+ sourceBufLen += match.length - 12;
+ } else if (pr_brPrefix.test(match)) {
+ //
tags are lexically significant so convert them to text.
+ // This is undone later.
+ sourceBuf.push('\n');
+ ++sourceBufLen;
+ } else {
+ if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
+ // A will start a section that should be
+ // ignored. Continue walking the list until we see a matching end
+ // tag.
+ var name = match.match(pr_tagNameRe)[2];
+ var depth = 1;
+ var j;
+ end_tag_loop:
+ for (j = i + 1; j < n; ++j) {
+ var name2 = matches[j].match(pr_tagNameRe);
+ if (name2 && name2[2] === name) {
+ if (name2[1] === '/') {
+ if (--depth === 0) { break end_tag_loop; }
+ } else {
+ ++depth;
+ }
+ }
+ }
+ if (j < n) {
+ extractedTags.push(
+ sourceBufLen, matches.slice(i, j + 1).join(''));
+ i = j;
+ } else { // Ignore unclosed sections.
+ extractedTags.push(sourceBufLen, match);
+ }
+ } else {
+ extractedTags.push(sourceBufLen, match);
+ }
+ }
+ } else {
+ var literalText = htmlToText(match);
+ sourceBuf.push(literalText);
+ sourceBufLen += literalText.length;
+ }
+ }
+ }
+ return { source: sourceBuf.join(''), tags: extractedTags };
+ }
+
+ /** True if the given tag contains a class attribute with the nocode class. */
+ function isNoCodeTag(tag) {
+ return !!tag
+ // First canonicalize the representation of attributes
+ .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
+ ' $1="$2$3$4"')
+ // Then look for the attribute we want.
+ .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
+ }
+
+ /**
+ * Apply the given language handler to sourceCode and add the resulting
+ * decorations to out.
+ * @param {number} basePos the index of sourceCode within the chunk of source
+ * whose decorations are already present on out.
+ */
+ function appendDecorations(basePos, sourceCode, langHandler, out) {
+ if (!sourceCode) { return; }
+ var job = {
+ source: sourceCode,
+ basePos: basePos
+ };
+ langHandler(job);
+ out.push.apply(out, job.decorations);
+ }
+
+ /** Given triples of [style, pattern, context] returns a lexing function,
+ * The lexing function interprets the patterns to find token boundaries and
+ * returns a decoration list of the form
+ * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
+ * where index_n is an index into the sourceCode, and style_n is a style
+ * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to
+ * all characters in sourceCode[index_n-1:index_n].
+ *
+ * The stylePatterns is a list whose elements have the form
+ * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
+ *
+ * Style is a style constant like PR_PLAIN, or can be a string of the
+ * form 'lang-FOO', where FOO is a language extension describing the
+ * language of the portion of the token in $1 after pattern executes.
+ * E.g., if style is 'lang-lisp', and group 1 contains the text
+ * '(hello (world))', then that portion of the token will be passed to the
+ * registered lisp handler for formatting.
+ * The text before and after group 1 will be restyled using this decorator
+ * so decorators should take care that this doesn't result in infinite
+ * recursion. For example, the HTML lexer rule for SCRIPT elements looks
+ * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match
+ * 'RT
Element Missed Instructions Cov. Missed Branches Cov. Missed Cxty Missed Lines Missed Methods Total 19 of 19 0% 0 of 0 n/a 2 2 6 6 2 2 dumpCoverageData(File, boolean, boolean) 0% n/a 1 1 4 4 1 1 dumpCoverageData(File, boolean) 0% n/a 1 1 2 2 1 1