spicycode-rcov 0.8.1.5.6 → 0.8.1.5.7
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/Rakefile +13 -111
- data/bin/rcov +1 -1
- data/{readme_for_api → doc/readme_for_api} +0 -0
- data/doc/readme_for_emacs +64 -0
- data/{readme_for_rake → doc/readme_for_rake} +0 -0
- data/{readme_for_rant → doc/readme_for_rant} +0 -0
- data/{readme_for_vim → doc/readme_for_vim} +0 -0
- data/{rcov.el → editor-extensions/rcov.el} +0 -0
- data/{rcov.vim → editor-extensions/rcov.vim} +0 -0
- data/ext/rcovrt/{callsite.c → 1.8/callsite.c} +0 -0
- data/ext/rcovrt/{rcovrt.c → 1.8/rcovrt.c} +0 -0
- data/ext/rcovrt/1.9/callsite.c +258 -0
- data/ext/rcovrt/1.9/rcovrt.c +315 -0
- data/ext/rcovrt/extconf.rb +12 -2
- data/lib/rcov.rb +2 -2
- data/lib/rcov/report.rb +3 -3
- data/test/call_site_analyzer_test.rb +22 -58
- data/test/code_coverage_analyzer_test.rb +7 -5
- metadata +20 -17
- data/lib/rcov/rexml_extensions.rb +0 -44
- data/test/rexml_test.rb +0 -23
data/Rakefile
CHANGED
@@ -17,8 +17,7 @@ require 'rake/clean'
|
|
17
17
|
ENV["RCOVPATH"] = "bin/rcov"
|
18
18
|
|
19
19
|
# The following task is largely equivalent to:
|
20
|
-
#
|
21
|
-
# (really!)
|
20
|
+
# Rcov::RcovTask.new
|
22
21
|
desc "Create a cross-referenced code coverage report."
|
23
22
|
Rcov::RcovTask.new do |t|
|
24
23
|
t.test_files = FileList['test/*_test.rb']
|
@@ -53,6 +52,7 @@ if RUBY_PLATFORM == 'java'
|
|
53
52
|
end
|
54
53
|
else
|
55
54
|
Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t|
|
55
|
+
system("cd ext/rcovrt && make clean && rm Makefile")
|
56
56
|
t.libs << "ext/rcovrt"
|
57
57
|
t.test_files = FileList['test/*_test.rb']
|
58
58
|
t.verbose = true
|
@@ -73,122 +73,24 @@ end
|
|
73
73
|
|
74
74
|
desc "Run the unit tests"
|
75
75
|
task :test => [:test_rcovrt]
|
76
|
-
|
76
|
+
|
77
|
+
desc "install by setup.rb"
|
78
|
+
task :install do
|
79
|
+
sh "sudo ruby setup.rb install"
|
80
|
+
end
|
81
|
+
|
82
|
+
task :default => :test
|
77
83
|
|
78
84
|
desc "Generate rdoc documentation for the rcov library"
|
79
85
|
Rake::RDocTask.new("rdoc") { |rdoc|
|
80
86
|
rdoc.rdoc_dir = 'doc'
|
81
87
|
rdoc.title = "rcov"
|
82
88
|
rdoc.options << "--line-numbers" << "--inline-source"
|
83
|
-
rdoc.rdoc_files.include('readme_for_api')
|
84
|
-
rdoc.rdoc_files.include('readme_for_rake')
|
85
|
-
rdoc.rdoc_files.include('readme_for_rant')
|
86
|
-
rdoc.rdoc_files.include('readme_for_vim')
|
89
|
+
rdoc.rdoc_files.include('doc/readme_for_api')
|
90
|
+
rdoc.rdoc_files.include('doc/readme_for_rake')
|
91
|
+
rdoc.rdoc_files.include('doc/readme_for_rant')
|
92
|
+
rdoc.rdoc_files.include('doc/readme_for_vim')
|
87
93
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
88
94
|
}
|
89
95
|
|
90
|
-
task :default => :test
|
91
|
-
|
92
|
-
desc "install by setup.rb"
|
93
|
-
task :install do
|
94
|
-
sh "sudo ruby setup.rb install"
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
PKG_FILES = ["bin/rcov", "lib/rcov.rb", "lib/rcov/lowlevel.rb", "lib/rcov/xx.rb", "lib/rcov/version.rb", "lib/rcov/rant.rb", "lib/rcov/report.rb", "lib/rcov/rcovtask.rb", "ext/rcovrt/extconf.rb", "ext/rcovrt/rcovrt.c", "ext/rcovrt/callsite.c", "LEGAL", "LICENSE", "Rakefile", "Rantfile", "readme_for_rake", "readme_for_rant", "readme_for_vim", "readme_for_emacs", "readme_for_vim", "readme_for_api", "THANKS", "test/functional_test.rb", "test/file_statistics_test.rb", "test/assets/sample_03.rb", "test/assets/sample_05-new.rb", "test/code_coverage_analyzer_test.rb", "test/assets/sample_04.rb", "test/assets/sample_02.rb", "test/assets/sample_05-old.rb", "test/assets/sample_01.rb", "test/turn_off_rcovrt.rb", "test/call_site_analyzer_test.rb", "test/assets/sample_05.rb", "rcov.vim", "rcov.el", "setup.rb", "BLURB", "CHANGES"]
|
99
|
-
|
100
|
-
# gem management tasks Use these to build the java code before creating the gem package
|
101
|
-
# this code can also be used to generate the MRI gem. But I left the gemspec file in too.
|
102
|
-
spec = Gem::Specification.new do |s|
|
103
|
-
s.name = %q{rcov}
|
104
|
-
s.version = Rcov::VERSION
|
105
|
-
|
106
|
-
s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
|
107
|
-
s.authors = ["Mauricio Fernandez"]
|
108
|
-
s.cert_chain = nil
|
109
|
-
s.date = %q{2007-11-21}
|
110
|
-
s.default_executable = %q{rcov}
|
111
|
-
s.description = %q{rcov is a code coverage tool for Ruby. It is commonly used for viewing overall test unit coverage of target code. It features fast execution (20-300 times faster than previous tools), multiple analysis modes, XHTML and several kinds of text reports, easy automation with Rake via a RcovTask, fairly accurate coverage information through code linkage inference using simple heuristics, colorblind-friendliness...}
|
112
|
-
s.email = %q{mfp@acm.org}
|
113
|
-
s.executables = ["rcov"]
|
114
|
-
s.extensions = ["ext/rcovrt/extconf.rb"]
|
115
|
-
s.platform = Gem::Platform::RUBY
|
116
|
-
s.extra_rdoc_files = ["readme_for_api", "readme_for_rake", "readme_for_rant", "readme_for_vim"]
|
117
|
-
s.files = PKG_FILES
|
118
|
-
s.has_rdoc = true
|
119
|
-
s.homepage = %q{http://eigenclass.org/hiki.rb?rcov}
|
120
|
-
s.rdoc_options = ["--main", "readme_for_api", "--title", "rcov code coverage tool"]
|
121
|
-
s.require_paths = ["lib"]
|
122
|
-
s.required_ruby_version = Gem::Requirement.new("> 0.0.0")
|
123
|
-
s.rubygems_version = %q{1.2.0}
|
124
|
-
s.summary = %q{Code coverage analysis tool for Ruby}
|
125
|
-
s.test_files = ["test/functional_test.rb", "test/file_statistics_test.rb", "test/code_coverage_analyzer_test.rb", "test/call_site_analyzer_test.rb"]
|
126
|
-
|
127
|
-
if s.respond_to? :specification_version then
|
128
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
129
|
-
s.specification_version = 1
|
130
|
-
|
131
|
-
if current_version >= 3 then
|
132
|
-
else
|
133
|
-
end
|
134
|
-
else
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# tasks added in to support generating the JRuby gem.
|
139
|
-
if RUBY_PLATFORM == 'java'
|
140
|
-
spec.platform = "jruby"
|
141
|
-
spec.extensions = []
|
142
|
-
# add the jruby extension to the file list
|
143
|
-
PKG_FILES << "lib/rcovrt.jar"
|
144
|
-
|
145
|
-
def java_classpath_arg
|
146
|
-
begin
|
147
|
-
require 'java'
|
148
|
-
classpath = java.lang.System.getProperty('java.class.path')
|
149
|
-
rescue LoadError
|
150
|
-
end
|
151
|
-
|
152
|
-
if classpath.empty?
|
153
|
-
classpath = FileList["#{ENV['JRUBY_HOME']}/lib/*.jar"].join(File::PATH_SEPARATOR)
|
154
|
-
end
|
155
|
-
|
156
|
-
classpath ? "-cp #{classpath}" : ""
|
157
|
-
end
|
158
|
-
|
159
|
-
|
160
|
-
CLEAN.include ["ext/java/classes", "lib/rcovrt.jar", "pkg"]
|
161
|
-
|
162
|
-
def compile_java
|
163
|
-
mkdir_p "ext/java/classes"
|
164
|
-
sh "javac -g -target 1.5 -source 1.5 -d ext/java/classes #{java_classpath_arg} #{FileList['ext/java/src/**/*.java'].join(' ')}"
|
165
|
-
end
|
166
|
-
|
167
|
-
def make_jar
|
168
|
-
require 'fileutils'
|
169
|
-
lib = File.join(File.dirname(__FILE__), 'lib')
|
170
|
-
FileUtils.mkdir(lib) unless File.exists? lib
|
171
|
-
sh "jar cf lib/rcovrt.jar -C ext/java/classes/ ."
|
172
|
-
end
|
173
|
-
|
174
|
-
file 'lib/rcovrt.jar' => FileList["ext/java/src/*.java"] do
|
175
|
-
compile_java
|
176
|
-
make_jar
|
177
|
-
end
|
178
|
-
|
179
|
-
desc "compile the java extension and put it into the lib directory"
|
180
|
-
task :java_compile => ["lib/rcovrt.jar"]
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
Rake::GemPackageTask.new(spec) do |p|
|
185
|
-
p.need_tar = true
|
186
|
-
p.gem_spec = spec
|
187
|
-
end
|
188
|
-
|
189
|
-
# extend the gem task to include the java_compile
|
190
|
-
if RUBY_PLATFORM == 'java'
|
191
|
-
Rake::Task["pkg"].enhance(["java_compile"])
|
192
|
-
end
|
193
|
-
|
194
96
|
# vim: set sw=2 ft=ruby:
|
data/bin/rcov
CHANGED
@@ -265,7 +265,7 @@ EOF
|
|
265
265
|
"method specified by SELECTOR",
|
266
266
|
"(format: Foo::Bar#method, A::B.method)") do |selector|
|
267
267
|
case selector
|
268
|
-
when /([^.]+)(#|\.)(.*)
|
268
|
+
when /([^.]+)(#|\.)(.*)/ then options.report_cov_bug_for = selector
|
269
269
|
else
|
270
270
|
raise OptionParser::InvalidArgument, selector
|
271
271
|
end
|
File without changes
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
<tt>rcov.el</tt> allows you to use rcov from Emacs conveniently.
|
3
|
+
* Run unit tests and jump to uncovered code by <tt>C-x `</tt>.
|
4
|
+
* Run unit tests and save the current coverage status.
|
5
|
+
* Run unit tests and jump to uncovered code introduced since the last run.
|
6
|
+
* View cross-reference annotated code.
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
|
10
|
+
Copy <tt>rcov.el</tt> to the appropriate directory, which is in load-path.
|
11
|
+
Then require it.
|
12
|
+
(require 'rcov)
|
13
|
+
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
There are some commands to run rcov in Emacs.
|
18
|
+
All of them displays +rcov+ window, whose major-mode is compilation-mode.
|
19
|
+
Therefore you can jump to uncovered code by <tt>C-x `</tt>.
|
20
|
+
|
21
|
+
+rcov-command-line+, +rcovsave-command-line+, and +rcovdiff-command-line+ define
|
22
|
+
command line to run rcov.
|
23
|
+
If you do not use +rcov+ from Rake, you must modify them.
|
24
|
+
|
25
|
+
=== Finding uncovered code
|
26
|
+
|
27
|
+
Type the following while editing your program:
|
28
|
+
M-x rcov
|
29
|
+
|
30
|
+
=== Setting the reference point
|
31
|
+
|
32
|
+
+rcov+'s <tt>--text-coverage-diff</tt> mode compares the current coverage status against
|
33
|
+
the saved one. It therefore needs that information to be recorded
|
34
|
+
before you write new code (typically right after you perform a commit) in
|
35
|
+
order to have something to compare against.
|
36
|
+
|
37
|
+
You can save the current status with the <tt>--save</tt> option.
|
38
|
+
|
39
|
+
Type the following to save the current status in Emacs:
|
40
|
+
M-x rcovsave
|
41
|
+
If you do not use +rcov+ from Rake, you must modify +rcovsave-command-line+ variable.
|
42
|
+
|
43
|
+
=== Finding new uncovered code
|
44
|
+
|
45
|
+
Type the following to save the current status in Emacs:
|
46
|
+
M-x rcovdiff
|
47
|
+
|
48
|
+
=== Viewing cross-reference annotated code
|
49
|
+
|
50
|
+
If you read cross-reference annotated code, issue
|
51
|
+
rake rcov RCOVOPTS='-a'
|
52
|
+
at the beginning.
|
53
|
+
This command creates +coverage+ directory and many *.rb files in it.
|
54
|
+
Filenames of these Ruby scripts are converted from original path.
|
55
|
+
You can browse them by normally <tt>C-x C-f</tt>.
|
56
|
+
You can think of <tt>-a</tt> option as <tt>--xrefs</tt> option and output format is Ruby script.
|
57
|
+
|
58
|
+
After find-file-ed annotated script, the major-mode is rcov-xref-mode,
|
59
|
+
which is derived from ruby-mode and specializes navigation.
|
60
|
+
|
61
|
+
<tt>Tab</tt> and <tt>M-Tab</tt> goes forward/backward links.
|
62
|
+
<tt>Ret</tt> follows selected link.
|
63
|
+
|
64
|
+
This feature is useful to read third-party code or to follow control flow.
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,258 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/st.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
|
5
|
+
static char callsite_hook_set_p;
|
6
|
+
|
7
|
+
typedef struct {
|
8
|
+
const char *sourcefile;
|
9
|
+
unsigned int sourceline;
|
10
|
+
VALUE curr_meth;
|
11
|
+
} type_def_site;
|
12
|
+
static VALUE caller_info = 0;
|
13
|
+
static VALUE method_def_site_info = 0;
|
14
|
+
|
15
|
+
static int caller_stack_len = 1;
|
16
|
+
|
17
|
+
/*
|
18
|
+
*
|
19
|
+
* callsite hook and associated functions
|
20
|
+
*
|
21
|
+
* */
|
22
|
+
|
23
|
+
static VALUE
|
24
|
+
record_callsite_info(VALUE args)
|
25
|
+
{
|
26
|
+
VALUE caller_ary;
|
27
|
+
VALUE curr_meth;
|
28
|
+
VALUE count_hash;
|
29
|
+
VALUE count;
|
30
|
+
VALUE *pargs = (VALUE *)args;
|
31
|
+
|
32
|
+
caller_ary = pargs[0];
|
33
|
+
curr_meth = pargs[1];
|
34
|
+
count_hash = rb_hash_aref(caller_info, curr_meth);
|
35
|
+
if(TYPE(count_hash) != T_HASH) {
|
36
|
+
/* Qnil, anything else should be impossible unless somebody's been
|
37
|
+
* messing with ObjectSpace */
|
38
|
+
count_hash = rb_hash_new();
|
39
|
+
rb_hash_aset(caller_info, curr_meth, count_hash);
|
40
|
+
}
|
41
|
+
count = rb_hash_aref(count_hash, caller_ary);
|
42
|
+
if(count == Qnil)
|
43
|
+
count = INT2FIX(0);
|
44
|
+
count = INT2FIX(FIX2UINT(count) + 1);
|
45
|
+
rb_hash_aset(count_hash, caller_ary, count);
|
46
|
+
/* * /
|
47
|
+
printf("CALLSITE: %s -> %s %d\n", RSTRING_PTR(rb_inspect(curr_meth)),
|
48
|
+
RSTRING_PTR(rb_inspect(caller_ary)), FIX2INT(count));
|
49
|
+
/ * */
|
50
|
+
|
51
|
+
return Qnil;
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
static VALUE
|
56
|
+
record_method_def_site(VALUE args)
|
57
|
+
{
|
58
|
+
type_def_site *pargs = (type_def_site *)args;
|
59
|
+
VALUE def_site_info;
|
60
|
+
// VALUE hash;
|
61
|
+
|
62
|
+
if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
|
63
|
+
return Qnil;
|
64
|
+
def_site_info = rb_ary_new();
|
65
|
+
rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
|
66
|
+
rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
|
67
|
+
rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
|
68
|
+
/* * /
|
69
|
+
printf("DEFSITE: %s:%d for %s\n", pargs->sourcefile, pargs->sourceline+1,
|
70
|
+
RSTRING_PTR(rb_inspect(pargs->curr_meth)));
|
71
|
+
/ * */
|
72
|
+
|
73
|
+
return Qnil;
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE
|
77
|
+
callsite_custom_backtrace(int lev)
|
78
|
+
{
|
79
|
+
ID id;
|
80
|
+
VALUE klass;
|
81
|
+
VALUE klass_path;
|
82
|
+
VALUE eval_string;
|
83
|
+
|
84
|
+
rb_frame_method_id_and_class(&id, &klass);
|
85
|
+
if (id == ID_ALLOCATOR)
|
86
|
+
return Qnil;
|
87
|
+
if (klass) {
|
88
|
+
if (TYPE(klass) == T_ICLASS) {
|
89
|
+
klass = RBASIC(klass)->klass;
|
90
|
+
}
|
91
|
+
else if (FL_TEST(klass, FL_SINGLETON)) {
|
92
|
+
klass = rb_iv_get(klass, "__attached__");
|
93
|
+
}
|
94
|
+
}
|
95
|
+
// rb_sprintf("\"#<Class:%s>\"", RSTRING_PTR(klass_path))
|
96
|
+
|
97
|
+
/*
|
98
|
+
klass = class << klass; self end unless klass === eval("self", binding)
|
99
|
+
*/
|
100
|
+
|
101
|
+
klass_path = rb_class_path(klass);
|
102
|
+
VALUE reciever = rb_funcall(rb_binding_new(), rb_intern("eval"), 1, rb_str_new2("self"));
|
103
|
+
if (rb_funcall(klass, rb_intern("=="), 1, reciever) == Qtrue) {
|
104
|
+
klass_path = rb_sprintf("\"#<Class:%s>\"", RSTRING_PTR(klass_path));
|
105
|
+
OBJ_FREEZE(klass_path);
|
106
|
+
}
|
107
|
+
|
108
|
+
eval_string = rb_sprintf("caller[%d, 1].map do |line|\nmd = /^([^:]*)(?::(\\d+)(?::in `(?:block in )?(.*)'))?/.match(line)\nraise \"Bad backtrace format\" unless md\n[%s, md[3] ? md[3].to_sym : nil, md[1], (md[2] || '').to_i]\nend", lev, RSTRING_PTR(klass_path));
|
109
|
+
return rb_eval_string(RSTRING_PTR(eval_string));
|
110
|
+
}
|
111
|
+
|
112
|
+
static void
|
113
|
+
coverage_event_callsite_hook(rb_event_flag_t event, VALUE node,
|
114
|
+
VALUE self, ID mid, VALUE klass)
|
115
|
+
{
|
116
|
+
VALUE caller_ary;
|
117
|
+
VALUE curr_meth;
|
118
|
+
VALUE args[2];
|
119
|
+
int status;
|
120
|
+
|
121
|
+
caller_ary = callsite_custom_backtrace(caller_stack_len);
|
122
|
+
|
123
|
+
VALUE klass_path;
|
124
|
+
curr_meth = rb_ary_new();
|
125
|
+
|
126
|
+
rb_frame_method_id_and_class(&mid, &klass);
|
127
|
+
|
128
|
+
if (mid == ID_ALLOCATOR)
|
129
|
+
return; //Qnil;
|
130
|
+
if (klass) {
|
131
|
+
if (TYPE(klass) == T_ICLASS) {
|
132
|
+
klass = RBASIC(klass)->klass;
|
133
|
+
}
|
134
|
+
else if (FL_TEST(klass, FL_SINGLETON)) {
|
135
|
+
klass = rb_iv_get(klass, "__attached__");
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
/*
|
140
|
+
klass = class << klass; self end unless klass === eval("self", binding)
|
141
|
+
*/
|
142
|
+
|
143
|
+
klass_path = rb_class_path(klass);
|
144
|
+
VALUE reciever = rb_funcall(rb_binding_new(), rb_intern("eval"), 1, rb_str_new2("self"));
|
145
|
+
if (rb_funcall(klass, rb_intern("=="), 1, reciever) == Qtrue) {
|
146
|
+
klass_path = rb_sprintf("#<Class:%s>", RSTRING_PTR(klass_path));
|
147
|
+
OBJ_FREEZE(klass_path);
|
148
|
+
}
|
149
|
+
|
150
|
+
rb_ary_push(curr_meth, klass_path);
|
151
|
+
rb_ary_push(curr_meth, ID2SYM(mid));
|
152
|
+
|
153
|
+
args[0] = caller_ary;
|
154
|
+
args[1] = curr_meth;
|
155
|
+
rb_protect(record_callsite_info, (VALUE)args, &status);
|
156
|
+
|
157
|
+
if(!status) {
|
158
|
+
type_def_site args;
|
159
|
+
|
160
|
+
args.sourcefile = rb_sourcefile();
|
161
|
+
args.sourceline = rb_sourceline();
|
162
|
+
args.curr_meth = curr_meth;
|
163
|
+
rb_protect(record_method_def_site, (VALUE)&args, NULL);
|
164
|
+
}
|
165
|
+
if(status)
|
166
|
+
rb_gv_set("$!", Qnil);
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
static VALUE
|
171
|
+
cov_install_callsite_hook(VALUE self)
|
172
|
+
{
|
173
|
+
if(!callsite_hook_set_p) {
|
174
|
+
if(TYPE(caller_info) != T_HASH)
|
175
|
+
caller_info = rb_hash_new();
|
176
|
+
callsite_hook_set_p = 1;
|
177
|
+
VALUE something = 0;
|
178
|
+
rb_add_event_hook(coverage_event_callsite_hook,
|
179
|
+
RUBY_EVENT_CALL, something);
|
180
|
+
return Qtrue;
|
181
|
+
} else
|
182
|
+
return Qfalse;
|
183
|
+
}
|
184
|
+
|
185
|
+
|
186
|
+
static VALUE
|
187
|
+
cov_remove_callsite_hook(VALUE self)
|
188
|
+
{
|
189
|
+
if(!callsite_hook_set_p)
|
190
|
+
return Qfalse;
|
191
|
+
else {
|
192
|
+
rb_remove_event_hook(coverage_event_callsite_hook);
|
193
|
+
callsite_hook_set_p = 0;
|
194
|
+
return Qtrue;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
static VALUE
|
200
|
+
cov_generate_callsite_info(VALUE self)
|
201
|
+
{
|
202
|
+
VALUE ret;
|
203
|
+
|
204
|
+
ret = rb_ary_new();
|
205
|
+
rb_ary_push(ret, caller_info);
|
206
|
+
rb_ary_push(ret, method_def_site_info);
|
207
|
+
return ret;
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
static VALUE
|
212
|
+
cov_reset_callsite(VALUE self)
|
213
|
+
{
|
214
|
+
if(callsite_hook_set_p) {
|
215
|
+
rb_raise(rb_eRuntimeError,
|
216
|
+
"Cannot reset the callsite info in the middle of a traced run.");
|
217
|
+
return Qnil;
|
218
|
+
}
|
219
|
+
|
220
|
+
caller_info = rb_hash_new();
|
221
|
+
method_def_site_info = rb_hash_new();
|
222
|
+
return Qnil;
|
223
|
+
}
|
224
|
+
|
225
|
+
void
|
226
|
+
Init_rcov_callsite()
|
227
|
+
{
|
228
|
+
VALUE mRcov;
|
229
|
+
VALUE mRCOV__;
|
230
|
+
ID id_rcov = rb_intern("Rcov");
|
231
|
+
ID id_coverage__ = rb_intern("RCOV__");
|
232
|
+
// ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
|
233
|
+
|
234
|
+
if(rb_const_defined(rb_cObject, id_rcov))
|
235
|
+
mRcov = rb_const_get(rb_cObject, id_rcov);
|
236
|
+
else
|
237
|
+
mRcov = rb_define_module("Rcov");
|
238
|
+
|
239
|
+
if(rb_const_defined(mRcov, id_coverage__))
|
240
|
+
mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
|
241
|
+
else
|
242
|
+
mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
|
243
|
+
|
244
|
+
callsite_hook_set_p = 0;
|
245
|
+
caller_info = rb_hash_new();
|
246
|
+
method_def_site_info = rb_hash_new();
|
247
|
+
rb_gc_register_address(&caller_info);
|
248
|
+
rb_gc_register_address(&method_def_site_info);
|
249
|
+
|
250
|
+
rb_define_singleton_method(mRCOV__, "install_callsite_hook",
|
251
|
+
cov_install_callsite_hook, 0);
|
252
|
+
rb_define_singleton_method(mRCOV__, "remove_callsite_hook",
|
253
|
+
cov_remove_callsite_hook, 0);
|
254
|
+
rb_define_singleton_method(mRCOV__, "generate_callsite_info",
|
255
|
+
cov_generate_callsite_info, 0);
|
256
|
+
rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
|
257
|
+
}
|
258
|
+
/* vim: set sw=8 expandtab: */
|
@@ -0,0 +1,315 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <ruby/st.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <assert.h>
|
5
|
+
|
6
|
+
#define COVERAGE_DEBUG_EVENTS 0
|
7
|
+
|
8
|
+
#define RCOVRT_VERSION_MAJOR 2
|
9
|
+
#define RCOVRT_VERSION_MINOR 0
|
10
|
+
#define RCOVRT_VERSION_REV 0
|
11
|
+
|
12
|
+
static VALUE mRcov;
|
13
|
+
static VALUE mRCOV__;
|
14
|
+
static VALUE oSCRIPT_LINES__;
|
15
|
+
static ID id_cover;
|
16
|
+
static st_table* coverinfo = 0;
|
17
|
+
static char coverage_hook_set_p;
|
18
|
+
|
19
|
+
struct cov_array {
|
20
|
+
unsigned int len;
|
21
|
+
unsigned int *ptr;
|
22
|
+
};
|
23
|
+
|
24
|
+
static struct cov_array *cached_array = 0;
|
25
|
+
static char *cached_file = 0;
|
26
|
+
|
27
|
+
/*
|
28
|
+
*
|
29
|
+
* coverage hook and associated functions
|
30
|
+
*
|
31
|
+
* */
|
32
|
+
static struct cov_array *
|
33
|
+
coverage_increase_counter_uncached(char *sourcefile, unsigned int sourceline,
|
34
|
+
char mark_only)
|
35
|
+
{
|
36
|
+
struct cov_array *carray = NULL;
|
37
|
+
|
38
|
+
if(sourcefile == NULL) {
|
39
|
+
/* "can't happen", just ignore and avoid segfault */
|
40
|
+
return NULL;
|
41
|
+
} else if(!st_lookup(coverinfo, (st_data_t)sourcefile, (st_data_t*)&carray)) {
|
42
|
+
VALUE arr;
|
43
|
+
|
44
|
+
arr = rb_hash_aref(oSCRIPT_LINES__, rb_str_new2(sourcefile));
|
45
|
+
if(NIL_P(arr))
|
46
|
+
return 0;
|
47
|
+
rb_check_type(arr, T_ARRAY);
|
48
|
+
carray = calloc(1, sizeof(struct cov_array));
|
49
|
+
carray->ptr = calloc(RARRAY_LEN(arr), sizeof(unsigned int));
|
50
|
+
carray->len = RARRAY_LEN(arr);
|
51
|
+
st_insert(coverinfo, (st_data_t)strdup(sourcefile),
|
52
|
+
(st_data_t) carray);
|
53
|
+
} else {
|
54
|
+
/* recovered carray, sanity check */
|
55
|
+
assert(carray && "failed to create valid carray");
|
56
|
+
}
|
57
|
+
|
58
|
+
if(mark_only) {
|
59
|
+
if(!carray->ptr[sourceline])
|
60
|
+
carray->ptr[sourceline] = 1;
|
61
|
+
} else {
|
62
|
+
if (carray && carray->len > sourceline) {
|
63
|
+
carray->ptr[sourceline]++;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
return carray;
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
static void
|
72
|
+
coverage_mark_caller()
|
73
|
+
{
|
74
|
+
// if @coverage_hook_activated
|
75
|
+
// COVER[file] ||= Array.new(SCRIPT_LINES__[file].size, 0)
|
76
|
+
// COVER[file][line - 1] ||= 0
|
77
|
+
// COVER[file][line - 1] += 1
|
78
|
+
// end
|
79
|
+
|
80
|
+
coverage_increase_counter_uncached(rb_sourcefile(), rb_sourceline(), 1);
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
static void
|
85
|
+
coverage_increase_counter_cached(char *sourcefile, int sourceline)
|
86
|
+
{
|
87
|
+
if(cached_file == sourcefile && cached_array && cached_array->len > sourceline) {
|
88
|
+
cached_array->ptr[sourceline]++;
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
cached_file = sourcefile;
|
92
|
+
cached_array = coverage_increase_counter_uncached(sourcefile, sourceline, 0);
|
93
|
+
}
|
94
|
+
|
95
|
+
static void
|
96
|
+
coverage_event_coverage_hook(rb_event_flag_t event, VALUE node,
|
97
|
+
VALUE self, ID mid, VALUE klass)
|
98
|
+
{
|
99
|
+
char *sourcefile;
|
100
|
+
unsigned int sourceline;
|
101
|
+
static unsigned int in_hook = 0;
|
102
|
+
|
103
|
+
if(in_hook) {
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
|
107
|
+
in_hook++;
|
108
|
+
|
109
|
+
#if COVERAGE_DEBUG_EVENTS
|
110
|
+
do {
|
111
|
+
int status;
|
112
|
+
VALUE old_exception;
|
113
|
+
old_exception = rb_gv_get("$!");
|
114
|
+
rb_protect(rb_inspect, klass, &status);
|
115
|
+
if(!status) {
|
116
|
+
printf("EVENT: %d %s %s %s %d\n", event,
|
117
|
+
klass ? RSTRING(rb_inspect(klass))->ptr : "",
|
118
|
+
mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
|
119
|
+
: "unknown",
|
120
|
+
node ? node->nd_file : "", node ? nd_line(node) : 0);
|
121
|
+
} else {
|
122
|
+
printf("EVENT: %d %s %s %d\n", event,
|
123
|
+
mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
|
124
|
+
: "unknown",
|
125
|
+
node ? node->nd_file : "", node ? nd_line(node) : 0);
|
126
|
+
}
|
127
|
+
rb_gv_set("$!", old_exception);
|
128
|
+
} while (0);
|
129
|
+
#endif
|
130
|
+
|
131
|
+
if(event & RUBY_EVENT_C_CALL) {
|
132
|
+
coverage_mark_caller();
|
133
|
+
}
|
134
|
+
if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
|
135
|
+
in_hook--;
|
136
|
+
return;
|
137
|
+
}
|
138
|
+
|
139
|
+
// printf("NODE? %s , %s\n", rb_id2name(rb_frame_this_func()), RSTRING_PTR(rb_inspect(node)));
|
140
|
+
|
141
|
+
sourcefile = rb_sourcefile();
|
142
|
+
sourceline = rb_sourceline();
|
143
|
+
|
144
|
+
if (0 == sourceline || 0 == sourcefile) {
|
145
|
+
in_hook--;
|
146
|
+
return;
|
147
|
+
}
|
148
|
+
|
149
|
+
coverage_increase_counter_cached(sourcefile, sourceline);
|
150
|
+
if(event & RUBY_EVENT_CALL)
|
151
|
+
coverage_mark_caller();
|
152
|
+
in_hook--;
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
static VALUE
|
157
|
+
cov_install_coverage_hook(VALUE self)
|
158
|
+
{
|
159
|
+
if(!coverage_hook_set_p) {
|
160
|
+
if(!coverinfo)
|
161
|
+
coverinfo = st_init_strtable();
|
162
|
+
coverage_hook_set_p = 1;
|
163
|
+
/* TODO: allow C_CALL too, since it's supported already
|
164
|
+
* the overhead is around ~30%, tested on typo */
|
165
|
+
VALUE holder = 0;
|
166
|
+
rb_add_event_hook(coverage_event_coverage_hook,
|
167
|
+
RUBY_EVENT_ALL & ~RUBY_EVENT_C_CALL &
|
168
|
+
~RUBY_EVENT_C_RETURN & ~RUBY_EVENT_CLASS, holder);
|
169
|
+
return Qtrue;
|
170
|
+
}
|
171
|
+
else
|
172
|
+
return Qfalse;
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
static int
|
177
|
+
populate_cover(st_data_t key, st_data_t value, st_data_t cover)
|
178
|
+
{
|
179
|
+
VALUE rcover;
|
180
|
+
VALUE rkey;
|
181
|
+
VALUE rval;
|
182
|
+
struct cov_array *carray;
|
183
|
+
unsigned int i;
|
184
|
+
|
185
|
+
rcover = (VALUE)cover;
|
186
|
+
carray = (struct cov_array *) value;
|
187
|
+
rkey = rb_str_new2((char*) key);
|
188
|
+
rval = rb_ary_new2(carray->len);
|
189
|
+
for(i = 0; i < carray->len; i++)
|
190
|
+
rb_ary_push(rval, UINT2NUM(carray->ptr[i]));
|
191
|
+
|
192
|
+
rb_hash_aset(rcover, rkey, rval);
|
193
|
+
|
194
|
+
return ST_CONTINUE;
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
static int
|
199
|
+
free_table(st_data_t key, st_data_t value, st_data_t ignored)
|
200
|
+
{
|
201
|
+
struct cov_array *carray;
|
202
|
+
|
203
|
+
carray = (struct cov_array *) value;
|
204
|
+
free((char *)key);
|
205
|
+
free(carray->ptr);
|
206
|
+
free(carray);
|
207
|
+
|
208
|
+
return ST_CONTINUE;
|
209
|
+
}
|
210
|
+
|
211
|
+
|
212
|
+
static VALUE
|
213
|
+
cov_remove_coverage_hook(VALUE self)
|
214
|
+
{
|
215
|
+
if(!coverage_hook_set_p)
|
216
|
+
return Qfalse;
|
217
|
+
else {
|
218
|
+
rb_remove_event_hook(coverage_event_coverage_hook);
|
219
|
+
coverage_hook_set_p = 0;
|
220
|
+
return Qtrue;
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
|
225
|
+
static VALUE
|
226
|
+
cov_generate_coverage_info(VALUE self)
|
227
|
+
{
|
228
|
+
VALUE cover;
|
229
|
+
|
230
|
+
if(rb_const_defined_at(mRCOV__, id_cover)) {
|
231
|
+
rb_mod_remove_const(mRCOV__, ID2SYM(id_cover));
|
232
|
+
}
|
233
|
+
|
234
|
+
cover = rb_hash_new();
|
235
|
+
if(coverinfo)
|
236
|
+
st_foreach(coverinfo, populate_cover, cover);
|
237
|
+
rb_define_const(mRCOV__, "COVER", cover);
|
238
|
+
|
239
|
+
return cover;
|
240
|
+
}
|
241
|
+
|
242
|
+
|
243
|
+
static VALUE
|
244
|
+
cov_reset_coverage(VALUE self)
|
245
|
+
{
|
246
|
+
if(coverage_hook_set_p) {
|
247
|
+
rb_raise(rb_eRuntimeError,
|
248
|
+
"Cannot reset the coverage info in the middle of a traced run.");
|
249
|
+
return Qnil;
|
250
|
+
}
|
251
|
+
|
252
|
+
cached_array = 0;
|
253
|
+
cached_file = 0;
|
254
|
+
st_foreach(coverinfo, free_table, Qnil);
|
255
|
+
st_free_table(coverinfo);
|
256
|
+
coverinfo = 0;
|
257
|
+
|
258
|
+
return Qnil;
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
static VALUE
|
263
|
+
cov_ABI(VALUE self)
|
264
|
+
{
|
265
|
+
VALUE ret;
|
266
|
+
|
267
|
+
ret = rb_ary_new();
|
268
|
+
rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MAJOR));
|
269
|
+
rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_MINOR));
|
270
|
+
rb_ary_push(ret, INT2FIX(RCOVRT_VERSION_REV));
|
271
|
+
|
272
|
+
return ret;
|
273
|
+
}
|
274
|
+
|
275
|
+
|
276
|
+
void
|
277
|
+
Init_rcovrt()
|
278
|
+
{
|
279
|
+
ID id_rcov = rb_intern("Rcov");
|
280
|
+
ID id_coverage__ = rb_intern("RCOV__");
|
281
|
+
ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
|
282
|
+
|
283
|
+
id_cover = rb_intern("COVER");
|
284
|
+
|
285
|
+
if(rb_const_defined(rb_cObject, id_rcov))
|
286
|
+
mRcov = rb_const_get(rb_cObject, id_rcov);
|
287
|
+
else
|
288
|
+
mRcov = rb_define_module("Rcov");
|
289
|
+
|
290
|
+
if(rb_const_defined(mRcov, id_coverage__))
|
291
|
+
mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
|
292
|
+
else
|
293
|
+
mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
|
294
|
+
|
295
|
+
if(rb_const_defined(rb_cObject, id_script_lines__))
|
296
|
+
oSCRIPT_LINES__ = rb_const_get(rb_cObject, rb_intern("SCRIPT_LINES__"));
|
297
|
+
else {
|
298
|
+
oSCRIPT_LINES__ = rb_hash_new();
|
299
|
+
rb_const_set(rb_cObject, id_script_lines__, oSCRIPT_LINES__);
|
300
|
+
}
|
301
|
+
|
302
|
+
coverage_hook_set_p = 0;
|
303
|
+
|
304
|
+
rb_define_singleton_method(mRCOV__, "install_coverage_hook",
|
305
|
+
cov_install_coverage_hook, 0);
|
306
|
+
rb_define_singleton_method(mRCOV__, "remove_coverage_hook",
|
307
|
+
cov_remove_coverage_hook, 0);
|
308
|
+
rb_define_singleton_method(mRCOV__, "generate_coverage_info",
|
309
|
+
cov_generate_coverage_info, 0);
|
310
|
+
rb_define_singleton_method(mRCOV__, "reset_coverage", cov_reset_coverage, 0);
|
311
|
+
rb_define_singleton_method(mRCOV__, "ABI", cov_ABI, 0);
|
312
|
+
|
313
|
+
Init_rcov_callsite();
|
314
|
+
}
|
315
|
+
/* vim: set sw=8 expandtab: */
|
data/ext/rcovrt/extconf.rb
CHANGED
@@ -6,8 +6,18 @@ unless RUBY_PLATFORM == 'java' then
|
|
6
6
|
have_library("gcov", "__gcov_open")
|
7
7
|
|
8
8
|
$CFLAGS << " -fprofile-arcs -ftest-coverage"
|
9
|
-
|
9
|
+
if RUBY_VERSION =~ /1.9/
|
10
|
+
$CFLAGS << ' -DRUBY_19_COMPATIBILITY'
|
11
|
+
create_makefile("rcovrt", "1.9/")
|
12
|
+
else
|
13
|
+
create_makefile("rcovrt", "1.8/")
|
14
|
+
end
|
10
15
|
else
|
11
|
-
|
16
|
+
if RUBY_VERSION =~ /1.9/
|
17
|
+
$CFLAGS << ' -DRUBY_19_COMPATIBILITY'
|
18
|
+
create_makefile("rcovrt", "1.9/")
|
19
|
+
else
|
20
|
+
create_makefile("rcovrt", "1.8/")
|
21
|
+
end
|
12
22
|
end
|
13
23
|
end
|
data/lib/rcov.rb
CHANGED
@@ -917,8 +917,8 @@ class CallSiteAnalyzer < DifferentialAnalyzer
|
|
917
917
|
def expand_name(classname_or_fullname, methodname = nil)
|
918
918
|
if methodname.nil?
|
919
919
|
case classname_or_fullname
|
920
|
-
when /(.*)#(.*)
|
921
|
-
when /(.*)\.(.*)
|
920
|
+
when /(.*)#(.*)/ then classname, methodname = $1, $2
|
921
|
+
when /(.*)\.(.*)/ then classname, methodname = "#<Class:#{$1}>", $2
|
922
922
|
else
|
923
923
|
raise ArgumentError, "Incorrect method name"
|
924
924
|
end
|
data/lib/rcov/report.rb
CHANGED
@@ -99,8 +99,8 @@ class Formatter # :nodoc:
|
|
99
99
|
@ignore_files = options[:ignore]
|
100
100
|
@dont_ignore_files = options[:dont_ignore]
|
101
101
|
@sort_criterium = case options[:sort]
|
102
|
-
when :loc
|
103
|
-
when :coverage
|
102
|
+
when :loc then lambda{|fname, finfo| finfo.num_code_lines}
|
103
|
+
when :coverage then lambda{|fname, finfo| finfo.code_coverage}
|
104
104
|
else lambda{|fname, finfo| fname}
|
105
105
|
end
|
106
106
|
@sort_reverse = options[:sort_reverse]
|
@@ -773,7 +773,7 @@ EOS
|
|
773
773
|
tr_(:class => color_classes[color_class_index]) {
|
774
774
|
td_ {
|
775
775
|
case f.name
|
776
|
-
when "TOTAL"
|
776
|
+
when "TOTAL" then
|
777
777
|
t_ { "TOTAL" }
|
778
778
|
else
|
779
779
|
a_(:href => mangle_filename(f.name)){ t_ { f.name } }
|
@@ -73,37 +73,25 @@ class TestCallSiteAnalyzer < Test::Unit::TestCase
|
|
73
73
|
|
74
74
|
def test_basic_defsite_recording
|
75
75
|
@a.run_hooked{ @o.f1 }
|
76
|
-
verify_defsite_equal(["./test/assets/sample_03.rb", 3],
|
77
|
-
|
78
|
-
verify_defsite_equal(["./test/assets/sample_03.rb", 7],
|
79
|
-
@a.defsite("Rcov::Test::Temporary::Sample03", "f2"))
|
80
|
-
verify_defsite_equal(["./test/assets/sample_03.rb", 7],
|
81
|
-
@a.defsite("Rcov::Test::Temporary::Sample03#f2"))
|
76
|
+
verify_defsite_equal(["./test/assets/sample_03.rb", 3], @a.defsite("Rcov::Test::Temporary::Sample03", "f1"))
|
77
|
+
verify_defsite_equal(["./test/assets/sample_03.rb", 7], @a.defsite("Rcov::Test::Temporary::Sample03", "f2"))
|
78
|
+
verify_defsite_equal(["./test/assets/sample_03.rb", 7], @a.defsite("Rcov::Test::Temporary::Sample03#f2"))
|
82
79
|
end
|
83
80
|
|
84
81
|
def test_basic_callsite_recording
|
85
82
|
@a.run_hooked{ @o.f1 }
|
86
83
|
assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
87
84
|
assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
88
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10},
|
89
|
-
|
90
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10},
|
91
|
-
@a.callsites("Rcov::Test::Temporary::Sample03#f2"))
|
92
|
-
#verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
|
93
|
-
# @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
94
|
-
#verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
|
95
|
-
# @a.callsites("Rcov::Test::Temporary::Sample03#f2"))
|
85
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
86
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03#f2"))
|
96
87
|
end
|
97
88
|
|
98
89
|
def test_basic_callsite_recording_API
|
99
90
|
@a.run_hooked{ @o.f1 }
|
100
91
|
assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
101
92
|
assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
102
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
103
|
-
|
104
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
105
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10},
|
106
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
93
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
94
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
107
95
|
callsites = @a.callsites("Rcov::Test::Temporary::Sample03", "f2")
|
108
96
|
callsite = callsites.keys[0]
|
109
97
|
#expand path is used here to compensate for differences between JRuby and MRI
|
@@ -117,12 +105,8 @@ class TestCallSiteAnalyzer < Test::Unit::TestCase
|
|
117
105
|
@a.run_hooked{ @o.class.g1 }
|
118
106
|
assert(@a.analyzed_classes.include?("#<Class:Rcov::Test::Temporary::Sample03>"))
|
119
107
|
assert_equal(%w[g1 g2], @a.analyzed_methods("#<Class:Rcov::Test::Temporary::Sample03>"))
|
120
|
-
verify_callsites_equal({[[class << Rcov::Test::Temporary::Sample03; self end,
|
121
|
-
|
122
|
-
@a.callsites("Rcov::Test::Temporary::Sample03.g2"))
|
123
|
-
verify_callsites_equal({[[class << Rcov::Test::Temporary::Sample03; self end,
|
124
|
-
:g1, "./test/assets/sample_03.rb", 15]] => 10},
|
125
|
-
@a.callsites("#<Class:Rcov::Test::Temporary::Sample03>","g2"))
|
108
|
+
verify_callsites_equal({[[class << Rcov::Test::Temporary::Sample03; self end, :g1, "./test/assets/sample_03.rb", 15]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03.g2"))
|
109
|
+
verify_callsites_equal({[[class << Rcov::Test::Temporary::Sample03; self end, :g1, "./test/assets/sample_03.rb", 15]] => 10}, @a.callsites("#<Class:Rcov::Test::Temporary::Sample03>","g2"))
|
126
110
|
end
|
127
111
|
|
128
112
|
|
@@ -130,24 +114,17 @@ class TestCallSiteAnalyzer < Test::Unit::TestCase
|
|
130
114
|
@a.run_hooked{ @o.f1 }
|
131
115
|
assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
132
116
|
assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
133
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
134
|
-
"./test/assets/sample_03.rb", 4]] => 10},
|
135
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
117
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
136
118
|
|
137
119
|
@a.run_hooked{ @o.f1 }
|
138
120
|
assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
139
121
|
assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
140
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
141
|
-
"./test/assets/sample_03.rb", 4]] => 20},
|
142
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
122
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 20}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
143
123
|
|
144
124
|
@a.run_hooked{ @o.f3 }
|
145
125
|
assert_equal(%w[f1 f2 f3], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
146
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
147
|
-
|
148
|
-
[[Rcov::Test::Temporary::Sample03, :f3,
|
149
|
-
"./test/assets/sample_03.rb", 11]]=>100 },
|
150
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
126
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 120,
|
127
|
+
[[Rcov::Test::Temporary::Sample03, :f3, "./test/assets/sample_03.rb", 11]] => 100 }, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
151
128
|
end
|
152
129
|
|
153
130
|
def test_reset
|
@@ -158,10 +135,7 @@ class TestCallSiteAnalyzer < Test::Unit::TestCase
|
|
158
135
|
end
|
159
136
|
assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
160
137
|
assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
161
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
162
|
-
"./test/assets/sample_03.rb", 4]] => 10},
|
163
|
-
@a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
164
|
-
|
138
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
165
139
|
end
|
166
140
|
|
167
141
|
def test_nested_callsite_recording
|
@@ -171,37 +145,27 @@ class TestCallSiteAnalyzer < Test::Unit::TestCase
|
|
171
145
|
b.run_hooked { @o.f1 }
|
172
146
|
assert(b.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
173
147
|
assert_equal(%w[f1 f2], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
174
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
175
|
-
"./test/assets/sample_03.rb", 4]] => 10},
|
176
|
-
b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
148
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
177
149
|
|
178
150
|
@o.f1
|
179
151
|
assert_equal(%w[f1 f2], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
180
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
181
|
-
"./test/assets/sample_03.rb", 4]] => 10},
|
182
|
-
b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
152
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 10}, b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
183
153
|
|
184
154
|
assert(a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
|
185
155
|
assert_equal(%w[f1 f2], a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
186
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
187
|
-
"./test/assets/sample_03.rb", 4]] => 20},
|
188
|
-
a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
156
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 20}, a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
189
157
|
end
|
158
|
+
|
190
159
|
b.run_hooked{ @o.f3 }
|
191
160
|
assert_equal(%w[f1 f2 f3], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
|
192
|
-
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1,
|
193
|
-
|
194
|
-
[[Rcov::Test::Temporary::Sample03, :f3,
|
195
|
-
"./test/assets/sample_03.rb", 11]]=>100 },
|
196
|
-
b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
161
|
+
verify_callsites_equal({[[Rcov::Test::Temporary::Sample03, :f1, "./test/assets/sample_03.rb", 4]] => 110,
|
162
|
+
[[Rcov::Test::Temporary::Sample03, :f3, "./test/assets/sample_03.rb", 11]]=>100 }, b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
|
197
163
|
end
|
198
164
|
|
199
165
|
def test_expand_name
|
200
166
|
assert_equal(["Foo", "foo"], @a.instance_eval{ expand_name("Foo#foo") })
|
201
167
|
assert_equal(["Foo", "foo"], @a.instance_eval{ expand_name("Foo", "foo") })
|
202
|
-
assert_equal(["#<Class:Foo>", "foo"],
|
203
|
-
|
204
|
-
assert_equal(["#<Class:Foo>", "foo"],
|
205
|
-
@a.instance_eval{ expand_name("#<Class:Foo>", "foo") })
|
168
|
+
assert_equal(["#<Class:Foo>", "foo"], @a.instance_eval{ expand_name("Foo.foo") })
|
169
|
+
assert_equal(["#<Class:Foo>", "foo"], @a.instance_eval{ expand_name("#<Class:Foo>", "foo") })
|
206
170
|
end
|
207
171
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
3
|
class TestCodeCoverageAnalyzer < Test::Unit::TestCase
|
4
|
-
|
4
|
+
LINES = <<-EOF.split "\n"
|
5
5
|
puts 1
|
6
6
|
if foo
|
7
7
|
bar
|
@@ -88,9 +88,9 @@ EOF
|
|
88
88
|
analyzer = Rcov::CodeCoverageAnalyzer.new
|
89
89
|
analyzer.run_hooked{ load sample_file }
|
90
90
|
line_info, cov_info, count_info = analyzer.data(sample_file)
|
91
|
-
assert_equal([1, 2, 0, 0, 1, 0, 11], count_info) unless PLATFORM =~ /java/
|
91
|
+
assert_equal([1, 2, 0, 0, 1, 0, 11], count_info) unless (defined? PLATFORM && PLATFORM =~ /java/) || RUBY_VERSION =~ /1.9/
|
92
92
|
# JRUBY reports an if x==blah as hitting this type of line once, JRUBY also optimizes this stuff so you'd have to run with --debug to get "extra" information. MRI hits it twice.
|
93
|
-
assert_equal([1,
|
93
|
+
assert_equal([1, 2, 0, 0, 1, 0, 11], count_info) if RUBY_VERSION =~ /1.9/
|
94
94
|
|
95
95
|
analyzer.reset
|
96
96
|
#set_trace_func proc { |event, file, line, id, binding, classname| printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname if (file =~ /sample_02.rb/) }
|
@@ -98,13 +98,15 @@ EOF
|
|
98
98
|
sample_file = File.join(File.dirname(__FILE__), "assets/sample_02.rb")
|
99
99
|
analyzer.run_hooked{ load sample_file }
|
100
100
|
line_info, cov_info, count_info = analyzer.data(sample_file)
|
101
|
-
assert_equal([8, 1, 0, 0, 0], count_info)
|
101
|
+
assert_equal([8, 1, 0, 0, 0], count_info) unless RUBY_VERSION =~ /1.9/
|
102
|
+
assert_equal([4, 1, 0, 0, 4], count_info) if RUBY_VERSION =~ /1.9/
|
102
103
|
|
103
104
|
analyzer.reset
|
104
105
|
assert_equal([], analyzer.analyzed_files)
|
105
106
|
analyzer.run_hooked{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
|
106
107
|
line_info, cov_info, count_info = analyzer.data(sample_file)
|
107
|
-
assert_equal([0, 1, 1, 1, 0], count_info)
|
108
|
+
assert_equal([0, 1, 1, 1, 0], count_info) unless RUBY_VERSION =~ /1.9/
|
109
|
+
assert_equal([0, 2, 1, 0, 0], count_info) if RUBY_VERSION =~ /1.9/
|
108
110
|
analyzer.run_hooked do
|
109
111
|
10.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
|
110
112
|
end
|
metadata
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spicycode-rcov
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.1.5.
|
4
|
+
version: 0.8.1.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauricio Fernandez
|
8
|
+
- Chad Humphries
|
9
|
+
- Aaron Bedra
|
8
10
|
autorequire:
|
9
11
|
bindir: bin
|
10
12
|
cert_chain:
|
11
|
-
date:
|
13
|
+
date: 2009-03-17 00:00:00 -07:00
|
12
14
|
default_executable: rcov
|
13
15
|
dependencies: []
|
14
16
|
|
@@ -19,10 +21,10 @@ executables:
|
|
19
21
|
extensions:
|
20
22
|
- ext/rcovrt/extconf.rb
|
21
23
|
extra_rdoc_files:
|
22
|
-
- readme_for_api
|
23
|
-
- readme_for_rake
|
24
|
-
- readme_for_rant
|
25
|
-
- readme_for_vim
|
24
|
+
- doc/readme_for_api
|
25
|
+
- doc/readme_for_rake
|
26
|
+
- doc/readme_for_rant
|
27
|
+
- doc/readme_for_vim
|
26
28
|
files:
|
27
29
|
- bin/rcov
|
28
30
|
- lib/rcov.rb
|
@@ -31,19 +33,21 @@ files:
|
|
31
33
|
- lib/rcov/version.rb
|
32
34
|
- lib/rcov/rant.rb
|
33
35
|
- lib/rcov/report.rb
|
34
|
-
- lib/rcov/rexml_extensions.rb
|
35
36
|
- lib/rcov/rcovtask.rb
|
36
37
|
- ext/rcovrt/extconf.rb
|
37
|
-
- ext/rcovrt/rcovrt.c
|
38
|
-
- ext/rcovrt/
|
38
|
+
- ext/rcovrt/1.8/rcovrt.c
|
39
|
+
- ext/rcovrt/1.9/rcovrt.c
|
40
|
+
- ext/rcovrt/1.8/callsite.c
|
41
|
+
- ext/rcovrt/1.9/callsite.c
|
39
42
|
- LEGAL
|
40
43
|
- LICENSE
|
41
44
|
- Rakefile
|
42
45
|
- Rantfile
|
43
|
-
- readme_for_rake
|
44
|
-
- readme_for_rant
|
45
|
-
- readme_for_vim
|
46
|
-
-
|
46
|
+
- doc/readme_for_rake
|
47
|
+
- doc/readme_for_rant
|
48
|
+
- doc/readme_for_vim
|
49
|
+
- doc/readme_for_emacs
|
50
|
+
- doc/readme_for_api
|
47
51
|
- THANKS
|
48
52
|
- test/functional_test.rb
|
49
53
|
- test/file_statistics_test.rb
|
@@ -57,14 +61,13 @@ files:
|
|
57
61
|
- test/turn_off_rcovrt.rb
|
58
62
|
- test/call_site_analyzer_test.rb
|
59
63
|
- test/assets/sample_05.rb
|
60
|
-
-
|
61
|
-
- rcov.
|
62
|
-
- rcov.el
|
64
|
+
- editor-extensions/rcov.vim
|
65
|
+
- editor-extensions/rcov.el
|
63
66
|
- setup.rb
|
64
67
|
- BLURB
|
65
68
|
- CHANGES
|
66
69
|
has_rdoc: true
|
67
|
-
homepage: http://
|
70
|
+
homepage: http://github.com/spicycode/rcov
|
68
71
|
post_install_message:
|
69
72
|
rdoc_options:
|
70
73
|
- --main
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
require 'rexml/formatters/pretty'
|
3
|
-
|
4
|
-
module Rcov
|
5
|
-
module REXMLExtensions
|
6
|
-
|
7
|
-
def self.fix_pretty_formatter_wrap
|
8
|
-
REXML::Formatters::Pretty.class_eval do
|
9
|
-
include PrettyFormatterWrapFix
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Fix for this bug: http://clint-hill.com/2008/10/02/a-bug-in-ruby-did-i-just-find-that/
|
14
|
-
# Also known from this fun exception:
|
15
|
-
#
|
16
|
-
# /usr/local/ruby/lib/ruby/1.8/rexml/formatters/pretty.rb:131:in
|
17
|
-
# `[]': no implicit conversion from nil to integer (TypeError)
|
18
|
-
#
|
19
|
-
# This bug was fixed in Ruby with this changeset http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=19487
|
20
|
-
# ...which should mean that this bug only affects Ruby 1.8.6. The latest stable version of 1.8.7 (and up) should be fine.
|
21
|
-
module PrettyFormatterWrapFix
|
22
|
-
|
23
|
-
def self.included(base)
|
24
|
-
base.class_eval do
|
25
|
-
def wrap(string, width)
|
26
|
-
# Recursively wrap string at width.
|
27
|
-
return string if string.length <= width
|
28
|
-
place = string.rindex(' ', width) # Position in string with last ' ' before cutoff
|
29
|
-
return string if place.nil?
|
30
|
-
return string[0,place] + "\n" + wrap(string[place+1..-1], width)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.init!
|
38
|
-
if RUBY_VERSION == "1.8.6"
|
39
|
-
fix_pretty_formatter_wrap
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
data/test/rexml_test.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/test_helper'
|
2
|
-
require 'rcov/rexml_extensions'
|
3
|
-
|
4
|
-
class TestRexml < Test::Unit::TestCase
|
5
|
-
|
6
|
-
def test_wrap_with_long_lines_without_spaces_should_not_break_wrap
|
7
|
-
Rcov::REXMLExtensions.fix_pretty_formatter_wrap
|
8
|
-
pretty_formatter = ::REXML::Formatters::Pretty.new
|
9
|
-
long_string = "this-is-a-long-string-without-any-spaces-to-try-to-break-rexml-formatter-and-it-is-over-100-characters-long"
|
10
|
-
pretty_formatter.instance_eval { wrap(long_string, 100) } # avoid send, it can't bypass private methods in ruby19
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_wrap_original_behavior_should_be_preserved
|
14
|
-
pretty_formatter = REXML::Formatters::Pretty.new
|
15
|
-
str = "This string should be wrapped at 40 characters"
|
16
|
-
pretty_formatter.instance_eval do
|
17
|
-
str = wrap(str, 40)
|
18
|
-
end # avoid send, it can't bypass private methods in ruby19
|
19
|
-
assert_equal("This string should be wrapped at 40\ncharacters", str)
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|