spicycode-rcov 0.8.1.5.6 → 0.8.1.5.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|