coverage 0.3
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.
- data/CHANGES +23 -0
- data/README +76 -0
- data/TODO +13 -0
- data/lib/coverage.rb +275 -0
- metadata +45 -0
data/CHANGES
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
29-december-2005 Neoneye
|
|
2
|
+
* Alex Pooley posted a patch to eliminate a warning.
|
|
3
|
+
|
|
4
|
+
14-april-2004 Neoneye
|
|
5
|
+
* post-install notice added.
|
|
6
|
+
|
|
7
|
+
30-march-2004 Neoneye
|
|
8
|
+
* better way to substitute into heredoc, while preserving whitespace.
|
|
9
|
+
|
|
10
|
+
22-march-2004 Neoneye
|
|
11
|
+
* version 0.2 released.
|
|
12
|
+
* sidebar can be specified, by creating a file
|
|
13
|
+
named 'coverage.sidebar'.
|
|
14
|
+
* avoid absolute names.
|
|
15
|
+
* output to the local dir 'coverage'.
|
|
16
|
+
* XHTML1.0 strict.
|
|
17
|
+
|
|
18
|
+
21-march-2004 Neoneye
|
|
19
|
+
* version 0.1 released.
|
|
20
|
+
* prepared to make a release of 'coverage.rb'
|
|
21
|
+
* While reading on the rubygems mailinglist I saw that batsman had
|
|
22
|
+
a patch to coverage. I have committed it. Thanks batsman.
|
|
23
|
+
It can now show percentages in the index.html file.
|
data/README
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Ruby - Coverage
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
Purpose
|
|
5
|
+
=======
|
|
6
|
+
|
|
7
|
+
>> this package is outdated, rcov is way better <<
|
|
8
|
+
|
|
9
|
+
This tool helps identify those lines of code in your
|
|
10
|
+
program which didn't got executed while running.
|
|
11
|
+
|
|
12
|
+
NaHi is the author of the original 'coverage.rb',
|
|
13
|
+
47 lines of Ruby code. Today it outputs nice HTML.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
License
|
|
18
|
+
=======
|
|
19
|
+
|
|
20
|
+
Ruby's license
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Install
|
|
24
|
+
=======
|
|
25
|
+
|
|
26
|
+
Follow these 3 steps in order to install
|
|
27
|
+
|
|
28
|
+
ruby install.rb config
|
|
29
|
+
|
|
30
|
+
ruby install.rb setup
|
|
31
|
+
|
|
32
|
+
ruby install.rb install
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
Usage
|
|
36
|
+
=====
|
|
37
|
+
|
|
38
|
+
Insert '-rcoverage' when you wish to make coverage output.
|
|
39
|
+
For instance:
|
|
40
|
+
|
|
41
|
+
ruby -rcoverage test_all.rb
|
|
42
|
+
|
|
43
|
+
It should generage an 'index.html' file, containing coverage info.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
Credits
|
|
47
|
+
=======
|
|
48
|
+
|
|
49
|
+
NAKAMURA Hiroshi (NaHi) for the original coverage code.
|
|
50
|
+
|
|
51
|
+
Mauricio Julio Fern�ndez Pradier, lots of improvements.
|
|
52
|
+
|
|
53
|
+
Robert Feldt, for suggestions.
|
|
54
|
+
|
|
55
|
+
Alex Pooley, for eliminating warning(s).
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
Bugs reports (rubyforge account required)
|
|
60
|
+
=========================================
|
|
61
|
+
|
|
62
|
+
If you find any misbehavier, then please submit it here:
|
|
63
|
+
http://rubyforge.org/tracker/?atid=149&group_id=18&func=browse
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Feature requests (rubyforge account required)
|
|
68
|
+
=============================================
|
|
69
|
+
|
|
70
|
+
If there is something you wish, then tell it so we can figure out
|
|
71
|
+
how to make 'coverage' capable of it.
|
|
72
|
+
http://rubyforge.org/tracker/?atid=152&group_id=18&func=browse
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
end of document
|
data/TODO
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
What needs to be done:
|
|
2
|
+
|
|
3
|
+
* 'end' statements isn't detected correct. I (Simon) has
|
|
4
|
+
only little insight how the original 'coverage.rb' works.
|
|
5
|
+
I don't know how to accomplish this. Please contribute
|
|
6
|
+
in case you know it.
|
|
7
|
+
|
|
8
|
+
* Have a Look at 'profiler.rb', how does it count which
|
|
9
|
+
pieces of code that has be executed.
|
|
10
|
+
When we have this information available, then produce
|
|
11
|
+
some nice HTML, so that you can browse that information.
|
|
12
|
+
|
|
13
|
+
* nicer html output.
|
data/lib/coverage.rb
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# module COVERAGE__ originally (c) NAKAMURA Hiroshi, under Ruby's license
|
|
2
|
+
# module PrettyCoverage originally (c) Simon Strandgaard, under Ruby's license
|
|
3
|
+
# minor modifications by Mauricio Julio Fern�ndez Pradier
|
|
4
|
+
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'rbconfig'
|
|
7
|
+
include Config
|
|
8
|
+
|
|
9
|
+
module PrettyCoverage
|
|
10
|
+
|
|
11
|
+
class HTML
|
|
12
|
+
def write_page(body, title, css, filename)
|
|
13
|
+
html = <<-EOHTML.gsub(/^\s*/, '') % [title, css, body]
|
|
14
|
+
<?xml version="1.0" encoding="ISO-8859-1"?>
|
|
15
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
16
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
17
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
|
18
|
+
<head><title>%s</title>
|
|
19
|
+
<style type="text/css">%s</style></head>
|
|
20
|
+
<body>%s</body></html>
|
|
21
|
+
EOHTML
|
|
22
|
+
File.open(filename, "w+") {|f| f.write(html) }
|
|
23
|
+
end
|
|
24
|
+
def escape(text)
|
|
25
|
+
text.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
|
26
|
+
end
|
|
27
|
+
def initialize
|
|
28
|
+
@files = {}
|
|
29
|
+
@files_codeonly = {}
|
|
30
|
+
@filenames = {}
|
|
31
|
+
@sidebar = ""
|
|
32
|
+
end
|
|
33
|
+
def output_dir(&block)
|
|
34
|
+
dir = "coverage"
|
|
35
|
+
if FileTest.directory?(dir)
|
|
36
|
+
FileUtils.rm_rf(dir)
|
|
37
|
+
end
|
|
38
|
+
FileUtils.mkdir(dir)
|
|
39
|
+
FileUtils.cd(dir) { block.call(dir) }
|
|
40
|
+
end
|
|
41
|
+
def load_sidebar
|
|
42
|
+
return unless FileTest.file?("coverage.sidebar")
|
|
43
|
+
data = nil
|
|
44
|
+
File.open("coverage.sidebar", "r") {|f| data = f.read}
|
|
45
|
+
@sidebar = "<div class=\"sidebar\">#{data}</div>"
|
|
46
|
+
end
|
|
47
|
+
def build_filenames
|
|
48
|
+
duplicates = Hash.new(0)
|
|
49
|
+
@files.keys.each do |filename, marked|
|
|
50
|
+
base = File.basename(filename)
|
|
51
|
+
absolute = File.expand_path(filename)
|
|
52
|
+
n = duplicates[base]
|
|
53
|
+
duplicates[base] += 1
|
|
54
|
+
if n > 0
|
|
55
|
+
base += n.to_s
|
|
56
|
+
end
|
|
57
|
+
@filenames[filename] = [base, absolute]
|
|
58
|
+
end
|
|
59
|
+
#p @filenames
|
|
60
|
+
end
|
|
61
|
+
def execute
|
|
62
|
+
puts "execute"
|
|
63
|
+
build_filenames
|
|
64
|
+
load_sidebar
|
|
65
|
+
output_dir do
|
|
66
|
+
create_file_index
|
|
67
|
+
@files.each do |file, line_marked|
|
|
68
|
+
create_file(file, line_marked, @files_codeonly[file])
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
def mk_filename(name)
|
|
73
|
+
base_absolute = @filenames[name]
|
|
74
|
+
raise "should not happen" unless base_absolute
|
|
75
|
+
base, absolute = base_absolute
|
|
76
|
+
return nil if absolute =~ /\A#{Regexp.escape(CONFIG["libdir"])}/
|
|
77
|
+
return nil if base =~ /test_/
|
|
78
|
+
[base + ".html", base, absolute]
|
|
79
|
+
end
|
|
80
|
+
def create_file_index
|
|
81
|
+
output_filename = "index.html"
|
|
82
|
+
rows = []
|
|
83
|
+
filestats = {}
|
|
84
|
+
filestats_code = {}
|
|
85
|
+
@files.sort_by{|k,v| k}.each do|file, line_marked|
|
|
86
|
+
url_filename = mk_filename(file)
|
|
87
|
+
next unless url_filename
|
|
88
|
+
percent = "%02.1f" % calc_coverage(line_marked)
|
|
89
|
+
percent2 = "%02.1f" % calc_coverage(@files_codeonly[file])
|
|
90
|
+
numlines = line_marked.transpose[1].size
|
|
91
|
+
filestats[file] = [calc_coverage(line_marked), numlines]
|
|
92
|
+
filestats_code[file] = [calc_coverage(@files_codeonly[file]),
|
|
93
|
+
numlines]
|
|
94
|
+
url, filename, abspath = url_filename
|
|
95
|
+
cells = [
|
|
96
|
+
"<a href=\"#{url}\">#{filename}</a>",
|
|
97
|
+
"<tt>#{numlines}</tt>",
|
|
98
|
+
" ", " ", " ",
|
|
99
|
+
"<tt>#{percent}%</tt>",
|
|
100
|
+
" ", " ", " ",
|
|
101
|
+
"<tt>#{percent2}%</tt>"
|
|
102
|
+
]
|
|
103
|
+
rows << cells.map{|cell| "<td>#{cell}</td>"}
|
|
104
|
+
end
|
|
105
|
+
rows.map!{|row| "<tr>#{row}</tr>"}
|
|
106
|
+
table = "<table>#{rows.join}</table>"
|
|
107
|
+
total_cov = 1.0 *
|
|
108
|
+
filestats.inject(0){|a,(k,v)| a + v[0] * v[1]} /
|
|
109
|
+
filestats.inject(0){|a,(k,v)| a + v[1]}
|
|
110
|
+
total_code_cov = 1.0 *
|
|
111
|
+
filestats_code.inject(0) {|a,(k,v)| a + v[0] * v[1]} /
|
|
112
|
+
filestats_code.inject(0){|a,(k,v)| a + v[1]}
|
|
113
|
+
body = "<h1>Average (with comments): %02.1f%%</h1>" % total_cov
|
|
114
|
+
body << "<h1>Average (code only): %02.1f%%</h1>" % total_code_cov
|
|
115
|
+
body << @sidebar
|
|
116
|
+
body << table
|
|
117
|
+
title = "coverage"
|
|
118
|
+
css = <<-EOCSS.gsub(/^\s*/, '')
|
|
119
|
+
body {
|
|
120
|
+
background-color: rgb(180, 180, 180);
|
|
121
|
+
}
|
|
122
|
+
span.marked {
|
|
123
|
+
background-color: rgb(185, 200, 200);
|
|
124
|
+
display: block;
|
|
125
|
+
}
|
|
126
|
+
div.overview {
|
|
127
|
+
border-bottom: 8px solid black;
|
|
128
|
+
}
|
|
129
|
+
div.sidebar {
|
|
130
|
+
float: right;
|
|
131
|
+
width: 300px;
|
|
132
|
+
border: 2px solid black;
|
|
133
|
+
margin-left: 10px;
|
|
134
|
+
padding-left: 10px;
|
|
135
|
+
padding-right: 10px;
|
|
136
|
+
margin-right: -10px;
|
|
137
|
+
background-color: rgb(185, 200, 200);
|
|
138
|
+
}
|
|
139
|
+
EOCSS
|
|
140
|
+
write_page(body, title, css, output_filename)
|
|
141
|
+
end
|
|
142
|
+
def add_file(file, line_marked)
|
|
143
|
+
percent = calc_coverage(line_marked)
|
|
144
|
+
path = File.expand_path(file)
|
|
145
|
+
return nil if path =~ /\A#{Regexp.escape(CONFIG["rubylibdir"])}/
|
|
146
|
+
return nil if path =~ /\A#{Regexp.escape(CONFIG["sitelibdir"])}/
|
|
147
|
+
#printf("file #{file} coverage=%02.1f%\n", percent)
|
|
148
|
+
|
|
149
|
+
# comments and empty lines.. we must
|
|
150
|
+
# propagate marked-value backwards
|
|
151
|
+
line_marked << ["", false]
|
|
152
|
+
(line_marked.size).downto(1) do |index|
|
|
153
|
+
line, marked = line_marked[index-1]
|
|
154
|
+
next_line, next_marked = line_marked[index]
|
|
155
|
+
if line =~ /^\s*(#|$)/ and marked == false
|
|
156
|
+
marked = next_marked
|
|
157
|
+
line_marked[index-1] = [line, marked]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
line_marked.pop
|
|
161
|
+
@files[file] = line_marked
|
|
162
|
+
@files_codeonly[file] = line_marked.select do |(line, marked)|
|
|
163
|
+
line !~ /^\s*(#|$)/
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
def calc_coverage(line_marked)
|
|
167
|
+
marked = line_marked.transpose[1]
|
|
168
|
+
n = marked.inject(0) {|r, i| (i) ? (r+1) : r }
|
|
169
|
+
percent = n.to_f * 100 / marked.size
|
|
170
|
+
end
|
|
171
|
+
def format_overview(file, line_marked, code_marked)
|
|
172
|
+
percent = "%02.1f" % calc_coverage(line_marked)
|
|
173
|
+
percent2 = "%02.1f" % calc_coverage(code_marked)
|
|
174
|
+
html = <<-EOHTML.gsub(/^\s*/, '')
|
|
175
|
+
<div class="overview">
|
|
176
|
+
<table>
|
|
177
|
+
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
|
|
178
|
+
<tr><td>total coverage</td><td>#{percent}%</td></tr>
|
|
179
|
+
<tr><td>code coverage</td><td>#{percent2}%</td></tr>
|
|
180
|
+
</table>
|
|
181
|
+
</div>
|
|
182
|
+
EOHTML
|
|
183
|
+
html
|
|
184
|
+
end
|
|
185
|
+
def format_lines(line_marked)
|
|
186
|
+
result = ""
|
|
187
|
+
last = nil
|
|
188
|
+
end_of_span = ""
|
|
189
|
+
format_line = "%#{line_marked.size.to_s.size}d"
|
|
190
|
+
line_no = 1
|
|
191
|
+
line_marked.each do |(line, marked)|
|
|
192
|
+
if marked != last
|
|
193
|
+
result += end_of_span
|
|
194
|
+
case marked
|
|
195
|
+
when true
|
|
196
|
+
result += "<span class=\"marked\">"
|
|
197
|
+
end_of_span = "</span>"
|
|
198
|
+
when false
|
|
199
|
+
end_of_span = ""
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
result += (format_line % line_no) + " " + escape(line) + "\n"
|
|
203
|
+
last = marked
|
|
204
|
+
line_no += 1
|
|
205
|
+
end
|
|
206
|
+
result += end_of_span
|
|
207
|
+
"<pre>#{result}</pre>"
|
|
208
|
+
end
|
|
209
|
+
def create_file(file, line_marked, code_marked)
|
|
210
|
+
url_filename = mk_filename(file)
|
|
211
|
+
return unless url_filename
|
|
212
|
+
output_filename, filename, abspath = url_filename
|
|
213
|
+
puts "outputting #{output_filename.inspect}"
|
|
214
|
+
body = format_overview(abspath, line_marked, code_marked) +
|
|
215
|
+
format_lines(line_marked)
|
|
216
|
+
title = filename + " - coverage"
|
|
217
|
+
css = <<-EOCSS.gsub(/^\s*/, '')
|
|
218
|
+
body {
|
|
219
|
+
background-color: rgb(180, 180, 180);
|
|
220
|
+
}
|
|
221
|
+
span.marked {
|
|
222
|
+
background-color: rgb(185, 200, 200);
|
|
223
|
+
display: block;
|
|
224
|
+
}
|
|
225
|
+
div.overview {
|
|
226
|
+
border-bottom: 8px solid black;
|
|
227
|
+
}
|
|
228
|
+
EOCSS
|
|
229
|
+
write_page(body, title, css, output_filename)
|
|
230
|
+
end
|
|
231
|
+
end # class HTML
|
|
232
|
+
|
|
233
|
+
end # module PrettyCoverage
|
|
234
|
+
|
|
235
|
+
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
|
236
|
+
|
|
237
|
+
module COVERAGE__
|
|
238
|
+
COVER = {}
|
|
239
|
+
def self.trace_func(event, file, line, id, binding, klass)
|
|
240
|
+
case event
|
|
241
|
+
when 'c-call', 'c-return', 'class'
|
|
242
|
+
return
|
|
243
|
+
end
|
|
244
|
+
COVER[file] ||= []
|
|
245
|
+
COVER[file][line] ||= 0
|
|
246
|
+
COVER[file][line] += 1
|
|
247
|
+
end
|
|
248
|
+
END {
|
|
249
|
+
set_trace_func(nil)
|
|
250
|
+
printer = PrettyCoverage::HTML.new
|
|
251
|
+
COVER.each do |file, lines|
|
|
252
|
+
next if SCRIPT_LINES__.has_key?(file) == false
|
|
253
|
+
lines = SCRIPT_LINES__[file]
|
|
254
|
+
covers = COVER[file]
|
|
255
|
+
line_status = []
|
|
256
|
+
0.upto(lines.size - 1) do |c|
|
|
257
|
+
line = lines[c].chomp
|
|
258
|
+
marked = false
|
|
259
|
+
if covers[c + 1]
|
|
260
|
+
marked = true
|
|
261
|
+
elsif /^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and covers[c + 1 + 1]
|
|
262
|
+
covers[c + 1] = covers[c + 1 + 1]
|
|
263
|
+
marked = true
|
|
264
|
+
elsif /^\s*(?:end|\})\s*$/ =~ line && covers[c + 1 - 1]
|
|
265
|
+
covers[c + 1] = covers[c + 1 - 1]
|
|
266
|
+
marked = true
|
|
267
|
+
end
|
|
268
|
+
line_status << [line, marked]
|
|
269
|
+
end
|
|
270
|
+
printer.add_file(file, line_status)
|
|
271
|
+
end
|
|
272
|
+
printer.execute
|
|
273
|
+
} # END
|
|
274
|
+
set_trace_func(COVERAGE__.method(:trace_func).to_proc)
|
|
275
|
+
end # module COVERAGE__
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
rubygems_version: 0.8.11
|
|
3
|
+
specification_version: 1
|
|
4
|
+
name: coverage
|
|
5
|
+
version: !ruby/object:Gem::Version
|
|
6
|
+
version: "0.3"
|
|
7
|
+
date: 2005-12-29 00:00:00 +01:00
|
|
8
|
+
summary: identifies inactive code
|
|
9
|
+
require_paths:
|
|
10
|
+
- lib
|
|
11
|
+
email: neoneye@gmail.com
|
|
12
|
+
homepage: http://aeditor.rubyforge.org
|
|
13
|
+
rubyforge_project: aeditor
|
|
14
|
+
description: "output-format is XHTML1.0 strict credit goes to NAKAMURA Hiroshi, which made
|
|
15
|
+
the original coverage in 47 lines of code! Mauricio Julio Fern�ndez Pradier,
|
|
16
|
+
lots of improvements. Robert Feldt, for suggestions. Alex Pooley, for
|
|
17
|
+
eliminating warnings."
|
|
18
|
+
autorequire: coverage
|
|
19
|
+
default_executable:
|
|
20
|
+
bindir: bin
|
|
21
|
+
has_rdoc: false
|
|
22
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
-
|
|
25
|
+
- ">"
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: 0.0.0
|
|
28
|
+
version:
|
|
29
|
+
platform: ruby
|
|
30
|
+
signing_key:
|
|
31
|
+
cert_chain:
|
|
32
|
+
authors:
|
|
33
|
+
- Simon Strandgaard
|
|
34
|
+
files:
|
|
35
|
+
- CHANGES
|
|
36
|
+
- README
|
|
37
|
+
- TODO
|
|
38
|
+
- lib/coverage.rb
|
|
39
|
+
test_files: []
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
extra_rdoc_files: []
|
|
42
|
+
executables: []
|
|
43
|
+
extensions: []
|
|
44
|
+
requirements: []
|
|
45
|
+
dependencies: []
|