diff options
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | Makefile.am | 262 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | plugin/icedteanp/IcedTeaNPPlugin.cc | 55 | ||||
-rw-r--r-- | tests/jacoco-operator/org/jacoco/operator/Main.java | 288 | ||||
-rw-r--r-- | tests/jacoco-operator/org/jacoco/operator/MergeTask.java | 157 | ||||
-rw-r--r-- | tests/jacoco-operator/org/jacoco/operator/ReportGenerator.java | 292 |
7 files changed, 1053 insertions, 37 deletions
@@ -1,3 +1,35 @@ +2012-12-11 Jiri Vanek <[email protected]> + + Added jacoco code coverage support + * Makefile.am: (JACOCO_*) bunch of new variables encapsulating jacoco + files. (PLUGIN_COVERAGE_BOOTCLASSPATH) classpath to be used in plugin + instead of normal one in coverage mode. (COVERABLE_PLUGIN_DIR) for + compiling plugin with agent on. (jacoco-operator-source-files.txt) for + storing files of reporting tool. All XSLTPROC command were done as non-fatal + (stamps/compile-jacoco-operator.stamp) for compiling report operator. + (stamps/run-unit-test-code-coverage-jacoco.stam) for cover unittests + Set of (COVERABLE_PLUGIN_*) targets to compile plugin with agent on. + (stamps/build-fake-plugin.stamp) top level target for fake plugin. + (stamps/run-reproducers-test-code-coverage-jacoco.stamp) target for + cover reproducers. (run-test-code-coverage-jacoco) for merged coverage + (clean-unit-test-code-coverage-jacoco) and + (clean-reproducers-test-code-coverage-jacoco) and + (clean-test-code-coverage-jacoco) and + (clean-test-code-coverage-tools-jacoco) cleaning targets. + (run-reproducers-test-code-coverage-jacoco) and + (run-unit-test-code-coverage-jacoco) as top level aliases. + * configure.ac: added check for jacoco library and asm library + * plugin/icedteanp/IcedTeaNPPlugin.cc removed duplicate code + (plugin_start_appletviewe) removed duplicated code and added handling of + java agent if defined. + * tests/jacoco-operator/org/jacoco/operator/Main.java : New class, + comamndline tool for merging results and for generating reports. + * tests/jacoco-operator/org/jacoco/operator/MergeTask.java: New class. + Utility class responsible for merging exec results to one exec file. + * tests/jacoco-operator/org/jacoco/operator/ReportGenerator: New class. + Utility method for gathering sources and builds and outputing xml and + html reports. + 2012-12-11 Adam Domurad <[email protected]> * plugin/icedteanp/java/sun/applet/PluginParameterParser.java: diff --git a/Makefile.am b/Makefile.am index 420fe3b..6973185 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,8 @@ export NETX_UNIT_TEST_DIR=$(NETX_TEST_DIR)/unit export JUNIT_RUNNER_DIR=$(TESTS_DIR)/junit-runner export JUNIT_RUNNER_SRCDIR=$(TESTS_SRCDIR)/junit-runner +export JACOCO_OPERATOR_DIR=$(TESTS_DIR)/jacoco-operator +export JACOCO_OPERATOR_SRCDIR=$(TESTS_SRCDIR)/jacoco-operator export TEST_EXTENSIONS_SRCDIR=$(TESTS_SRCDIR)/test-extensions export TEST_EXTENSIONS_TESTS_SRCDIR=$(TESTS_SRCDIR)/test-extensions-tests @@ -56,6 +58,22 @@ export CUSTOM_REPRODUCERS=custom export ALL_NONCUSTOM_REPRODUCERS=$(SIMPLE_REPRODUCERS) $(SIGNED_REPRODUCERS) export ALL_REPRODUCERS=$(ALL_NONCUSTOM_REPRODUCERS) $(CUSTOM_REPRODUCERS) +export JACOCO_PATH:=$(shell dirname "$(JACOCO_JAR)") +export JACOCO_AGENT=org.jacoco.agent.jar +export JACOCO_ANT=org.jacoco.ant.jar +export JACOCO_REPORT=org.jacoco.report.jar +export JACOCO_AGENTRT=org.jacoco.agent.rt.jar +export JACOCO_CORE=org.jacoco.core.jar +export JACOCO_JAVAWS_RESULTS=$(TEST_EXTENSIONS_DIR)/jacoco_javaws.exec +export JACOCO_PLUGIN_RESULTS=$(TEST_EXTENSIONS_DIR)/jacoco_plugin.exec +export JACOCO_CLASSPATH=$(JACOCO_PATH)/$(JACOCO_CORE):$(JACOCO_PATH)/$(JACOCO_AGENT):$(JACOCO_PATH)/$(JACOCO_REPORT):$(JACOCO_PATH)/$(JACOCO_AGENTRT):$(JACOCO_PATH)/$(JACOCO_ANT):$(ASM_JAR) +export JACOCO_AGENT_SWITCH_BODY=-javaagent:$(JACOCO_PATH)/$(JACOCO_AGENTRT) +export JACOCO_BASE_EXCLUDE=org.junit.*:junit.* +export JACOCO_ADVANCED_EXCLUDE=:*jacoco*:java.lang.*:java.reflect.*:java.util.*:sun.reflect.* +export JACOCO_AGENT_SWITCH="$(JACOCO_AGENT_SWITCH_BODY)=excludes=$(JACOCO_BASE_EXCLUDE)" +export JACOCO_AGENT_JAVAWS_SWITCH=\"$(JACOCO_AGENT_SWITCH_BODY)=excludes=$(JACOCO_BASE_EXCLUDE)$(JACOCO_ADVANCED_EXCLUDE),xboot=true,destfile=$(JACOCO_JAVAWS_RESULTS)\" +export JACOCO_AGENT_PLUGIN_SWITCH=\"$(JACOCO_AGENT_SWITCH_BODY)=excludes=$(JACOCO_BASE_EXCLUDE)$(JACOCO_ADVANCED_EXCLUDE),xboot=true,destfile=$(JACOCO_PLUGIN_RESULTS)\" +export JACOCO_OPERATOR_EXEC=$(BOOT_DIR)/bin/java $(EMMA_JAVA_ARGS) -cp $(JACOCO_OPERATOR_DIR):$(JACOCO_CLASSPATH):. org.jacoco.operator.Main # linking variables export PLUGIN_LINK_NAME=libjavaplugin.so @@ -103,6 +121,7 @@ export IT_JAVACFLAGS=$(IT_JAVAC_SETTINGS) -source $(IT_LANGUAGE_SOURCE_VERSION) # export LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:$(datadir)/$(PACKAGE_NAME)/netx.jar$(RHINO_RUNTIME)" export PLUGIN_BOOTCLASSPATH='"-Xbootclasspath/a:$(datadir)/$(PACKAGE_NAME)/netx.jar:$(datadir)/$(PACKAGE_NAME)/plugin.jar$(RHINO_RUNTIME)"' +export PLUGIN_COVERAGE_BOOTCLASSPATH='"-Xbootclasspath/a:$(datadir)/$(PACKAGE_NAME)/netx.jar:$(datadir)/$(PACKAGE_NAME)/plugin.jar$(RHINO_RUNTIME):$(JACOCO_CLASSPATH)"' # Fake update version to work with the Deployment Toolkit script used by Oracle # http://download.oracle.com/javase/tutorial/deployment/deploymentInDepth/depltoolkit_index.html @@ -128,6 +147,8 @@ export PLUGIN_SRCDIR=$(abs_top_srcdir)/plugin/icedteanp export LIVECONNECT_SRCS = $(PLUGIN_SRCDIR)/java export ICEDTEAPLUGIN_TARGET = $(PLUGIN_DIR)/$(BUILT_PLUGIN_LIBRARY) stamps/liveconnect-dist.stamp export PLUGIN_PKGS = sun.applet netscape.security netscape.javascript +#this is for plugin testcoverage +export COVERABLE_PLUGIN_DIR=$(TESTS_DIR)/icedteanp-build-with-jacoco endif if CP_SUPPORTS_REFLINK @@ -588,6 +609,9 @@ stamps/check-pac-functions.stamp: stamps/bootstrap-directory.stamp junit-runner-source-files.txt: find $(JUNIT_RUNNER_SRCDIR) -name '*.java' | sort > $@ +jacoco-operator-source-files.txt: + find $(JACOCO_OPERATOR_SRCDIR) -name '*.java' | sort > $@ + $(JUNIT_RUNNER_JAR): junit-runner-source-files.txt stamps/test-extensions-compile.stamp mkdir -p $(JUNIT_RUNNER_DIR) && \ $(BOOT_DIR)/bin/javac $(IT_JAVACFLAGS) \ @@ -825,8 +849,8 @@ stamps/run-netx-dist-tests.stamp: stamps/netx-dist.stamp extra-lib/about.jar sta $(BOOT_DIR)/bin/java $(REPRODUCERS_DPARAMETERS) \ -Xbootclasspath:$(RUNTIME) CommandLine $$class_names if WITH_XSLTPROC - $(XSLTPROC) --stringparam logs logs_reproducers.html $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/jreport.xsl $(TEST_EXTENSIONS_DIR)/tests-output.xml > $(TESTS_DIR)/index_reproducers.html - $(XSLTPROC) $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/logs.xsl $(TEST_EXTENSIONS_DIR)/ServerAccess-logs.xml > $(TESTS_DIR)/logs_reproducers.html + -$(XSLTPROC) --stringparam logs logs_reproducers.html $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/jreport.xsl $(TEST_EXTENSIONS_DIR)/tests-output.xml > $(TESTS_DIR)/index_reproducers.html + -$(XSLTPROC) $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/logs.xsl $(TEST_EXTENSIONS_DIR)/ServerAccess-logs.xml > $(TESTS_DIR)/logs_reproducers.html endif touch $@ @@ -1002,8 +1026,8 @@ stamps/run-netx-unit-tests.stamp: stamps/netx-unit-tests-compile.stamp $(JUNIT_R CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(abs_top_builddir)/liveconnect/lib/classes.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):$(TEST_EXTENSIONS_DIR):. \ $(BOOT_DIR)/bin/java -Xbootclasspath:$(RUNTIME) CommandLine $$class_names if WITH_XSLTPROC - $(XSLTPROC) --stringparam logs logs_unit.html $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/jreport.xsl $(NETX_UNIT_TEST_DIR)/tests-output.xml > $(TESTS_DIR)/index_unit.html - $(XSLTPROC) $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/logs.xsl $(NETX_UNIT_TEST_DIR)/ServerAccess-logs.xml > $(TESTS_DIR)/logs_unit.html + -$(XSLTPROC) --stringparam logs logs_unit.html $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/jreport.xsl $(NETX_UNIT_TEST_DIR)/tests-output.xml > $(TESTS_DIR)/index_unit.html + -$(XSLTPROC) $(TESTS_SRCDIR)/$(REPORT_STYLES_DIRNAME)/logs.xsl $(NETX_UNIT_TEST_DIR)/ServerAccess-logs.xml > $(TESTS_DIR)/logs_unit.html endif mkdir -p stamps && \ touch $@ @@ -1049,6 +1073,53 @@ else endif touch $@ +stamps/compile-jacoco-operator.stamp: jacoco-operator-source-files.txt +if WITH_JACOCO + mkdir -p $(JACOCO_OPERATOR_DIR) && \ + $(BOOT_DIR)/bin/javac $(IT_JAVACFLAGS) \ + -d $(JACOCO_OPERATOR_DIR) \ + -classpath $(JACOCO_CLASSPATH) \ + @jacoco-operator-source-files.txt ; +else + echo "Sorry, jacoco coverage report generator cant be compiled without jacoco installed. Try installing jacoco or specify with-jacoco value" ; + exit 5 +endif + touch $@ + + +#warning, during this target tests.build/netx/unit/tests-output.xml is backup and rewriten (but not coresponding html file) +#xml results run with jacoco agent however, can be wrong, co the new tests-output.xml is then renamed and orginal one restored +stamps/run-unit-test-code-coverage-jacoco.stamp: stamps/netx-unit-tests-compile.stamp $(JUNIT_RUNNER_JAR) \ + $(TESTS_DIR)/$(REPORT_STYLES_DIRNAME) $(UNIT_CLASS_NAMES) stamps/compile-jacoco-operator.stamp +if WITH_JACOCO + filename=" " ; \ + cd $(NETX_UNIT_TEST_SRCDIR) ; \ + for file in `find . -type f \! -iname "*.java"`; do\ + filename=`echo $$file `; \ + cp --parents $$filename $(NETX_UNIT_TEST_DIR) ; \ + done ; \ + cd $(NETX_UNIT_TEST_DIR) ; \ + for file in $(EMMA_MODIFIED_FILES) ; do \ + mv $(NETX_UNIT_TEST_DIR)/$$file $(NETX_UNIT_TEST_DIR)/"$$file""$(EMMA_BACKUP_SUFFIX)" ; \ + done ;\ + class_names=`cat $(UNIT_CLASS_NAMES)` ; \ + CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(abs_top_builddir)/liveconnect/lib/classes.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):$(TEST_EXTENSIONS_DIR):$(JACOCO_CLASSPATH):. \ + $(BOOT_DIR)/bin/java $(JACOCO_AGENT_SWITCH) -Xbootclasspath:$(RUNTIME) CommandLine $$class_names ; \ + for file in $(EMMA_MODIFIED_FILES) ; do \ + mv $(NETX_UNIT_TEST_DIR)/$$file $(NETX_UNIT_TEST_DIR)/"$$file""$(EMMA_SUFFIX)" ; \ + mv $(NETX_UNIT_TEST_DIR)/"$$file""$(EMMA_BACKUP_SUFFIX)" $(NETX_UNIT_TEST_DIR)/$$file ; \ + done ; \ + $(JACOCO_OPERATOR_EXEC) \ + report --die-soon --html-output coverage --xml-output coverage.xml --input-file jacoco.exec \ + --input-srcs $(NETX_SRCDIR) $(PLUGIN_SRCDIR)/java $(NETX_UNIT_TEST_SRCDIR) $(JUNIT_RUNNER_SRCDIR) $(TEST_EXTENSIONS_SRCDIR) \ + --input-builds $(NETX_DIR)/lib/classes.jar $(abs_top_builddir)/liveconnect/lib/classes.jar $(NETX_UNIT_TEST_DIR) $(JUNIT_RUNNER_JAR) $(TEST_EXTENSIONS_DIR) \ + --title "IcedTea-Web unit-tests codecoverage" ; +else + echo "Sorry, coverage report cant be run without jacoco installed. Try installing jacoco or specify with-jacoco value" ; + exit 5 +endif + touch $@ + #warning, during this target tests.build/netx/jnlp_testsengine/tests-output.xml is backup and rewriten (but not coresponding html file) #xml results run from emma sandbox, however, can be wrong, co the new tests-output.xml is then renamed and orginal one restored stamps/run-reproducers-test-code-coverage.stamp: stamps/run-netx-dist-tests.stamp $(REPRODUCERS_CLASS_NAMES) @@ -1139,7 +1210,145 @@ else endif touch $@ -run-test-code-coverage: run-unit-test-code-coverage run-reproducers-test-code-coverage +$(COVERABLE_PLUGIN_DIR): + mkdir -p $(COVERABLE_PLUGIN_DIR); + +$(COVERABLE_PLUGIN_DIR)/%.o: $(PLUGIN_SRCDIR)/%.cc + cd $(COVERABLE_PLUGIN_DIR) && \ + $(CXX) $(CXXFLAGS) \ + $(DEFS) $(VERSION_DEFS) \ + -DJDK_UPDATE_VERSION="\"$(JDK_UPDATE_VERSION)\"" \ + -DPLUGIN_NAME="\"IcedTea-Web Plugin with jacoco coverage agent\"" \ + -DPLUGIN_VERSION="\"$(PLUGIN_VERSION)\"" \ + -DPACKAGE_URL="\"$(PACKAGE_URL)\"" \ + -DMOZILLA_VERSION_COLLAPSED="$(MOZILLA_VERSION_COLLAPSED)" \ + -DICEDTEA_WEB_JRE="\"$(SYSTEM_JRE_DIR)\"" \ + -DPLUGIN_BOOTCLASSPATH=$(PLUGIN_COVERAGE_BOOTCLASSPATH) \ + -DCOVERAGE_AGENT=$(JACOCO_AGENT_PLUGIN_SWITCH) \ + $(GLIB_CFLAGS) \ + $(GTK_CFLAGS) \ + $(MOZILLA_CFLAGS) \ + -fvisibility=hidden \ + -fPIC -o $@ -c $< + +$(COVERABLE_PLUGIN_DIR)/$(BUILT_PLUGIN_LIBRARY): $(addprefix $(COVERABLE_PLUGIN_DIR)/,$(PLUGIN_OBJECTS)) + cd $(COVERABLE_PLUGIN_DIR) && \ + $(CXX) $(CXXFLAGS) \ + $(PLUGIN_OBJECTS) \ + $(GLIB_LIBS) \ + $(GTK_LIBS) \ + $(MOZILLA_LIBS) \ + -shared -o $@ + +stamps/build-fake-plugin.stamp: $(COVERABLE_PLUGIN_DIR) $(addprefix $(PLUGIN_SRCDIR)/,$(PLUGIN_SRC)) $(addprefix $(COVERABLE_PLUGIN_DIR)/,$(PLUGIN_OBJECTS)) stamps/liveconnect-dist.stamp $(COVERABLE_PLUGIN_DIR)/$(BUILT_PLUGIN_LIBRARY) + touch $@ + +#warning, during this target tests.build/netx/jnlp_testsengine/tests-output.xml is backup and rewriten (but not coresponding html file) +#xml results run with jacoco agent, however, can be wrong, co the new tests-output.xml is then renamed and orginal one restored +stamps/run-reproducers-test-code-coverage-jacoco.stamp: stamps/run-netx-dist-tests.stamp $(REPRODUCERS_CLASS_NAMES) \ +stamps/compile-jacoco-operator.stamp stamps/build-fake-plugin.stamp +if WITH_JACOCO + cd $(TESTS_DIR) ; \ + for file in $(EMMA_MODIFIED_FILES) ; do \ + mv $(TEST_EXTENSIONS_DIR)/$$file $(TEST_EXTENSIONS_DIR)/"$$file""$(EMMA_BACKUP_SUFFIX)" ; \ + done ;\ + echo "backuping javaws in $(DESTDIR)$(bindir)" ; \ + javaws_backup=$(DESTDIR)$(bindir)/javaws_backup ; \ + mv $(DESTDIR)$(bindir)/javaws $$javaws_backup ; \ + echo "patching $(javaws)" ; \ + nw_bootclasspath="$(LAUNCHER_BOOTCLASSPATH):$(JACOCO_CLASSPATH)" ; \ + cat $$javaws_backup | sed "s|COMMAND.k.=\"..JAVA.\"|COMMAND[k]=\"\\$$\\{JAVA\\}\" ; k=1 ; COMMAND[k]=$(JACOCO_AGENT_JAVAWS_SWITCH)|" | sed "s,$(LAUNCHER_BOOTCLASSPATH),$$nw_bootclasspath," > $(DESTDIR)$(bindir)/$(javaws) ; \ + chmod 777 $(DESTDIR)$(bindir)/$(javaws) ; \ + echo "backuping plugin in $(DESTDIR)/$(libdir)$(BUILT_PLUGIN_LIBRARY)" ; \ + plugin_backup=$(DESTDIR)$(libdir)/$(BUILT_PLUGIN_LIBRARY)_backup ; \ + mv $(DESTDIR)$(libdir)/$(BUILT_PLUGIN_LIBRARY) $$plugin_backup ; \ + echo "fakeing plugin" ; \ + cp $(COVERABLE_PLUGIN_DIR)/$(BUILT_PLUGIN_LIBRARY) $(DESTDIR)$(libdir)/$(BUILT_PLUGIN_LIBRARY) ; \ + testcases_srcs=( ) ; \ + k=0 ; \ + types=($(ALL_REPRODUCERS)); \ + for which in "$${types[@]}" ; do \ + . $(abs_top_srcdir)/NEW_LINE_IFS ; \ + simpleReproducers=(`cat $(abs_top_builddir)/junit-jnlp-dist-$$which.txt `); \ + IFS="$$IFS_BACKUP" ; \ + for dir in "$${simpleReproducers[@]}" ; do \ + testcases_srcs[k]="$(REPRODUCERS_TESTS_SRCDIR)/$$which/$$dir/testcases/" ; \ + k=$$((k+1)) ; \ + done ; \ + done ; \ + cd $(TEST_EXTENSIONS_DIR) ; \ + class_names=`cat $(REPRODUCERS_CLASS_NAMES)` ; \ + CLASSPATH=$(NETX_DIR)/lib/classes.jar:$(JUNIT_JAR):$(JUNIT_RUNNER_JAR):.:$(TEST_EXTENSIONS_DIR):$(JACOCO_CLASSPATH):$(TEST_EXTENSIONS_TESTS_DIR) \ + $(BOOT_DIR)/bin/java $(JACOCO_AGENT_SWITCH) $(REPRODUCERS_DPARAMETERS) \ + -Xbootclasspath:$(RUNTIME) CommandLine $$class_names ; \ + if [ -f $(JACOCO_JAVAWS_RESULTS) ] ; then \ + jacoco_javaws_results=$(JACOCO_JAVAWS_RESULTS) ; \ + $(JACOCO_OPERATOR_EXEC) \ + report --die-soon --html-output coverage-javaws --xml-output coverage-javaws.xml --input-file $(JACOCO_JAVAWS_RESULTS) \ + --input-srcs $(NETX_SRCDIR) \ + --input-builds $(NETX_DIR)/lib/classes.jar \ + --title "IcedTea-Web javaws reproducers codecoverage" ; \ + fi; \ + if [ -f $(JACOCO_PLUGIN_RESULTS) ] ; then \ + jacoco_plugin_results=$(JACOCO_PLUGIN_RESULTS) ; \ + $(JACOCO_OPERATOR_EXEC) \ + report --die-soon --html-output coverage-plugin --xml-output coverage-plugin.xml --input-file $(JACOCO_PLUGIN_RESULTS) \ + --input-srcs $(NETX_SRCDIR) $(PLUGIN_SRCDIR)/java \ + --input-builds $(NETX_DIR)/lib/classes.jar $(abs_top_builddir)/liveconnect/lib/classes.jar \ + --title "IcedTea-Web plugin reproducers codecoverage" ; \ + fi; \ + $(JACOCO_OPERATOR_EXEC) \ + merge --die-soon --input-files jacoco.exec $$jacoco_javaws_results $$jacoco_plugin_results --output-file jacoco-merged-reproducers.exec ; \ + $(JACOCO_OPERATOR_EXEC) \ + report --html-output coverage --xml-output coverage.xml --input-file jacoco-merged-reproducers.exec \ + --input-srcs $(NETX_SRCDIR) $(PLUGIN_SRCDIR)/java $(JUNIT_RUNNER_SRCDIR) $(TEST_EXTENSIONS_SRCDIR) $(TEST_EXTENSIONS_TESTS_SRCDIR) "$${testcases_srcs[@]}" \ + --input-builds $(NETX_DIR)/lib/classes.jar $(abs_top_builddir)/liveconnect/lib/classes.jar $(JUNIT_RUNNER_JAR) $(TEST_EXTENSIONS_DIR) $(TEST_EXTENSIONS_TESTS_DIR) \ + --title "IcedTea-Web reproducers-tests codecoverage" ; \ + echo "restoring javaws in $(DESTDIR)$(bindir)" ; \ + rm -f $(DESTDIR)$(bindir)/$(javaws); \ + mv $$javaws_backup $(DESTDIR)$(bindir)/$(javaws); \ + echo "restoring plugin in $(DESTDIR)/$(libdir)$(BUILT_PLUGIN_LIBRARY)" ; \ + mv $$plugin_backup $(DESTDIR)$(libdir)/$(BUILT_PLUGIN_LIBRARY) ; \ + for file in $(EMMA_MODIFIED_FILES) ; do \ + mv $(TEST_EXTENSIONS_DIR)/$$file $(TEST_EXTENSIONS_DIR)/"$$file""$(EMMA_SUFFIX)" ; \ + mv $(TEST_EXTENSIONS_DIR)/"$$file""$(EMMA_BACKUP_SUFFIX)" $(TEST_EXTENSIONS_DIR)/$$file ; \ + done ; +else + echo "Sorry, coverage report cant be run without jacoco installed. Try installing jacoco or specify with-jacoco value" ; + exit 5 +endif + touch $@ + +run-test-code-coverage-jacoco: stamps/run-unit-test-code-coverage-jacoco.stamp stamps/run-reproducers-test-code-coverage-jacoco.stamp +if WITH_JACOCO + cd $(TESTS_DIR) ; \ + k=0 ; \ + types=($(ALL_REPRODUCERS)); \ + for which in "$${types[@]}" ; do \ + . $(abs_top_srcdir)/NEW_LINE_IFS ; \ + simpleReproducers=(`cat $(abs_top_builddir)/junit-jnlp-dist-$$which.txt `); \ + IFS="$$IFS_BACKUP" ; \ + for dir in "$${simpleReproducers[@]}" ; do \ + testcases_srcs[k]="$(REPRODUCERS_TESTS_SRCDIR)/$$which/$$dir/testcases/" ; \ + k=$$((k+1)) ; \ + done ; \ + done ; \ + class_names=`cat $(REPRODUCERS_CLASS_NAMES)` ; \ + $(JACOCO_OPERATOR_EXEC) \ + merge --die-soon --input-files $(TEST_EXTENSIONS_DIR)/jacoco-merged-reproducers.exec $(NETX_UNIT_TEST_DIR)/jacoco.exec --output-file jacoco-merged.exec; \ + $(JACOCO_OPERATOR_EXEC) \ + report --html-output coverage --xml-output coverage.xml --input-file jacoco-merged.exec \ + --input-srcs $(NETX_SRCDIR) $(PLUGIN_SRCDIR)/java $(JUNIT_RUNNER_SRCDIR) $(TEST_EXTENSIONS_SRCDIR) $(TEST_EXTENSIONS_TESTS_SRCDIR) "$${testcases_srcs[@]}" \ + --input-builds $(NETX_DIR)/lib/classes.jar $(abs_top_builddir)/liveconnect/lib/classes.jar $(JUNIT_RUNNER_JAR) $(TEST_EXTENSIONS_DIR) $(TEST_EXTENSIONS_TESTS_DIR) \ + --input-srcs $(NETX_UNIT_TEST_SRCDIR) \ + --input-builds $(NETX_UNIT_TEST_DIR) \ + --title "IcedTea-Web complete codecoverage" ; +else + echo "Sorry, coverage report cant be run without jacoco installed. Try installing jacoco or specify with-jacoco value" ; + exit 5 +endif + +run-test-code-coverage: stamps/run-unit-test-code-coverage.stamps stamps/run-reproducers-test-code-coverage.stamps if WITH_EMMA cd $(TESTS_DIR) ; \ k=0 ; \ @@ -1175,7 +1384,7 @@ else exit 5 endif -clean-netx-tests: clean-netx-unit-tests clean-junit-runner clean-netx-dist-tests clean-test-code-coverage +clean-netx-tests: clean-netx-unit-tests clean-junit-runner clean-netx-dist-tests clean-test-code-coverage-jacoco clean-test-code-coverage if [ -e $(TESTS_DIR)/netx ]; then \ rmdir $(TESTS_DIR)/netx ; \ fi @@ -1258,6 +1467,43 @@ clean-test-code-coverage: clean-unit-test-code-coverage clean-reproducers-test-c rm -f $(TESTS_DIR)/coverage.em ; \ fi +clean-unit-test-code-coverage-jacoco: + if [ -e stamps/run-unit-test-code-coverage-jacoco.stamp ]; then \ + rm -rf $(NETX_UNIT_TEST_DIR)/coverage ; \ + rm -f $(NETX_UNIT_TEST_DIR)/coverage.xml ; \ + rm -f $(NETX_UNIT_TEST_DIR)/jacoco.exec ; \ + rm -f $(NETX_UNIT_TEST_DIR)/tests-output_withEmma.xml ; \ + rm -f stamps/run-unit-test-code-coverage-jacoco.stamp ; \ + fi + +clean-reproducers-test-code-coverage-jacoco: + if [ -e stamps/run-reproducers-test-code-coverage-jacoco.stamp ]; then \ + rm -rf $(TEST_EXTENSIONS_DIR)/coverage-javaws ; \ + rm -f $(TEST_EXTENSIONS_DIR)/coverage-javaws.xml ; \ + rm -f $(TEST_EXTENSIONS_DIR)/jacoco_javaws.exec ; \ + rm -rf $(TEST_EXTENSIONS_DIR)/coverage-plugin ; \ + rm -f $(TEST_EXTENSIONS_DIR)/coverage-plugin.xml ; \ + rm -f $(TEST_EXTENSIONS_DIR)/jacoco_plugin.exec ; \ + rm -rf $(TEST_EXTENSIONS_DIR)/coverage ; \ + rm -f $(TEST_EXTENSIONS_DIR)/coverage.xml ; \ + rm -f $(TEST_EXTENSIONS_DIR)/jacoco-merged-reproducers.exec ; \ + rm -f $(TEST_EXTENSIONS_DIR)/tests-output_withEmma.xml ; \ + rm -f stamps/run-reproducers-test-code-coverage-jacoco.stamp ; \ + fi + +clean-test-code-coverage-jacoco: clean-unit-test-code-coverage-jacoco clean-reproducers-test-code-coverage-jacoco clean-test-code-coverage-tools-jacoco + if [ -e $(TESTS_DIR)/coverage.xml ]; then \ + rm -rf $(TESTS_DIR)/coverage ; \ + rm -f $(TESTS_DIR)/jacoco-merged.exec; \ + fi + +clean-test-code-coverage-tools-jacoco: + rm -rf $(JACOCO_OPERATOR_DIR) + rm -rf $(COVERABLE_PLUGIN_DIR) + rm -f stamps/compile-jacoco-operator.stamp; + rm -f jacoco-operator-source-files.txt + rm -f stamps/build-fake-plugin.stamp + # plugin tests @@ -1377,3 +1623,7 @@ run-netx-dist-tests: stamps/run-netx-dist-tests.stamp run-unit-test-code-coverage: stamps/run-unit-test-code-coverage.stamp run-reproducers-test-code-coverage: stamps/run-reproducers-test-code-coverage.stamp + +run-unit-test-code-coverage-jacoco: stamps/run-unit-test-code-coverage-jacoco.stamp + +run-reproducers-test-code-coverage-jacoco: stamps/run-reproducers-test-code-coverage-jacoco.stamp diff --git a/configure.ac b/configure.ac index b1da7bb..57315b0 100644 --- a/configure.ac +++ b/configure.ac @@ -106,6 +106,10 @@ IT_FIND_OPTIONAL_JAR([junit], JUNIT, [/usr/share/java/junit4.jar /usr/share/junit-4/lib/junit.jar]) IT_FIND_OPTIONAL_JAR([emma], EMMA, [/usr/share/java/emma.jar]) +IT_FIND_OPTIONAL_JAR([jacoco], JACOCO, + [/usr/share/java/jacoco/org.jacoco.core.jar]) +IT_FIND_OPTIONAL_JAR([asm], ASM, + [/usr/share/java/objectweb-asm4/asm-all-4.0.jar /usr/share/java/objectweb-asm/asm-all.jar]) AC_CONFIG_FILES([jrunscript], [chmod u+x jrunscript]) AC_CONFIG_FILES([build.properties]) diff --git a/plugin/icedteanp/IcedTeaNPPlugin.cc b/plugin/icedteanp/IcedTeaNPPlugin.cc index 48678f5..763120d 100644 --- a/plugin/icedteanp/IcedTeaNPPlugin.cc +++ b/plugin/icedteanp/IcedTeaNPPlugin.cc @@ -1594,20 +1594,28 @@ plugin_start_appletviewer (ITNPPluginData* data) gchar** environment = NULL; std::vector<std::string*>* jvm_args = get_jvm_args(); - if (plugin_debug) + // Construct command line parameters + + command_line.push_back(appletviewer_executable); + + //Add JVM args to command_line + for (int i = 0; i < jvm_args->size(); i++) { - command_line.push_back(appletviewer_executable); + command_line.push_back(*jvm_args->at(i)); + } - //Add JVM args to command_line - for (int i = 0; i < jvm_args->size(); i++) - { - command_line.push_back(*jvm_args->at(i)); - } + command_line.push_back(PLUGIN_BOOTCLASSPATH); + // set the classpath to avoid using the default (cwd). + command_line.push_back("-classpath"); + command_line.push_back(ICEDTEA_WEB_JRE "/lib/rt.jar"); + + // Enable coverage agent if we are running instrumented plugin +#ifdef COVERAGE_AGENT + command_line.push_back(COVERAGE_AGENT); +#endif - command_line.push_back(PLUGIN_BOOTCLASSPATH); - // set the classpath to avoid using the default (cwd). - command_line.push_back("-classpath"); - command_line.push_back(ICEDTEA_WEB_JRE "/lib/rt.jar"); + if (plugin_debug) + { command_line.push_back("-Xdebug"); command_line.push_back("-Xnoagent"); @@ -1615,28 +1623,13 @@ plugin_start_appletviewer (ITNPPluginData* data) std::string debug_flags = "-Xrunjdwp:transport=dt_socket,address=8787,server=y,"; debug_flags += plugin_debug_suspend ? "suspend=y" : "suspend=n"; command_line.push_back(debug_flags); + } - command_line.push_back("sun.applet.PluginMain"); - command_line.push_back(out_pipe_name); - command_line.push_back(in_pipe_name); - } else - { - command_line.push_back(std::string(appletviewer_executable)); - - //Add JVM args to command_line - for (int i = 0; i < jvm_args->size(); i++) - { - command_line.push_back(*jvm_args->at(i)); - } - - command_line.push_back(PLUGIN_BOOTCLASSPATH); - command_line.push_back("-classpath"); - command_line.push_back(ICEDTEA_WEB_JRE "/lib/rt.jar"); - command_line.push_back("sun.applet.PluginMain"); - command_line.push_back(out_pipe_name); - command_line.push_back(in_pipe_name); + command_line.push_back("sun.applet.PluginMain"); + command_line.push_back(out_pipe_name); + command_line.push_back(in_pipe_name); - } + // Finished command line parameters environment = plugin_filter_environment(); std::vector<gchar*> vector_gchar = IcedTeaPluginUtilities::vectorStringToVectorGchar(&command_line); diff --git a/tests/jacoco-operator/org/jacoco/operator/Main.java b/tests/jacoco-operator/org/jacoco/operator/Main.java new file mode 100644 index 0000000..7537ae1 --- /dev/null +++ b/tests/jacoco-operator/org/jacoco/operator/Main.java @@ -0,0 +1,288 @@ +/* +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package org.jacoco.operator; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Commandline launcher + */ +public class Main { + + //main switches + private static final String MERGE = "merge"; + private static final String REPORT = "report"; + //switches + private static final String die_on_failure = "--die-soon"; + //merge + private static final String output_file = "--output-file"; + private static final String input_files = "--input-files"; + //report + private static final String html_output = "--html-output"; + private static final String xml_output = "--xml-output"; + private static final String input_srcs = "--input-srcs"; + private static final String input_builds = "--input-builds"; + private static final String title = "--title"; + private static String input_file = "--input-file"; + /** + * * + */ + private static boolean dieOnFailure = false; + private static boolean warned = false; + + public static void main(String[] args) throws IOException { + if (args.length < 2) { + printHelp(); + System.exit(0); + } + + Runnable r = null; + if (args[0].equalsIgnoreCase(MERGE)) { + r = proceedMerge(cutFirstParam(args)); + } else if (args[0].equalsIgnoreCase(REPORT)) { + r = proceedReport(cutFirstParam(args)); + } else { + System.err.println("Unsuported main switch `" + args[0] + "`, use " + MERGE + " or " + REPORT); + printHelp(); + System.exit(1); + } + if (dieOnFailure && warned) { + System.err.println(die_on_failure + " is specified and warning occured. Exiting"); + System.exit(2); + } + r.run(); + + } + + private static void printHelp() { + System.out.println("Usage: java `classpath` org.jacoco.operator.Main [" + MERGE + "|" + REPORT + "] switches/files"); + System.out.println(" order of switches does not matter"); + System.out.println(" Merge usage: java `classpath` org.jacoco.operator.Main " + MERGE + " " + output_file + " file " + input_files + " file file file ..."); + System.out.println(" Report usage: java `classpath` org.jacoco.operator.Main " + REPORT + " " + html_output + " file " + xml_output + " file " + input_srcs + " file file file ... " + input_builds + " file file file " + title + " titleOfReport " + input_file + " file"); + System.out.println("Where:"); + System.out.println(" classpath should contain this application, and complete jacoco, and sometimes asm3 (depends on jacoco bundle)"); + System.out.println(" " + die_on_failure + " - can be set as first parameter (after main switch), each warning then will cause exit of application"); + System.out.println(" " + MERGE); + System.out.println(" " + output_file + " - is file where merged inputs will be saved"); + System.out.println(" " + input_files + " - is list of files which will be merged into output file"); + System.out.println(" " + REPORT); + System.out.println(" " + html_output + " - name of directory into which report will be generated. Should be empty or not yet exist"); + System.out.println(" " + xml_output + " - is name of file into which xml report will be written"); + System.out.println(" " + input_srcs + " - jars, zips or directories with java sources which will be used during report generation"); + System.out.println(" " + input_builds + " - jars, zips or directories with compiled java classes, debug information must be present"); + System.out.println(" " + title + " - title of report"); + System.out.println(" " + input_file + " - input file with recorded coverage-run-session. By default jacoco saves into " + MergeTask.DEFAULT_NAME); + + } + + private static String[] cutFirstParam(String[] args) { + String[] arg = new String[args.length - 1]; + System.arraycopy(args, 1, arg, 0, arg.length); + return arg; + } + + private static Runnable proceedMerge(String[] a) throws IOException { + String doing = null; + String outputFile = null; + List<String> inputFiles = new ArrayList<String>(2); + for (String s : a) { + if (s.startsWith("--")) { + if (s.equalsIgnoreCase(die_on_failure)) { + doing = null; + dieOnFailure = true; + } else if (s.equalsIgnoreCase(output_file)) { + doing = output_file; + } else if (s.equalsIgnoreCase(input_files)) { + doing = input_files; + } else { + warnOrDie("Unknown Switch for merge " + s); + doing = null; + } + } else { + if (doing == null) { + warnOrDie("Missing switch during processing of " + s); + } else { + if (doing.equalsIgnoreCase(output_file)) { + outputFile = s; + } else if (doing.equalsIgnoreCase(input_files)) { + inputFiles.add(s); + } else { + warnOrDie("Unknown processing of switch of" + doing); + } + + } + } + } + throwIfNullOrEmpty(outputFile, "empty output file"); + File ff = new File(outputFile); + if (ff.exists()) { + warnOrDie("Warning, output file " + ff.getAbsolutePath() + " exists"); + } + MergeTask m = new MergeTask(ff); + for (String string : inputFiles) { + if (checkIfNotNullOrEmpty(string)) { + File f = new File(string); + if (!f.exists()) { + warnOrDie("Warning, input coverage " + f.getAbsolutePath() + " does not exists!"); + } + m.addInputFile(f); + } + } + return m; + + } + + private static Runnable proceedReport(String[] a) throws IOException { + String doing = null; + String htmlDir = null; + String xmlFile = null; + List<String> inputSrcs = new ArrayList<String>(1); + List<String> inputBuilds = new ArrayList<String>(1); + String titleValue = null; + String inputFile = null; + for (String s : a) { + if (s.startsWith("--")) { + if (s.equalsIgnoreCase(die_on_failure)) { + doing = null; + dieOnFailure = true; + } else if (s.equalsIgnoreCase(html_output)) { + doing = html_output; + } else if (s.equalsIgnoreCase(xml_output)) { + doing = xml_output; + } else if (s.equalsIgnoreCase(input_srcs)) { + doing = input_srcs; + } else if (s.equalsIgnoreCase(input_builds)) { + doing = input_builds; + } else if (s.equalsIgnoreCase(title)) { + doing = title; + } else if (s.equalsIgnoreCase(input_file)) { + doing = input_file; + } else { + warnOrDie("Unknown Switch for report " + s); + doing = null; + } + } else { + if (doing == null) { + warnOrDie("Missing switch during processing of " + s); + } else { + if (doing.equalsIgnoreCase(html_output)) { + htmlDir = s; + } else if (doing.equalsIgnoreCase(xml_output)) { + xmlFile = s; + } else if (doing.equalsIgnoreCase(input_srcs)) { + inputSrcs.add(s); + } else if (doing.equalsIgnoreCase(input_builds)) { + inputBuilds.add(s); + } else if (doing.equalsIgnoreCase(title)) { + titleValue = s; + } else if (doing.equalsIgnoreCase(input_file)) { + inputFile = s; + } else { + warnOrDie("Unknown processing of switch of " + doing); + } + + } + } + } + File finalHtmlFile = null; + if (checkIfNotNullOrEmpty(htmlDir)) { + finalHtmlFile = new File(htmlDir); + if (finalHtmlFile.exists()) { + warnOrDie("Warning, direcotry for html report exists! " + finalHtmlFile.getAbsolutePath()); + } + } + File finalXmlFile = null; + if (checkIfNotNullOrEmpty(xmlFile)) { + finalXmlFile = new File(xmlFile); + if (finalXmlFile.exists()) { + warnOrDie("Warning, file for xml report exists! " + finalHtmlFile.getAbsolutePath()); + } + } + if (chckIfNUllOrEmpty(titleValue)) { + titleValue = "Coverage report"; + } + throwIfNullOrEmpty(inputFile, "No coverage data file specified!"); + File finalInputFile = new File(inputFile); + + ReportGenerator rg = new ReportGenerator(titleValue, finalInputFile, finalHtmlFile, finalXmlFile); + + for (String string : inputSrcs) { + if (checkIfNotNullOrEmpty(string)) { + File f = new File(string); + if (!f.exists()) { + warnOrDie("Warning, input source " + f.getAbsolutePath() + " does not exists!"); + } + rg.addSource(f); + } + } + for (String string : inputBuilds) { + if (checkIfNotNullOrEmpty(string)) { + File f = new File(string); + if (!f.exists()) { + warnOrDie("Warning, input build " + f.getAbsolutePath() + " does not exists!"); + } + rg.addClasses(f); + } + } + return rg; + } + + private static String throwIfNullOrEmpty(String outputFile, String message) throws RuntimeException { + if (chckIfNUllOrEmpty(outputFile)) { + throw new RuntimeException(message); + } + return outputFile; + } + + private static boolean checkIfNotNullOrEmpty(String string) { + return string != null && string.trim().length() != 0; + } + + private static boolean chckIfNUllOrEmpty(String outputFile) { + return outputFile == null || outputFile.trim().length() == 0; + } + + private static void warnOrDie(String string) { + System.err.println(string); + warned = true; + + } +} diff --git a/tests/jacoco-operator/org/jacoco/operator/MergeTask.java b/tests/jacoco-operator/org/jacoco/operator/MergeTask.java new file mode 100644 index 0000000..02c1b80 --- /dev/null +++ b/tests/jacoco-operator/org/jacoco/operator/MergeTask.java @@ -0,0 +1,157 @@ +/* +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ +package org.jacoco.operator; + +import java.io.BufferedOutputStream; +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.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.jacoco.core.data.ExecutionDataReader; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.ExecutionDataWriter; +import org.jacoco.core.data.SessionInfoStore; + +/** + * Task for merging a set of execution data store files into a single file + * + * Inspired by: + * https://raw.github.com/jacoco/jacoco/master/org.jacoco.ant/src/org/jacoco/ant/MergeTask.java + */ +public class MergeTask implements Runnable { + + public static final String DEFAULT_NAME = "jacoco.exec"; + private File destfile; + private final List<File> files = new ArrayList<File>(1); + + public MergeTask(File destfile) { + this.destfile = destfile; + } + + public MergeTask(File destfile, List<File> inputs) { + this.destfile = destfile; + files.addAll(inputs); + } + + /** + * Sets the location of the merged data store + * + * @param destfile Destination data store location + */ + public void setDestfile(final File destfile) { + this.destfile = destfile; + } + + public void addInputFile(final File input) { + if (input != null) { + files.add(input); + } + } + + public void addInputFiles(final List<File> input) { + files.addAll(input); + } + + public void execute() throws IOException { + if (destfile == null) { + throw new RuntimeException("Destination file must be supplied"); + } + + final SessionInfoStore infoStore = new SessionInfoStore(); + final ExecutionDataStore dataStore = new ExecutionDataStore(); + + loadSourceFiles(infoStore, dataStore); + + OutputStream outputStream = null; + try { + + outputStream = new BufferedOutputStream(new FileOutputStream( + destfile)); + final ExecutionDataWriter dataWriter = new ExecutionDataWriter( + outputStream); + infoStore.accept(dataWriter); + dataStore.accept(dataWriter); + } finally { + if (outputStream != null) { + outputStream.close(); + } + } + + } + + private void loadSourceFiles(final SessionInfoStore infoStore, final ExecutionDataStore dataStore) throws IOException { + if (files == null || files.isEmpty()) { + throw new RuntimeException("No input files"); + } + final Iterator<?> resourceIterator = files.iterator(); + while (resourceIterator.hasNext()) { + final File resource = (File) resourceIterator.next(); + + if (resource.isDirectory()) { + continue; + } + InputStream resourceStream = null; + try { + resourceStream = new FileInputStream(resource); + final ExecutionDataReader reader = new ExecutionDataReader( + resourceStream); + reader.setSessionInfoVisitor(infoStore); + reader.setExecutionDataVisitor(dataStore); + reader.read(); + } finally { + if (resourceStream != null) { + resourceStream.close(); + } + } + } + } + + @Override + public void run() { + try { + execute(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/tests/jacoco-operator/org/jacoco/operator/ReportGenerator.java b/tests/jacoco-operator/org/jacoco/operator/ReportGenerator.java new file mode 100644 index 0000000..84629f9 --- /dev/null +++ b/tests/jacoco-operator/org/jacoco/operator/ReportGenerator.java @@ -0,0 +1,292 @@ +/* +Copyright (C) 2012 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + */ + +package org.jacoco.operator; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IBundleCoverage; +import org.jacoco.core.data.ExecutionDataReader; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.SessionInfoStore; +import org.jacoco.report.DirectorySourceFileLocator; +import org.jacoco.report.FileMultiReportOutput; +import org.jacoco.report.IReportVisitor; +import org.jacoco.report.MultiSourceFileLocator; +import org.jacoco.report.html.HTMLFormatter; +import org.jacoco.report.xml.XMLFormatter; + +/** + * This example creates a HTML report for eclipse like projects based on a + * single execution data store called jacoco.exec. The report contains no + * grouping information. + * + * The class files under test must be compiled with debug information, otherwise + * source highlighting will not work. + * + * Originally based on: + * http://www.eclemma.org/jacoco/trunk/doc/examples/java/ReportGenerator.java + */ +public class ReportGenerator implements Runnable { + + private final String title; + private final File executionDataFile; + private final List<File> classesDirectories = new ArrayList<File>(1); + private final List<File> sourceDirectories = new ArrayList<File>(1); + private File reportDirectory; + private File xmlOutput; + private ExecutionDataStore executionDataStore; + private SessionInfoStore sessionInfoStore; + private String XML_DEF_NAME = "coverage-summary.xml"; + + /** + * Create a new generator based for the given project. + * + * @param projectDirectory + */ + public ReportGenerator(final File projectDirectory) { + this.title = projectDirectory.getName(); + this.executionDataFile = new File(projectDirectory, MergeTask.DEFAULT_NAME); + this.classesDirectories.add(new File(projectDirectory, "bin")); + this.sourceDirectories.add(new File(projectDirectory, "src")); + this.reportDirectory = new File(projectDirectory, "coveragereport"); + this.xmlOutput = new File(projectDirectory, XML_DEF_NAME); + } + + public ReportGenerator(String title, File exec, File classes, File sources, File htmlReport, File xmlReport) { + this.title = title; + this.executionDataFile = exec; + if (classes != null) { + this.classesDirectories.add(classes); + } + if (sources != null) { + this.sourceDirectories.add(sources); + } + this.reportDirectory = htmlReport; + + this.xmlOutput = xmlReport; + } + + public ReportGenerator(String title, File exec, List<File> classes, List<File> sources, File htmlReport, File xmlReport) { + this.title = title; + this.executionDataFile = exec; + if (classes != null) { + this.classesDirectories.addAll(classes); + } + if (sources != null) { + this.sourceDirectories.addAll(sources); + } + this.reportDirectory = htmlReport; + this.xmlOutput = xmlReport; + } + + public ReportGenerator(String title, File exec, List<File> classes, List<File> sources, File report) { + this.title = title; + this.executionDataFile = exec; + if (classes != null) { + this.classesDirectories.addAll(classes); + } + if (sources != null) { + this.sourceDirectories.addAll(sources); + } + this.reportDirectory = report; + this.xmlOutput = new File(report, XML_DEF_NAME); + } + + public ReportGenerator(String title, File exec, File htmlReport, File xmlReport) { + this.title = title; + this.executionDataFile = exec; + this.reportDirectory = htmlReport; + this.xmlOutput = xmlReport; + } + + public ReportGenerator(String title, File exec, File report) { + this.title = title; + this.executionDataFile = exec; + this.reportDirectory = report; + this.xmlOutput = new File(report, XML_DEF_NAME); + } + + public void addSource(File f) { + sourceDirectories.add(f); + + } + + public void addClasses(File f) { + classesDirectories.add(f); + + } + + /** + * Create the report. + * + * @throws IOException + */ + public void execute() throws IOException { + + // Read the jacoco.exec file. Multiple data stores could be merged + // at this point + loadExecutionData(); + + // Run the structure analyzer on a single class folder to build up + // the coverage model. The process would be similar if your classes + // were in a jar file. Typically you would create a bundle for each + // class folder and each jar you want in your report. If you have + // more than one bundle you will need to add a grouping node to your + // report + final IBundleCoverage bundleCoverage = analyzeStructure(); + + if (reportDirectory != null) { + createHtmlReport(bundleCoverage); + } + if (xmlOutput != null) { + createXmlReport(bundleCoverage); + } + + } + + private void createHtmlReport(final IBundleCoverage bundleCoverage) + throws IOException { + + // Create a concrete report visitor based on some supplied + // configuration. In this case we use the defaults + final HTMLFormatter htmlFormatter = new HTMLFormatter(); + final IReportVisitor visitor = htmlFormatter.createVisitor(new FileMultiReportOutput(reportDirectory)); + + // Initialize the report with all of the execution and session + // information. At this point the report doesn't know about the + // structure of the report being created + visitor.visitInfo(sessionInfoStore.getInfos(), + executionDataStore.getContents()); + + // Populate the report structure with the bundle coverage information. + // Call visitGroup if you need groups in your report. + MultiSourceFileLocator msf = new MultiSourceFileLocator(4); + for (File file : sourceDirectories) { + msf.add(new DirectorySourceFileLocator( + file, "utf-8", 4)); + } + + visitor.visitBundle(bundleCoverage, msf); + + // Signal end of structure information to allow report to write all + // information out + visitor.visitEnd(); + + } + + private void createXmlReport(final IBundleCoverage bundleCoverage) + throws IOException { + + OutputStream fos = new FileOutputStream(xmlOutput); + try { + // Create a concrete report visitor based on some supplied + // configuration. In this case we use the defaults + final XMLFormatter htmlFormatter = new XMLFormatter(); + final IReportVisitor visitor = htmlFormatter.createVisitor(fos); + + // Initialize the report with all of the execution and session + // information. At this point the report doesn't know about the + // structure of the report being created + visitor.visitInfo(sessionInfoStore.getInfos(), + executionDataStore.getContents()); + + // Populate the report structure with the bundle coverage information. + // Call visitGroup if you need groups in your report. + visitor.visitBundle(bundleCoverage, null); + + + // Signal end of structure information to allow report to write all + // information out + visitor.visitEnd(); + } finally { + if (fos != null) { + fos.close(); + } + } + + } + + private void loadExecutionData() throws IOException { + final FileInputStream fis = new FileInputStream(executionDataFile); + try { + final ExecutionDataReader executionDataReader = new ExecutionDataReader( + fis); + executionDataStore = new ExecutionDataStore(); + sessionInfoStore = new SessionInfoStore(); + + executionDataReader.setExecutionDataVisitor(executionDataStore); + executionDataReader.setSessionInfoVisitor(sessionInfoStore); + + while (executionDataReader.read()) { + } + } finally { + if (fis != null) { + fis.close(); + } + } + } + + private IBundleCoverage analyzeStructure() throws IOException { + final CoverageBuilder coverageBuilder = new CoverageBuilder(); + final Analyzer analyzer = new Analyzer(executionDataStore, + coverageBuilder); + for (File file : classesDirectories) { + analyzer.analyzeAll(file); + + } + + return coverageBuilder.getBundle(title); + } + + @Override + public void run() { + try { + execute(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} |