relevance-rcov 0.9.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/BLURB +111 -0
  2. data/LICENSE +53 -0
  3. data/Rakefile +94 -0
  4. data/THANKS +110 -0
  5. data/bin/rcov +514 -0
  6. data/doc/readme_for_api.markdown +22 -0
  7. data/doc/readme_for_emacs.markdown +52 -0
  8. data/doc/readme_for_rake.markdown +51 -0
  9. data/doc/readme_for_vim.markdown +34 -0
  10. data/editor-extensions/rcov.el +131 -0
  11. data/editor-extensions/rcov.vim +38 -0
  12. data/ext/java/src/CallsiteHook.java +137 -0
  13. data/ext/java/src/CoverageHook.java +117 -0
  14. data/ext/java/src/RcovHook.java +9 -0
  15. data/ext/java/src/RcovrtService.java +130 -0
  16. data/lib/rcov.rb +33 -0
  17. data/lib/rcov/call_site_analyzer.rb +225 -0
  18. data/lib/rcov/code_coverage_analyzer.rb +268 -0
  19. data/lib/rcov/coverage_info.rb +36 -0
  20. data/lib/rcov/differential_analyzer.rb +116 -0
  21. data/lib/rcov/file_statistics.rb +334 -0
  22. data/lib/rcov/formatters.rb +13 -0
  23. data/lib/rcov/formatters/base_formatter.rb +173 -0
  24. data/lib/rcov/formatters/failure_report.rb +15 -0
  25. data/lib/rcov/formatters/full_text_report.rb +48 -0
  26. data/lib/rcov/formatters/html_coverage.rb +274 -0
  27. data/lib/rcov/formatters/html_erb_template.rb +62 -0
  28. data/lib/rcov/formatters/text_coverage_diff.rb +193 -0
  29. data/lib/rcov/formatters/text_report.rb +32 -0
  30. data/lib/rcov/formatters/text_summary.rb +11 -0
  31. data/lib/rcov/lowlevel.rb +146 -0
  32. data/lib/rcov/rcovtask.rb +155 -0
  33. data/lib/rcov/templates/detail.html.erb +64 -0
  34. data/lib/rcov/templates/index.html.erb +93 -0
  35. data/lib/rcov/templates/jquery-1.3.2.min.js +19 -0
  36. data/lib/rcov/templates/jquery.tablesorter.min.js +15 -0
  37. data/lib/rcov/templates/print.css +12 -0
  38. data/lib/rcov/templates/rcov.js +42 -0
  39. data/lib/rcov/templates/screen.css +270 -0
  40. data/lib/rcov/version.rb +10 -0
  41. data/lib/rcovrt.jar +0 -0
  42. data/setup.rb +1588 -0
  43. data/test/assets/sample_01.rb +7 -0
  44. data/test/assets/sample_02.rb +5 -0
  45. data/test/assets/sample_03.rb +20 -0
  46. data/test/assets/sample_04.rb +10 -0
  47. data/test/assets/sample_05-new.rb +17 -0
  48. data/test/assets/sample_05-old.rb +13 -0
  49. data/test/assets/sample_05.rb +17 -0
  50. data/test/assets/sample_06.rb +8 -0
  51. data/test/call_site_analyzer_test.rb +171 -0
  52. data/test/code_coverage_analyzer_test.rb +219 -0
  53. data/test/file_statistics_test.rb +471 -0
  54. data/test/functional_test.rb +91 -0
  55. data/test/turn_off_rcovrt.rb +4 -0
  56. metadata +115 -0
@@ -0,0 +1,62 @@
1
+ module Rcov
2
+ module Formatters
3
+ class HtmlErbTemplate
4
+ attr_accessor :local_variables
5
+
6
+ def initialize(template_file, locals={})
7
+ require "erb"
8
+
9
+ template_path = File.expand_path("#{File.dirname(__FILE__)}/../templates/#{template_file}")
10
+ @template = ERB.new(File.read(template_path))
11
+ @local_variables = locals
12
+ @path_relativizer = Hash.new{|h,base|
13
+ h[base] = Pathname.new(base).cleanpath.to_s.gsub(%r{^\w:[/\\]}, "").gsub(/\./, "_").gsub(/[\\\/]/, "-") + ".html"
14
+ }
15
+ end
16
+
17
+ def render
18
+ @template.result(get_binding)
19
+ end
20
+
21
+ def coverage_threshold_classes(percentage)
22
+ return 110 if percentage == 100
23
+ return (1..10).find_all{|i| i * 10 > percentage}.map{|i| i.to_i * 10} * " "
24
+ end
25
+
26
+ def code_coverage_html(code_coverage_percentage, is_total=false)
27
+ %{<div class="percent_graph_legend"><tt class='#{ is_total ? 'coverage_total' : ''}'>#{ "%3.2f" % code_coverage_percentage }%</tt></div>
28
+ <div class="percent_graph">
29
+ <div class="covered" style="width:#{ code_coverage_percentage.round }px"></div>
30
+ <div class="uncovered" style="width:#{ 100 - code_coverage_percentage.round }px"></div>
31
+ </div>}
32
+ end
33
+
34
+ def file_filter_classes(file_path)
35
+ file_path.split('/')[0..-2] * " "
36
+ end
37
+
38
+ def relative_filename(path)
39
+ @path_relativizer[path]
40
+ end
41
+
42
+ def line_css(line_number)
43
+ case fileinfo.coverage[line_number]
44
+ when true
45
+ "marked"
46
+ when :inferred
47
+ "inferred"
48
+ else
49
+ "uncovered"
50
+ end
51
+ end
52
+
53
+ def method_missing(key, *args)
54
+ local_variables.has_key?(key) ? local_variables[key] : super
55
+ end
56
+
57
+ def get_binding
58
+ binding
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,193 @@
1
+ module Rcov
2
+ class TextCoverageDiff < BaseFormatter # :nodoc:
3
+ FORMAT_VERSION = [0, 1, 0]
4
+ DEFAULT_OPTS = { :textmode => :coverage_diff, :coverage_diff_mode => :record,
5
+ :coverage_diff_file => "coverage.info", :diff_cmd => "diff",
6
+ :comments_run_by_default => true }
7
+ HUNK_HEADER = /@@ -\d+,\d+ \+(\d+),(\d+) @@/
8
+
9
+ def SERIALIZER
10
+ # mfp> this was going to be YAML but I caught it failing at basic
11
+ # round-tripping, turning "\n" into "" and corrupting the data, so
12
+ # it must be Marshal for now
13
+ Marshal
14
+ end
15
+
16
+ def initialize(opts = {})
17
+ options = DEFAULT_OPTS.clone.update(opts)
18
+ @textmode = options[:textmode]
19
+ @color = options[:color]
20
+ @mode = options[:coverage_diff_mode]
21
+ @state_file = options[:coverage_diff_file]
22
+ @diff_cmd = options[:diff_cmd]
23
+ @gcc_output = options[:gcc_output]
24
+ super(options)
25
+ end
26
+
27
+ def execute
28
+ case @mode
29
+ when :record
30
+ record_state
31
+ when :compare
32
+ compare_state
33
+ else
34
+ raise "Unknown TextCoverageDiff mode: #{mode.inspect}."
35
+ end
36
+ end
37
+
38
+ def record_state
39
+ state = {}
40
+ each_file_pair_sorted do |filename, fileinfo|
41
+ state[filename] = {:lines => SCRIPT_LINES__[filename], :coverage => fileinfo.coverage.to_a,:counts => fileinfo.counts}
42
+ end
43
+ File.open(@state_file, "w") do |f|
44
+ self.SERIALIZER.dump([FORMAT_VERSION, state], f)
45
+ end
46
+ rescue
47
+ $stderr.puts <<-EOF
48
+ Couldn't save coverage data to #{@state_file}.
49
+ EOF
50
+ end # '
51
+
52
+ require 'tempfile'
53
+ def compare_state
54
+ return unless verify_diff_available
55
+ begin
56
+ format, prev_state = File.open(@state_file){|f| self.SERIALIZER.load(f) }
57
+ rescue
58
+ $stderr.puts <<-EOF
59
+ Couldn't load coverage data from #{@state_file}.
60
+ EOF
61
+ return # '
62
+ end
63
+ if !(Array === format) or
64
+ FORMAT_VERSION[0] != format[0] || FORMAT_VERSION[1] < format[1]
65
+ $stderr.puts <<-EOF
66
+ Couldn't load coverage data from #{@state_file}.
67
+ The file is saved in the format #{format.inspect[0..20]}.
68
+ This rcov executable understands #{FORMAT_VERSION.inspect}.
69
+ EOF
70
+ return # '
71
+ end
72
+ each_file_pair_sorted do |filename, fileinfo|
73
+ old_data = Tempfile.new("#{mangle_filename(filename)}-old")
74
+ new_data = Tempfile.new("#{mangle_filename(filename)}-new")
75
+ if prev_state.has_key? filename
76
+ old_code, old_cov = prev_state[filename].values_at(:lines, :coverage)
77
+ old_code.each_with_index do |line, i|
78
+ prefix = old_cov[i] ? " " : "!! "
79
+ old_data.write "#{prefix}#{line}"
80
+ end
81
+ else
82
+ old_data.write ""
83
+ end
84
+ old_data.close
85
+ SCRIPT_LINES__[filename].each_with_index do |line, i|
86
+ prefix = fileinfo.coverage[i] ? " " : "!! "
87
+ new_data.write "#{prefix}#{line}"
88
+ end
89
+ new_data.close
90
+
91
+ diff = `#{@diff_cmd} -u "#{old_data.path}" "#{new_data.path}"`
92
+ new_uncovered_hunks = process_unified_diff(filename, diff)
93
+ old_data.close!
94
+ new_data.close!
95
+ display_hunks(filename, new_uncovered_hunks)
96
+ end
97
+ end
98
+
99
+ def display_hunks(filename, hunks)
100
+ return if hunks.empty?
101
+ puts
102
+ puts "=" * 80
103
+ puts "!!!!! Uncovered code introduced in #{filename}"
104
+
105
+ hunks.each do |offset, lines|
106
+ if @gcc_output
107
+ lines.each_with_index do |line,i|
108
+ lineno = offset + i
109
+ flag = (/^!! / !~ line) ? "-" : ":"
110
+ prefix = "#{filename}#{flag}#{lineno}#{flag}"
111
+ puts "#{prefix}#{line[3..-1]}"
112
+ end
113
+ elsif @color
114
+ puts "### #{filename}:#{offset}"
115
+ lines.each do |line|
116
+ prefix = (/^!! / !~ line) ? "\e[32;40m" : "\e[31;40m"
117
+ puts "#{prefix}#{line[3..-1].chomp}\e[37;40m"
118
+ end
119
+ else
120
+ puts "### #{filename}:#{offset}"
121
+ puts lines
122
+ end
123
+ end
124
+ end
125
+
126
+ def verify_diff_available
127
+ old_stderr = STDERR.dup
128
+ old_stdout = STDOUT.dup
129
+ new_stderr = Tempfile.new("rcov_check_diff")
130
+ STDERR.reopen new_stderr.path
131
+ STDOUT.reopen new_stderr.path
132
+
133
+ retval = system "#{@diff_cmd} --version"
134
+ unless retval
135
+ old_stderr.puts <<EOF
136
+ The '#{@diff_cmd}' executable seems not to be available.
137
+ You can specify which diff executable should be used with --diff-cmd.
138
+ If your system doesn't have one, you might want to use Diff::LCS's:
139
+ gem install diff-lcs
140
+ and use --diff-cmd=ldiff.
141
+ EOF
142
+ return false
143
+ end
144
+ true
145
+ ensure
146
+ STDOUT.reopen old_stdout
147
+ STDERR.reopen old_stderr
148
+ new_stderr.close!
149
+ end
150
+
151
+ def process_unified_diff(filename, diff)
152
+ current_hunk = []
153
+ current_hunk_start = 0
154
+ keep_current_hunk = false
155
+ state = :init
156
+ interesting_hunks = []
157
+ diff.each_with_index do |line, i|
158
+ #puts "#{state} %5d #{line}" % i
159
+ case state
160
+ when :init
161
+ if md = HUNK_HEADER.match(line)
162
+ current_hunk = []
163
+ current_hunk_start = md[1].to_i
164
+ state = :body
165
+ end
166
+ when :body
167
+ case line
168
+ when HUNK_HEADER
169
+ new_start = $1.to_i
170
+ if keep_current_hunk
171
+ interesting_hunks << [current_hunk_start, current_hunk]
172
+ end
173
+ current_hunk_start = new_start
174
+ current_hunk = []
175
+ keep_current_hunk = false
176
+ when /^-/
177
+ # ignore
178
+ when /^\+!! /
179
+ keep_current_hunk = true
180
+ current_hunk << line[1..-1]
181
+ else
182
+ current_hunk << line[1..-1]
183
+ end
184
+ end
185
+ end
186
+ if keep_current_hunk
187
+ interesting_hunks << [current_hunk_start, current_hunk]
188
+ end
189
+
190
+ interesting_hunks
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,32 @@
1
+ module Rcov
2
+ class TextReport < TextSummary # :nodoc:
3
+ def execute
4
+ print_lines
5
+ print_header
6
+ print_lines
7
+
8
+ each_file_pair_sorted do |fname, finfo|
9
+ name = fname.size < 52 ? fname : "..." + fname[-48..-1]
10
+ print_info(name, finfo.num_lines, finfo.num_code_lines,
11
+ finfo.code_coverage)
12
+ end
13
+
14
+ print_lines
15
+ print_info("Total", num_lines, num_code_lines, code_coverage)
16
+ print_lines
17
+ puts summary
18
+ end
19
+
20
+ def print_info(name, lines, loc, coverage)
21
+ puts "|%-51s | %5d | %5d | %5.1f%% |" % [name, lines, loc, 100 * coverage]
22
+ end
23
+
24
+ def print_lines
25
+ puts "+----------------------------------------------------+-------+-------+--------+"
26
+ end
27
+
28
+ def print_header
29
+ puts "| File | Lines | LOC | COV |"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,11 @@
1
+ module Rcov
2
+ class TextSummary < BaseFormatter # :nodoc:
3
+ def execute
4
+ puts summary
5
+ end
6
+
7
+ def summary
8
+ "%.1f%% %d file(s) %d Lines %d LOC" % [code_coverage * 100, @files.size, num_lines, num_code_lines]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,146 @@
1
+ # rcov Copyright (c) 2004-2006 Mauricio Fernandez <mfp@acm.org>
2
+ #
3
+ # See LEGAL and LICENSE for licensing information.
4
+
5
+ require 'rcov/version'
6
+
7
+ module Rcov
8
+
9
+ # RCOV__ performs the low-level tracing of the execution, gathering code
10
+ # coverage information in the process. The C core made available through the
11
+ # rcovrt extension will be used if possible. Otherwise the functionality
12
+ # will be emulated using set_trace_func, but this is very expensive and
13
+ # will fail if other libraries (e.g. breakpoint) change the trace_func.
14
+ #
15
+ # Do not use this module; it is very low-level and subject to frequent
16
+ # changes. Rcov::CodeCoverageAnalyzer offers a much more convenient and
17
+ # stable interface.
18
+
19
+ module RCOV__
20
+ COVER = {}
21
+ CALLSITES = {}
22
+ DEFSITES = {}
23
+ pure_ruby_impl_needed = true
24
+ unless defined? $rcov_do_not_use_rcovrt
25
+ begin
26
+ require 'rcovrt'
27
+ abi = [0,0,0]
28
+ begin
29
+ abi = RCOV__.ABI
30
+ raise if abi[0] != RCOVRT_ABI[0] || abi[1] < RCOVRT_ABI[1]
31
+ pure_ruby_impl_needed = false
32
+ rescue
33
+ $stderr.puts <<-EOF
34
+ The rcovrt extension I found was built for a different version of rcov.
35
+ The required ABI is: #{RCOVRT_ABI.join(".")}
36
+ Your current rcovrt extension is: #{abi.join(".")}
37
+
38
+ Please delete rcovrt.{so,bundle,dll,...} and install the required one.
39
+ EOF
40
+ raise LoadError
41
+ end
42
+ rescue LoadError
43
+ $stderr.puts <<-EOF
44
+
45
+ Since the rcovrt extension couldn't be loaded, rcov will run in pure-Ruby
46
+ mode, which is about two orders of magnitude slower.
47
+
48
+ If you're on win32, you can find a pre-built extension (usable with recent
49
+ One Click Installer and mswin32 builds) at http://eigenclass.org/hiki.rb?rcov .
50
+
51
+ EOF
52
+ end
53
+ end
54
+
55
+ if pure_ruby_impl_needed
56
+ methods = %w[install_coverage_hook remove_coverage_hook reset_coverage
57
+ install_callsite_hook remove_callsite_hook reset_callsite
58
+ generate_coverage_info generate_callsite_info]
59
+ sklass = class << self; self end
60
+ (methods & sklass.instance_methods).each do |meth|
61
+ sklass.class_eval{ remove_method meth }
62
+ end
63
+
64
+ @coverage_hook_activated = @callsite_hook_activated = false
65
+
66
+ def self.install_coverage_hook # :nodoc:
67
+ install_common_hook
68
+ @coverage_hook_activated = true
69
+ end
70
+
71
+ def self.install_callsite_hook # :nodoc:
72
+ install_common_hook
73
+ @callsite_hook_activated = true
74
+ end
75
+
76
+ def self.install_common_hook # :nodoc:
77
+ set_trace_func lambda {|event, file, line, id, binding, klass|
78
+ next unless SCRIPT_LINES__.has_key? file
79
+ case event
80
+ when 'call'
81
+ if @callsite_hook_activated
82
+ receiver = eval("self", binding)
83
+ klass = class << klass; self end unless klass === receiver
84
+ begin
85
+ DEFSITES[[klass.to_s, id.to_s]] = [file, line]
86
+ rescue Exception
87
+ end
88
+ caller_arr = self.format_backtrace_array(caller[1,1])
89
+ begin
90
+ hash = CALLSITES[[klass.to_s, id.to_s]] ||= {}
91
+ hash[caller_arr] ||= 0
92
+ hash[caller_arr] += 1
93
+ #puts "#{event} #{file} #{line} #{klass.inspect} " +
94
+ # "#{klass.object_id} #{id} #{eval('self', binding)}"
95
+ rescue Exception
96
+ end
97
+ end
98
+ when 'c-call', 'c-return', 'class'
99
+ return
100
+ end
101
+ if @coverage_hook_activated
102
+ COVER[file] ||= Array.new(SCRIPT_LINES__[file].size, 0)
103
+ COVER[file][line - 1] ||= 0
104
+ COVER[file][line - 1] += 1
105
+ end
106
+ }
107
+ end
108
+
109
+ def self.remove_coverage_hook # :nodoc:
110
+ @coverage_hook_activated = false
111
+ set_trace_func(nil) if !@callsite_hook_activated
112
+ end
113
+
114
+ def self.remove_callsite_hook # :nodoc:
115
+ @callsite_hook_activated = false
116
+ set_trace_func(nil) if !@coverage_hook_activated
117
+ end
118
+
119
+ def self.reset_coverage # :nodoc:
120
+ COVER.replace({})
121
+ end
122
+
123
+ def self.reset_callsite # :nodoc:
124
+ CALLSITES.replace({})
125
+ DEFSITES.replace({})
126
+ end
127
+
128
+ def self.generate_coverage_info # :nodoc:
129
+ Marshal.load(Marshal.dump(COVER))
130
+ end
131
+
132
+ def self.generate_callsite_info # :nodoc:
133
+ [CALLSITES, DEFSITES]
134
+ end
135
+
136
+ def self.format_backtrace_array(backtrace)
137
+ backtrace.map do |line|
138
+ md = /^([^:]*)(?::(\d+)(?::in `(.*)'))?/.match(line)
139
+ raise "Bad backtrace format" unless md
140
+ [nil, md[3] ? md[3].to_sym : nil, md[1], (md[2] || '').to_i]
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ end