rcov 0.8.1.2.0 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/BLURB +2 -40
  2. data/LICENSE +2 -5
  3. data/Rakefile +32 -106
  4. data/THANKS +14 -0
  5. data/bin/rcov +277 -1090
  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/{rcov.el → editor-extensions/rcov.el} +0 -0
  11. data/{rcov.vim → editor-extensions/rcov.vim} +0 -0
  12. data/ext/rcovrt/1.8/callsite.c +216 -0
  13. data/ext/rcovrt/1.8/rcovrt.c +287 -0
  14. data/ext/rcovrt/1.9/callsite.c +234 -0
  15. data/ext/rcovrt/1.9/rcovrt.c +264 -0
  16. data/ext/rcovrt/extconf.rb +12 -2
  17. data/lib/rcov.rb +13 -968
  18. data/lib/rcov/call_site_analyzer.rb +225 -0
  19. data/lib/rcov/code_coverage_analyzer.rb +268 -0
  20. data/lib/rcov/coverage_info.rb +36 -0
  21. data/lib/rcov/differential_analyzer.rb +116 -0
  22. data/lib/rcov/file_statistics.rb +334 -0
  23. data/lib/rcov/formatters.rb +13 -0
  24. data/lib/rcov/formatters/base_formatter.rb +173 -0
  25. data/lib/rcov/formatters/failure_report.rb +15 -0
  26. data/lib/rcov/formatters/full_text_report.rb +48 -0
  27. data/lib/rcov/formatters/html_coverage.rb +274 -0
  28. data/lib/rcov/formatters/html_erb_template.rb +62 -0
  29. data/lib/rcov/formatters/text_coverage_diff.rb +193 -0
  30. data/lib/rcov/formatters/text_report.rb +32 -0
  31. data/lib/rcov/formatters/text_summary.rb +11 -0
  32. data/lib/rcov/lowlevel.rb +16 -17
  33. data/lib/rcov/rcovtask.rb +21 -22
  34. data/lib/rcov/templates/detail.html.erb +64 -0
  35. data/lib/rcov/templates/index.html.erb +93 -0
  36. data/lib/rcov/templates/jquery-1.3.2.min.js +19 -0
  37. data/lib/rcov/templates/jquery.tablesorter.min.js +15 -0
  38. data/lib/rcov/templates/print.css +12 -0
  39. data/lib/rcov/templates/rcov.js +42 -0
  40. data/lib/rcov/templates/screen.css +270 -0
  41. data/lib/rcov/version.rb +5 -8
  42. data/setup.rb +5 -2
  43. data/test/{sample_01.rb → assets/sample_01.rb} +0 -0
  44. data/test/{sample_02.rb → assets/sample_02.rb} +0 -0
  45. data/test/{sample_03.rb → assets/sample_03.rb} +0 -0
  46. data/test/{sample_04.rb → assets/sample_04.rb} +0 -0
  47. data/test/{sample_05-new.rb → assets/sample_05-new.rb} +0 -0
  48. data/test/{sample_05-old.rb → assets/sample_05-old.rb} +0 -0
  49. data/test/{sample_05.rb → assets/sample_05.rb} +0 -0
  50. data/test/{test_CallSiteAnalyzer.rb → call_site_analyzer_test.rb} +57 -81
  51. data/test/{test_CodeCoverageAnalyzer.rb → code_coverage_analyzer_test.rb} +71 -35
  52. data/test/{test_FileStatistics.rb → file_statistics_test.rb} +34 -36
  53. data/test/{test_functional.rb → functional_test.rb} +21 -35
  54. metadata +91 -69
  55. data/CHANGES +0 -177
  56. data/LEGAL +0 -36
  57. data/README.API +0 -42
  58. data/README.emacs +0 -64
  59. data/README.en +0 -130
  60. data/README.rake +0 -62
  61. data/README.rant +0 -68
  62. data/README.vim +0 -47
  63. data/Rantfile +0 -76
  64. data/ext/rcovrt/callsite.c +0 -242
  65. data/ext/rcovrt/rcovrt.c +0 -329
  66. data/lib/rcov/rant.rb +0 -87
  67. data/lib/rcov/report.rb +0 -1236
  68. data/mingw-rbconfig.rb +0 -174
@@ -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
data/lib/rcov/lowlevel.rb CHANGED
@@ -6,15 +6,16 @@ require 'rcov/version'
6
6
 
7
7
  module Rcov
8
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.
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
+
18
19
  module RCOV__
19
20
  COVER = {}
20
21
  CALLSITES = {}
@@ -59,19 +60,19 @@ One Click Installer and mswin32 builds) at http://eigenclass.org/hiki.rb?rcov .
59
60
  (methods & sklass.instance_methods).each do |meth|
60
61
  sklass.class_eval{ remove_method meth }
61
62
  end
62
-
63
+
63
64
  @coverage_hook_activated = @callsite_hook_activated = false
64
65
 
65
66
  def self.install_coverage_hook # :nodoc:
66
67
  install_common_hook
67
68
  @coverage_hook_activated = true
68
69
  end
69
-
70
+
70
71
  def self.install_callsite_hook # :nodoc:
71
72
  install_common_hook
72
73
  @callsite_hook_activated = true
73
74
  end
74
-
75
+
75
76
  def self.install_common_hook # :nodoc:
76
77
  set_trace_func lambda {|event, file, line, id, binding, klass|
77
78
  next unless SCRIPT_LINES__.has_key? file
@@ -109,7 +110,7 @@ One Click Installer and mswin32 builds) at http://eigenclass.org/hiki.rb?rcov .
109
110
  @coverage_hook_activated = false
110
111
  set_trace_func(nil) if !@callsite_hook_activated
111
112
  end
112
-
113
+
113
114
  def self.remove_callsite_hook # :nodoc:
114
115
  @callsite_hook_activated = false
115
116
  set_trace_func(nil) if !@coverage_hook_activated
@@ -140,8 +141,6 @@ One Click Installer and mswin32 builds) at http://eigenclass.org/hiki.rb?rcov .
140
141
  end
141
142
  end
142
143
  end
143
- end # RCOV__
144
-
145
- end # Rcov
144
+ end
146
145
 
147
- # vi: set sw=2:
146
+ end
data/lib/rcov/rcovtask.rb CHANGED
@@ -12,9 +12,9 @@ module Rcov
12
12
  # coverage reports.
13
13
  #
14
14
  # Example:
15
- #
15
+ #
16
16
  # require 'rcov/rcovtask'
17
- #
17
+ #
18
18
  # Rcov::RcovTask.new do |t|
19
19
  # t.libs << "test"
20
20
  # t.test_files = FileList['test/test*.rb']
@@ -103,27 +103,27 @@ module Rcov
103
103
  (@name==:rcov ? "" : " for #{actual_name}")
104
104
  end
105
105
  task @name do
106
- run_code = ''
107
- RakeFileUtils.verbose(@verbose) do
108
- run_code =
109
- case rcov_path
110
- when nil, ''
111
- "-S rcov"
112
- else %!"#{rcov_path}"!
113
- end
106
+ run_code = ''
107
+ RakeFileUtils.verbose(@verbose) do
108
+ run_code =
109
+ case rcov_path
110
+ when nil, ''
111
+ "-S rcov"
112
+ else %!"#{rcov_path}"!
113
+ end
114
114
  ruby_opts = @ruby_opts.clone
115
115
  ruby_opts.push( "-I#{lib_path}" )
116
116
  ruby_opts.push run_code
117
- ruby_opts.push( "-w" ) if @warning
118
- ruby ruby_opts.join(" ") + " " + option_list +
119
- %[ -o "#{@output_dir}" ] +
120
- file_list.collect { |fn| %["#{fn}"] }.join(' ')
121
- end
117
+ ruby_opts.push( "-w" ) if @warning
118
+ ruby ruby_opts.join(" ") + " " + option_list +
119
+ %[ -o "#{@output_dir}" ] +
120
+ file_list.collect { |fn| %["#{fn}"] }.join(' ')
121
+ end
122
122
  end
123
123
 
124
124
  desc "Remove rcov products for #{actual_name}"
125
125
  task paste("clobber_", actual_name) do
126
- rm_r @output_dir rescue nil
126
+ rm_r @output_dir rescue nil
127
127
  end
128
128
 
129
129
  clobber_task = paste("clobber_", actual_name)
@@ -143,14 +143,13 @@ module Rcov
143
143
 
144
144
  def file_list # :nodoc:
145
145
  if ENV['TEST']
146
- FileList[ ENV['TEST'] ]
146
+ FileList[ ENV['TEST'] ]
147
147
  else
148
- result = []
149
- result += @test_files.to_a if @test_files
150
- result += FileList[ @pattern ].to_a if @pattern
151
- FileList[result]
148
+ result = []
149
+ result += @test_files.to_a if @test_files
150
+ result += FileList[ @pattern ].to_a if @pattern
151
+ FileList[result]
152
152
  end
153
153
  end
154
154
  end
155
155
  end
156
-
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <title><%= page_title %></title>
5
+ <link href="screen.css" media="all" rel="stylesheet" type="text/css" />
6
+ <link href="print.css" media="print" rel="stylesheet" type="text/css" />
7
+ <% if css %><link href="custom.css" media="all" rel="stylesheet" type="text/css" /><% end %>
8
+ <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
9
+ <script type="text/javascript" src="rcov.js"></script>
10
+ </head>
11
+ <body>
12
+ <h1><%= "#{project_name} C0 Coverage Information - RCov" %></h1>
13
+ <h2><%= page_title %></h2>
14
+
15
+ <% if output_threshold != 101 %>
16
+ <!-- Note: 101 is the default threshold if you don't enter one -->
17
+ <p>Threshold: <%= output_threshold %>%</p>
18
+ <% end %>
19
+
20
+ <div class="report_table_wrapper">
21
+ <table class='report' id='report_table'>
22
+ <thead>
23
+ <tr>
24
+ <th class="left_align">Name</th>
25
+ <th class="right_align">Total Lines</th>
26
+ <th class="right_align">Lines of Code</th>
27
+ <th class="left_align">Total Coverage</th>
28
+ <th class="left_align">Code Coverage</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ <tr>
33
+ <td class="left_align"><a href="<%= relative_filename(fileinfo.name) %>"><%= fileinfo.name %></a></td>
34
+ <td class='right_align'><tt><%= fileinfo.num_lines %></tt></td>
35
+ <td class='right_align'><tt><%= fileinfo.num_code_lines %></tt></td>
36
+ <td class="left_align"><%= code_coverage_html(fileinfo.total_coverage_for_report) %></td>
37
+ <td class="left_align"><%= code_coverage_html(fileinfo.code_coverage_for_report) %></td>
38
+ </tr>
39
+ </tbody>
40
+ </table>
41
+ </div>
42
+
43
+ <h3>Key</h3>
44
+
45
+ <div class="key"><pre><span class='marked'>Code reported as executed by Ruby looks like this...</span><span class='marked1'>and this: this line is also marked as covered.</span><span class='inferred'>Lines considered as run by rcov, but not reported by Ruby, look like this,</span><span class='inferred1'>and this: these lines were inferred by rcov (using simple heuristics).</span><span class='uncovered'>Finally, here's a line marked as not executed.</span></pre></div>
46
+
47
+ <h3>Coverage Details</h3>
48
+
49
+ <table class="details">
50
+ <tbody>
51
+ <% fileinfo.num_lines.times do |i| %>
52
+ <% line = fileinfo.lines[i].chomp %>
53
+ <% count = fileinfo.counts[i] %>
54
+ <tr class="<%= line_css(i) %>">
55
+ <td><pre><a name="line<%= i.next %>"><%= i.next %></a> <%= CGI::escapeHTML(line) %></pre></td>
56
+ </tr>
57
+ <% end %>
58
+ </tbody>
59
+ </table>
60
+
61
+ <p>Generated on <%= generated_on %> with <a href="<%= rcov::UPSTREAM_URL %>">rcov <%= rcov::VERSION %></a></p>
62
+
63
+ </body>
64
+ </html>