rcov 0.6.0.1-mswin32 → 0.7.0.1-mswin32

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/BLURB CHANGED
@@ -2,7 +2,7 @@
2
2
  Source code, additional information, screenshots... available at
3
3
  http://eigenclass.org/hiki.rb?rcov
4
4
  Release information:
5
- http://eigenclass.org/hiki.rb?rcov+0.6.0
5
+ http://eigenclass.org/hiki.rb?rcov+0.7.0
6
6
 
7
7
  If you're on win32, you can also find a pre-built rcovrt.so (which makes
8
8
  code coverage analysis >100 times faster) in the above-mentioned pages.
data/CHANGES CHANGED
@@ -1,6 +1,24 @@
1
1
 
2
2
  User-visible changes.
3
3
 
4
+ Since 0.6.0 (2006-06-12)
5
+ ========================
6
+ Features
7
+ --------
8
+ * coverage/callsite data from multiple runs can be aggregated (--aggregate)
9
+
10
+ Bugfixes
11
+ --------
12
+ * the SCRIPT_LINES__ workaround works better
13
+ * fixed silly bug in coverage data acquisition (line after the correct one
14
+ marked in some situations)
15
+ * avoid problems with repeated path separators in default ignore list, based
16
+ on rbconfig's data
17
+
18
+
19
+ Minor enhancements
20
+ ------------------
21
+
4
22
  Since 0.5.0 (2006-05-30)
5
23
  ========================
6
24
  Features
data/Rakefile CHANGED
@@ -48,7 +48,7 @@ Rake::TestTask.new(:test_rcovrt => ["ext/rcovrt/rcovrt.so"]) do |t|
48
48
  t.verbose = true
49
49
  end
50
50
 
51
- file "ext/rcovrt/rcovrt.so" => "ext/rcovrt/rcov.c" do
51
+ file "ext/rcovrt/rcovrt.so" => FileList["ext/rcovrt/*.c"] do
52
52
  ruby "setup.rb config"
53
53
  ruby "setup.rb setup"
54
54
  end
@@ -87,9 +87,10 @@ PKG_FILES = FileList[
87
87
  "bin/rcov",
88
88
  "lib/**/*.rb",
89
89
  "ext/rcovrt/extconf.rb",
90
- "ext/rcovrt/rcov.c",
90
+ "ext/rcovrt/*.c",
91
+ "ext/rcovrt/*.h",
91
92
  "LEGAL", "LICENSE", "Rakefile", "Rantfile", "README.*", "THANKS", "test/*.rb",
92
- "mingw-rbconfig.rb",
93
+ "mingw-rbconfig.rb", "rcov.vim",
93
94
  "setup.rb", "BLURB", "CHANGES"
94
95
  ]
95
96
 
data/THANKS CHANGED
@@ -41,3 +41,12 @@ Coda Hale:
41
41
  Tim Shadel:
42
42
  * reported that the last comment block was not being marked even when
43
43
  it was the last thing in the file
44
+
45
+ Thomas Leitner:
46
+ * reported that the SCRIPT_LINES__ workaround did not always work
47
+
48
+ Assaph Mehr:
49
+ * beta-tested 0.7.0 and found a bug in --aggregate (missing files)
50
+
51
+ Ryan Kinderman:
52
+ * suggested that -Ipath be passed to ruby instead of rcov in RcovTasks
data/bin/rcov CHANGED
@@ -56,6 +56,7 @@ options.coverage_diff_mode = :compare
56
56
  options.coverage_diff_save = false
57
57
  options.diff_cmd = "diff"
58
58
  options.report_cov_bug_for = nil
59
+ options.aggregate_file = nil
59
60
 
60
61
  EXTRA_HELP = <<-EOF
61
62
 
@@ -165,6 +166,12 @@ EOF
165
166
  "ANSI color sequences unless -n.") do
166
167
  options.textmode = :coverage
167
168
  end
169
+ opts.on("--aggregate FILE", "Aggregate data from previous runs",
170
+ "in FILE. Overwrites FILE with the",
171
+ "merged data. FILE is created if",
172
+ "necessary.") do |file|
173
+ options.aggregate_file = file
174
+ end
168
175
  opts.on("-D [FILE]", "--text-coverage-diff [FILE]",
169
176
  "Compare code coverage with saved state",
170
177
  "in FILE, defaults to coverage.info.",
@@ -177,7 +184,8 @@ EOF
177
184
  options.coverage_diff_mode = :compare
178
185
  options.coverage_diff_file = file if file && !file.empty?
179
186
  end
180
- opts.on("--save [FILE]", "Save coverage data to FILE.",
187
+ opts.on("--save [FILE]", "Save coverage data to FILE,",
188
+ "for later use with rcov -D.",
181
189
  "(default: coverage.info)") do |file|
182
190
  options.coverage_diff_save = true
183
191
  options.coverage_diff_mode = :record
@@ -289,8 +297,33 @@ require 'rcov'
289
297
 
290
298
  options.callsites = true if options.report_cov_bug_for
291
299
 
300
+ def rcov_load_aggregate_data(file)
301
+ require 'zlib'
302
+ begin
303
+ old_data = nil
304
+ Zlib::GzipReader.open(file){|gz| old_data = Marshal.load(gz) }
305
+ rescue
306
+ old_data = {}
307
+ end
308
+ old_data || {}
309
+ end
310
+
311
+ def rcov_save_aggregate_data(file)
312
+ require 'zlib'
313
+ Zlib::GzipWriter.open(file) do |f|
314
+ Marshal.dump({:callsites => $rcov_callsite_analyzer,
315
+ :coverage => $rcov_code_coverage_analyzer}, f)
316
+ end
317
+ end
318
+
292
319
  if options.callsites
293
- $rcov_callsite_analyzer = Rcov::CallSiteAnalyzer.new
320
+ if options.aggregate_file
321
+ saved_aggregate_data = rcov_load_aggregate_data(options.aggregate_file)
322
+ if saved_aggregate_data[:callsites]
323
+ $rcov_callsite_analyzer = saved_aggregate_data[:callsites]
324
+ end
325
+ end
326
+ $rcov_callsite_analyzer ||= Rcov::CallSiteAnalyzer.new
294
327
  $rcov_callsite_analyzer.install_hook
295
328
  else
296
329
  $rcov_callsite_analyzer = nil
@@ -333,12 +366,19 @@ end
333
366
 
334
367
  formatters << make_formatter[Rcov::TextCoverageDiff] if options.coverage_diff_save
335
368
 
336
- $rcov_code_coverage_analyzer = Rcov::CodeCoverageAnalyzer.new
369
+ if options.aggregate_file
370
+ saved_aggregate_data ||= rcov_load_aggregate_data(options.aggregate_file)
371
+ if saved_aggregate_data[:coverage]
372
+ $rcov_code_coverage_analyzer = saved_aggregate_data[:coverage]
373
+ end
374
+ end
375
+ $rcov_code_coverage_analyzer ||= Rcov::CodeCoverageAnalyzer.new
337
376
 
338
377
  # must be registered before test/unit puts its own
339
378
  END {
340
379
  $rcov_code_coverage_analyzer.remove_hook
341
380
  $rcov_callsite_analyzer.remove_hook if $rcov_callsite_analyzer
381
+ rcov_save_aggregate_data(options.aggregate_file) if options.aggregate_file
342
382
  $rcov_code_coverage_analyzer.dump_coverage_info(formatters)
343
383
  if options.report_cov_bug_for
344
384
  defsite = $rcov_callsite_analyzer.defsite(options.report_cov_bug_for)
@@ -0,0 +1,242 @@
1
+ #include <ruby.h>
2
+ #include <env.h>
3
+ #include <node.h>
4
+ #include <st.h>
5
+ #include <stdlib.h>
6
+
7
+
8
+ static char callsite_hook_set_p;
9
+
10
+ typedef struct {
11
+ char *sourcefile;
12
+ unsigned int sourceline;
13
+ VALUE curr_meth;
14
+ } type_def_site;
15
+ static VALUE caller_info = 0;
16
+ static VALUE method_def_site_info = 0;
17
+
18
+ static caller_stack_len = 1;
19
+
20
+ /*
21
+ *
22
+ * callsite hook and associated functions
23
+ *
24
+ * */
25
+
26
+ static VALUE
27
+ record_callsite_info(VALUE args)
28
+ {
29
+ VALUE caller_ary;
30
+ VALUE curr_meth;
31
+ VALUE count_hash;
32
+ VALUE count;
33
+ VALUE *pargs = (VALUE *)args;
34
+
35
+ caller_ary = pargs[0];
36
+ curr_meth = pargs[1];
37
+ count_hash = rb_hash_aref(caller_info, curr_meth);
38
+ if(TYPE(count_hash) != T_HASH) {
39
+ /* Qnil, anything else should be impossible unless somebody's been
40
+ * messing with ObjectSpace */
41
+ count_hash = rb_hash_new();
42
+ rb_hash_aset(caller_info, curr_meth, count_hash);
43
+ }
44
+ count = rb_hash_aref(count_hash, caller_ary);
45
+ if(count == Qnil)
46
+ count = INT2FIX(0);
47
+ count = INT2FIX(FIX2UINT(count) + 1);
48
+ rb_hash_aset(count_hash, caller_ary, count);
49
+ /*
50
+ printf("CALLSITE: %s -> %s %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
51
+ RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
52
+ */
53
+
54
+ return Qnil;
55
+ }
56
+
57
+
58
+ static VALUE
59
+ record_method_def_site(VALUE args)
60
+ {
61
+ type_def_site *pargs = (type_def_site *)args;
62
+ VALUE def_site_info;
63
+ VALUE hash;
64
+
65
+ if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
66
+ return Qnil;
67
+ def_site_info = rb_ary_new();
68
+ rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
69
+ rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
70
+ rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
71
+ /*
72
+ printf("DEFSITE: %s:%d for %s\n", pargs->sourcefile, pargs->sourceline+1,
73
+ RSTRING(rb_inspect(pargs->curr_meth))->ptr);
74
+ */
75
+
76
+ return Qnil;
77
+ }
78
+
79
+ static VALUE
80
+ callsite_custom_backtrace(int lev)
81
+ {
82
+ struct FRAME *frame = ruby_frame;
83
+ VALUE ary;
84
+ NODE *n;
85
+ VALUE level;
86
+ VALUE klass;
87
+
88
+ ary = rb_ary_new();
89
+ if (frame->last_func == ID_ALLOCATOR) {
90
+ frame = frame->prev;
91
+ }
92
+ for (; frame && (n = frame->node); frame = frame->prev) {
93
+ if (frame->prev && frame->prev->last_func) {
94
+ if (frame->prev->node == n) continue;
95
+ level = rb_ary_new();
96
+ klass = frame->prev->last_class ? frame->prev->last_class : Qnil;
97
+ if(TYPE(klass) == T_ICLASS) {
98
+ klass = CLASS_OF(klass);
99
+ }
100
+ rb_ary_push(level, klass);
101
+ rb_ary_push(level, ID2SYM(frame->prev->last_func));
102
+ rb_ary_push(level, rb_str_new2(n->nd_file));
103
+ rb_ary_push(level, INT2NUM(nd_line(n)));
104
+ }
105
+ else {
106
+ level = rb_ary_new();
107
+ rb_ary_push(level, Qnil);
108
+ rb_ary_push(level, Qnil);
109
+ rb_ary_push(level, rb_str_new2(n->nd_file));
110
+ rb_ary_push(level, INT2NUM(nd_line(n)));
111
+ }
112
+ rb_ary_push(ary, level);
113
+ if(--lev == 0)
114
+ break;
115
+ }
116
+
117
+ return ary;
118
+ }
119
+
120
+ static void
121
+ coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE self,
122
+ ID mid, VALUE klass)
123
+ {
124
+ VALUE caller_ary;
125
+ VALUE curr_meth;
126
+ VALUE args[2];
127
+ int status;
128
+
129
+ caller_ary = callsite_custom_backtrace(caller_stack_len);
130
+
131
+ if(TYPE(klass) == T_ICLASS) {
132
+ klass = CLASS_OF(klass);
133
+ }
134
+ curr_meth = rb_ary_new();
135
+ rb_ary_push(curr_meth, klass);
136
+ rb_ary_push(curr_meth, ID2SYM(mid));
137
+
138
+ args[0] = caller_ary;
139
+ args[1] = curr_meth;
140
+ rb_protect(record_callsite_info, (VALUE)args, &status);
141
+ if(!status && node) {
142
+ type_def_site args;
143
+
144
+ args.sourcefile = node->nd_file;
145
+ args.sourceline = nd_line(node) - 1;
146
+ args.curr_meth = curr_meth;
147
+ rb_protect(record_method_def_site, (VALUE)&args, NULL);
148
+ }
149
+ if(status)
150
+ rb_gv_set("$!", Qnil);
151
+ }
152
+
153
+
154
+ static VALUE
155
+ cov_install_callsite_hook(VALUE self)
156
+ {
157
+ if(!callsite_hook_set_p) {
158
+ if(TYPE(caller_info) != T_HASH)
159
+ caller_info = rb_hash_new();
160
+ callsite_hook_set_p = 1;
161
+ rb_add_event_hook(coverage_event_callsite_hook,
162
+ RUBY_EVENT_CALL);
163
+
164
+ return Qtrue;
165
+ } else
166
+ return Qfalse;
167
+ }
168
+
169
+
170
+ static VALUE
171
+ cov_remove_callsite_hook(VALUE self)
172
+ {
173
+ if(!callsite_hook_set_p)
174
+ return Qfalse;
175
+ else {
176
+ rb_remove_event_hook(coverage_event_callsite_hook);
177
+ callsite_hook_set_p = 0;
178
+ return Qtrue;
179
+ }
180
+ }
181
+
182
+
183
+ static VALUE
184
+ cov_generate_callsite_info(VALUE self)
185
+ {
186
+ VALUE ret;
187
+
188
+ ret = rb_ary_new();
189
+ rb_ary_push(ret, caller_info);
190
+ rb_ary_push(ret, method_def_site_info);
191
+ return ret;
192
+ }
193
+
194
+
195
+ static VALUE
196
+ cov_reset_callsite(VALUE self)
197
+ {
198
+ if(callsite_hook_set_p) {
199
+ rb_raise(rb_eRuntimeError,
200
+ "Cannot reset the callsite info in the middle of a traced run.");
201
+ return Qnil;
202
+ }
203
+
204
+ caller_info = rb_hash_new();
205
+ method_def_site_info = rb_hash_new();
206
+ return Qnil;
207
+ }
208
+
209
+ void
210
+ Init_rcov_callsite()
211
+ {
212
+ VALUE mRcov;
213
+ VALUE mRCOV__;
214
+ ID id_rcov = rb_intern("Rcov");
215
+ ID id_coverage__ = rb_intern("RCOV__");
216
+ ID id_script_lines__ = rb_intern("SCRIPT_LINES__");
217
+
218
+ if(rb_const_defined(rb_cObject, id_rcov))
219
+ mRcov = rb_const_get(rb_cObject, id_rcov);
220
+ else
221
+ mRcov = rb_define_module("Rcov");
222
+
223
+ if(rb_const_defined(mRcov, id_coverage__))
224
+ mRCOV__ = rb_const_get_at(mRcov, id_coverage__);
225
+ else
226
+ mRCOV__ = rb_define_module_under(mRcov, "RCOV__");
227
+
228
+ callsite_hook_set_p = 0;
229
+ caller_info = rb_hash_new();
230
+ method_def_site_info = rb_hash_new();
231
+ rb_gc_register_address(&caller_info);
232
+ rb_gc_register_address(&method_def_site_info);
233
+
234
+ rb_define_singleton_method(mRCOV__, "install_callsite_hook",
235
+ cov_install_callsite_hook, 0);
236
+ rb_define_singleton_method(mRCOV__, "remove_callsite_hook",
237
+ cov_remove_callsite_hook, 0);
238
+ rb_define_singleton_method(mRCOV__, "generate_callsite_info",
239
+ cov_generate_callsite_info, 0);
240
+ rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
241
+ }
242
+ /* vim: set sw=8 expandtab: */
@@ -5,6 +5,8 @@
5
5
  #include <st.h>
6
6
  #include <stdlib.h>
7
7
 
8
+ #define COVERAGE_DEBUG_EVENTS 0
9
+
8
10
  #define RCOVRT_VERSION_MAJOR 2
9
11
  #define RCOVRT_VERSION_MINOR 0
10
12
  #define RCOVRT_VERSION_REV 0
@@ -15,7 +17,6 @@ static VALUE oSCRIPT_LINES__;
15
17
  static ID id_cover;
16
18
  static st_table* coverinfo = 0;
17
19
  static char coverage_hook_set_p;
18
- static char callsite_hook_set_p;
19
20
 
20
21
  struct cov_array {
21
22
  unsigned int len;
@@ -25,204 +26,6 @@ struct cov_array {
25
26
  static struct cov_array *cached_array = 0;
26
27
  static char *cached_file = 0;
27
28
 
28
- typedef struct {
29
- char *sourcefile;
30
- unsigned int sourceline;
31
- VALUE curr_meth;
32
- } type_def_site;
33
- static VALUE caller_info = 0;
34
- static VALUE method_def_site_info = 0;
35
-
36
- static caller_stack_len = 1;
37
-
38
- /*
39
- *
40
- * callsite hook and associated functions
41
- *
42
- * */
43
-
44
- static VALUE
45
- record_callsite_info(VALUE args)
46
- {
47
- VALUE caller_ary;
48
- VALUE curr_meth;
49
- VALUE count_hash;
50
- VALUE count;
51
- VALUE *pargs = (VALUE *)args;
52
-
53
- caller_ary = pargs[0];
54
- curr_meth = pargs[1];
55
- count_hash = rb_hash_aref(caller_info, curr_meth);
56
- if(TYPE(count_hash) != T_HASH) {
57
- /* Qnil, anything else should be impossible unless somebody's been
58
- * messing with ObjectSpace */
59
- count_hash = rb_hash_new();
60
- rb_hash_aset(caller_info, curr_meth, count_hash);
61
- }
62
- count = rb_hash_aref(count_hash, caller_ary);
63
- if(count == Qnil)
64
- count = INT2FIX(0);
65
- count = INT2FIX(FIX2UINT(count) + 1);
66
- rb_hash_aset(count_hash, caller_ary, count);
67
- /*
68
- printf("CALLSITE: %s -> %s %d\n", RSTRING(rb_inspect(curr_meth))->ptr,
69
- RSTRING(rb_inspect(caller_ary))->ptr, FIX2INT(count));
70
- */
71
-
72
- return Qnil;
73
- }
74
-
75
-
76
- static VALUE
77
- record_method_def_site(VALUE args)
78
- {
79
- type_def_site *pargs = (type_def_site *)args;
80
- VALUE def_site_info;
81
- VALUE hash;
82
-
83
- if( RTEST(rb_hash_aref(method_def_site_info, pargs->curr_meth)) )
84
- return Qnil;
85
- def_site_info = rb_ary_new();
86
- rb_ary_push(def_site_info, rb_str_new2(pargs->sourcefile));
87
- rb_ary_push(def_site_info, INT2NUM(pargs->sourceline+1));
88
- rb_hash_aset(method_def_site_info, pargs->curr_meth, def_site_info);
89
- /*
90
- printf("DEFSITE: %s:%d for %s\n", pargs->sourcefile, pargs->sourceline+1,
91
- RSTRING(rb_inspect(pargs->curr_meth))->ptr);
92
- */
93
-
94
- return Qnil;
95
- }
96
-
97
- static VALUE
98
- callsite_custom_backtrace(int lev)
99
- {
100
- struct FRAME *frame = ruby_frame;
101
- VALUE ary;
102
- NODE *n;
103
- VALUE level;
104
- VALUE klass;
105
-
106
- ary = rb_ary_new();
107
- if (frame->last_func == ID_ALLOCATOR) {
108
- frame = frame->prev;
109
- }
110
- for (; frame && (n = frame->node); frame = frame->prev) {
111
- if (frame->prev && frame->prev->last_func) {
112
- if (frame->prev->node == n) continue;
113
- level = rb_ary_new();
114
- klass = frame->prev->last_class ? frame->prev->last_class : Qnil;
115
- if(TYPE(klass) == T_ICLASS) {
116
- klass = CLASS_OF(klass);
117
- }
118
- rb_ary_push(level, klass);
119
- rb_ary_push(level, ID2SYM(frame->prev->last_func));
120
- rb_ary_push(level, rb_str_new2(n->nd_file));
121
- rb_ary_push(level, INT2NUM(nd_line(n)));
122
- }
123
- else {
124
- level = rb_ary_new();
125
- rb_ary_push(level, Qnil);
126
- rb_ary_push(level, Qnil);
127
- rb_ary_push(level, rb_str_new2(n->nd_file));
128
- rb_ary_push(level, INT2NUM(nd_line(n)));
129
- }
130
- rb_ary_push(ary, level);
131
- if(--lev == 0)
132
- break;
133
- }
134
-
135
- return ary;
136
- }
137
-
138
- static void
139
- coverage_event_callsite_hook(rb_event_t event, NODE *node, VALUE self,
140
- ID mid, VALUE klass)
141
- {
142
- VALUE caller_ary;
143
- VALUE curr_meth;
144
- VALUE args[2];
145
- int status;
146
-
147
- caller_ary = callsite_custom_backtrace(caller_stack_len);
148
-
149
- if(TYPE(klass) == T_ICLASS) {
150
- klass = CLASS_OF(klass);
151
- }
152
- curr_meth = rb_ary_new();
153
- rb_ary_push(curr_meth, klass);
154
- rb_ary_push(curr_meth, ID2SYM(mid));
155
-
156
- args[0] = caller_ary;
157
- args[1] = curr_meth;
158
- rb_protect(record_callsite_info, (VALUE)args, &status);
159
- if(!status && node) {
160
- type_def_site args;
161
-
162
- args.sourcefile = node->nd_file;
163
- args.sourceline = nd_line(node) - 1;
164
- args.curr_meth = curr_meth;
165
- rb_protect(record_method_def_site, (VALUE)&args, NULL);
166
- }
167
- if(status)
168
- rb_gv_set("$!", Qnil);
169
- }
170
-
171
-
172
- static VALUE
173
- cov_install_callsite_hook(VALUE self)
174
- {
175
- if(!callsite_hook_set_p) {
176
- if(TYPE(caller_info) != T_HASH)
177
- caller_info = rb_hash_new();
178
- callsite_hook_set_p = 1;
179
- rb_add_event_hook(coverage_event_callsite_hook,
180
- RUBY_EVENT_CALL);
181
-
182
- return Qtrue;
183
- } else
184
- return Qfalse;
185
- }
186
-
187
-
188
- static VALUE
189
- cov_remove_callsite_hook(VALUE self)
190
- {
191
- if(!callsite_hook_set_p)
192
- return Qfalse;
193
- else {
194
- rb_remove_event_hook(coverage_event_callsite_hook);
195
- callsite_hook_set_p = 0;
196
- return Qtrue;
197
- }
198
- }
199
-
200
-
201
- static VALUE
202
- cov_generate_callsite_info(VALUE self)
203
- {
204
- VALUE ret;
205
-
206
- ret = rb_ary_new();
207
- rb_ary_push(ret, caller_info);
208
- rb_ary_push(ret, method_def_site_info);
209
- return ret;
210
- }
211
-
212
-
213
- static VALUE
214
- cov_reset_callsite(VALUE self)
215
- {
216
- if(callsite_hook_set_p) {
217
- rb_raise(rb_eRuntimeError,
218
- "Cannot reset the callsite info in the middle of a traced run.");
219
- return Qnil;
220
- }
221
-
222
- caller_info = rb_hash_new();
223
- method_def_site_info = rb_hash_new();
224
- return Qnil;
225
- }
226
29
 
227
30
  /*
228
31
  *
@@ -272,10 +75,10 @@ coverage_mark_caller()
272
75
  for (; frame && (n = frame->node); frame = frame->prev) {
273
76
  if (frame->prev && frame->prev->last_func) {
274
77
  if (frame->prev->node == n) continue;
275
- coverage_increase_counter_uncached(n->nd_file, nd_line(n), 1);
78
+ coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
276
79
  }
277
80
  else {
278
- coverage_increase_counter_uncached(n->nd_file, nd_line(n), 1);
81
+ coverage_increase_counter_uncached(n->nd_file, nd_line(n) - 1, 1);
279
82
  }
280
83
  break;
281
84
  }
@@ -300,19 +103,56 @@ coverage_event_coverage_hook(rb_event_t event, NODE *node, VALUE self,
300
103
  {
301
104
  char *sourcefile;
302
105
  unsigned int sourceline;
106
+ static unsigned int in_hook = 0;
303
107
 
304
- if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS))
108
+ if(in_hook) {
305
109
  return;
110
+ }
111
+
112
+ in_hook++;
113
+
114
+ #if COVERAGE_DEBUG_EVENTS
115
+ do {
116
+ int status;
117
+ VALUE old_exception;
118
+ old_exception = rb_gv_get("$!");
119
+ rb_protect(rb_inspect, klass, &status);
120
+ if(!status) {
121
+ printf("EVENT: %d %s %s %s %d\n", event,
122
+ klass ? RSTRING(rb_inspect(klass))->ptr : "",
123
+ mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
124
+ : "unknown",
125
+ node ? node->nd_file : "", node ? nd_line(node) : 0);
126
+ } else {
127
+ printf("EVENT: %d %s %s %d\n", event,
128
+ mid ? (mid == ID_ALLOCATOR ? "ID_ALLOCATOR" : rb_id2name(mid))
129
+ : "unknown",
130
+ node ? node->nd_file : "", node ? nd_line(node) : 0);
131
+ }
132
+ rb_gv_set("$!", old_exception);
133
+ } while (0);
134
+ #endif
135
+
136
+ if(event & RUBY_EVENT_C_CALL) {
137
+ coverage_mark_caller();
138
+ }
139
+ if(event & (RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN | RUBY_EVENT_CLASS)) {
140
+ in_hook--;
141
+ return;
142
+ }
306
143
 
307
- if(node == NULL)
144
+ if(node == NULL) {
145
+ in_hook--;
308
146
  return;
147
+ }
309
148
 
310
149
  sourcefile = node->nd_file;
311
150
  sourceline = nd_line(node) - 1;
312
151
 
313
152
  coverage_increase_counter_cached(sourcefile, sourceline);
314
- if(event == RUBY_EVENT_CALL)
153
+ if(event & RUBY_EVENT_CALL)
315
154
  coverage_mark_caller();
155
+ in_hook--;
316
156
  }
317
157
 
318
158
 
@@ -323,6 +163,8 @@ cov_install_coverage_hook(VALUE self)
323
163
  if(!coverinfo)
324
164
  coverinfo = st_init_strtable();
325
165
  coverage_hook_set_p = 1;
166
+ /* TODO: allow C_CALL too, since it's supported already
167
+ * the overhead is around ~30%, tested on typo */
326
168
  rb_add_event_hook(coverage_event_coverage_hook,
327
169
  RUBY_EVENT_ALL & ~RUBY_EVENT_C_CALL &
328
170
  ~RUBY_EVENT_C_RETURN & ~RUBY_EVENT_CLASS);
@@ -461,27 +303,17 @@ Init_rcovrt()
461
303
  rb_const_set(rb_cObject, id_script_lines__, oSCRIPT_LINES__);
462
304
  }
463
305
 
464
- caller_info = rb_hash_new();
465
- method_def_site_info = rb_hash_new();
466
- rb_gc_register_address(&caller_info);
467
- rb_gc_register_address(&method_def_site_info);
468
-
469
306
  coverage_hook_set_p = 0;
470
307
 
471
308
  rb_define_singleton_method(mRCOV__, "install_coverage_hook",
472
309
  cov_install_coverage_hook, 0);
473
310
  rb_define_singleton_method(mRCOV__, "remove_coverage_hook",
474
311
  cov_remove_coverage_hook, 0);
475
- rb_define_singleton_method(mRCOV__, "install_callsite_hook",
476
- cov_install_callsite_hook, 0);
477
- rb_define_singleton_method(mRCOV__, "remove_callsite_hook",
478
- cov_remove_callsite_hook, 0);
479
312
  rb_define_singleton_method(mRCOV__, "generate_coverage_info",
480
313
  cov_generate_coverage_info, 0);
481
- rb_define_singleton_method(mRCOV__, "generate_callsite_info",
482
- cov_generate_callsite_info, 0);
483
314
  rb_define_singleton_method(mRCOV__, "reset_coverage", cov_reset_coverage, 0);
484
- rb_define_singleton_method(mRCOV__, "reset_callsite", cov_reset_callsite, 0);
485
315
  rb_define_singleton_method(mRCOV__, "ABI", cov_ABI, 0);
316
+
317
+ Init_rcov_callsite();
486
318
  }
487
319
  /* vim: set sw=8 expandtab: */
data/lib/rcov/rcovtask.rb CHANGED
@@ -112,8 +112,8 @@ module Rcov
112
112
  else %!"#{rcov_path}"!
113
113
  end
114
114
  ruby_opts = @ruby_opts.clone
115
- ruby_opts.push run_code
116
115
  ruby_opts.push( "-I#{lib_path}" )
116
+ ruby_opts.push run_code
117
117
  ruby_opts.push( "-w" ) if @warning
118
118
  ruby ruby_opts.join(" ") + " " + option_list +
119
119
  %[ -o "#{@output_dir}" ] +
data/lib/rcov/report.rb CHANGED
@@ -4,8 +4,14 @@
4
4
  module Rcov
5
5
 
6
6
  class Formatter # :nodoc:
7
- ignore_files = [/\A#{Regexp.escape(Config::CONFIG["libdir"])}/, /\btc_[^.]*.rb/,
8
- /_test\.rb\z/, /\btest\//, /\bvendor\//, /\A#{Regexp.escape(__FILE__)}\z/]
7
+ require 'pathname'
8
+ ignore_files = [
9
+ /\A#{Regexp.escape(Pathname.new(Config::CONFIG["libdir"]).cleanpath.to_s)}/,
10
+ /\btc_[^.]*.rb/,
11
+ /_test\.rb\z/,
12
+ /\btest\//,
13
+ /\bvendor\//,
14
+ /\A#{Regexp.escape(__FILE__)}\z/]
9
15
  DEFAULT_OPTS = {:ignore => ignore_files, :sort => :name, :sort_reverse => false,
10
16
  :output_threshold => 101, :dont_ignore => [],
11
17
  :callsite_analyzer => nil, :comments_run_by_default => false}
data/lib/rcov/version.rb CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  module Rcov
6
6
 
7
- VERSION = "0.6.0"
8
- RELEASE_DATE = "2006-06-12"
7
+ VERSION = "0.7.0"
8
+ RELEASE_DATE = "2006/08/04"
9
9
  RCOVRT_ABI = [2,0,0]
10
10
  UPSTREAM_URL = "http://eigenclass.org/hiki.rb?rcov"
11
11
 
data/lib/rcov.rb CHANGED
@@ -559,6 +559,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer
559
559
  # Return an array with the names of the files whose code was executed inside
560
560
  # the block given to #run_hooked or between #install_hook and #remove_hook.
561
561
  def analyzed_files
562
+ update_script_lines__
562
563
  raw_data_relative.select do |file, lines|
563
564
  @script_lines__.has_key?(file)
564
565
  end.map{|fname,| fname}
@@ -581,6 +582,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer
581
582
  # reset the data at any time with #reset to start from scratch.
582
583
  def data(filename)
583
584
  raw_data = raw_data_relative
585
+ update_script_lines__
584
586
  unless @script_lines__.has_key?(filename) &&
585
587
  raw_data.has_key?(filename)
586
588
  return nil
@@ -611,6 +613,7 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer
611
613
  def reset; super end
612
614
 
613
615
  def dump_coverage_info(formatters) # :nodoc:
616
+ update_script_lines__
614
617
  raw_data_relative.each do |file, lines|
615
618
  next if @script_lines__.has_key?(file) == false
616
619
  lines = @script_lines__[file]
@@ -690,19 +693,58 @@ class CodeCoverageAnalyzer < DifferentialAnalyzer
690
693
  ! different
691
694
  end
692
695
 
693
- # FIXME find all prime factors, try them all
694
- factors = (2..10).to_a.reverse
696
+ factors = braindead_factorize(line_info.size)
695
697
  factors.each do |n|
696
698
  if is_repeated[n]
697
699
  line_info = line_info[0, line_info.size / n]
698
700
  coverage_info = coverage_info[0, coverage_info.size / n]
699
701
  count_info = count_info[0, count_info.size / n]
700
702
  end
701
- end
703
+ end if factors.size > 1 # don't even try if it's prime
702
704
 
703
705
  [line_info, coverage_info, count_info]
704
706
  end
705
707
 
708
+ def braindead_factorize(num)
709
+ return [0] if num == 0
710
+ return [-1] + braindead_factorize(-num) if num < 0
711
+ factors = []
712
+ while num % 2 == 0
713
+ factors << 2
714
+ num /= 2
715
+ end
716
+ size = num
717
+ n = 3
718
+ max = Math.sqrt(num)
719
+ while n <= max && n <= size
720
+ while size % n == 0
721
+ size /= n
722
+ factors << n
723
+ end
724
+ n += 2
725
+ end
726
+ factors << size if size != 1
727
+ factors
728
+ end
729
+
730
+ def update_script_lines__
731
+ @script_lines__ = @script_lines__.merge(SCRIPT_LINES__)
732
+ end
733
+
734
+ public
735
+ def marshal_dump # :nodoc:
736
+ # @script_lines__ is updated just before serialization so as to avoid
737
+ # missing files in SCRIPT_LINES__
738
+ ivs = {}
739
+ update_script_lines__
740
+ instance_variables.each{|iv| ivs[iv] = instance_variable_get(iv)}
741
+ ivs
742
+ end
743
+
744
+ def marshal_load(ivs) # :nodoc:
745
+ ivs.each_pair{|iv, val| instance_variable_set(iv, val)}
746
+ end
747
+
706
748
  end # CodeCoverageAnalyzer
707
749
 
708
750
  # A CallSiteAnalyzer can be used to obtain information about:
data/lib/rcovrt.so CHANGED
Binary file
data/mingw-rbconfig.rb CHANGED
@@ -7,8 +7,8 @@
7
7
  # mswin32 builds) is installed under $HOME/ruby-mingw32.
8
8
 
9
9
  module Config
10
- RUBY_VERSION == "1.8.4" or
11
- raise "ruby lib version (1.8.4) doesn't match executable version (#{RUBY_VERSION})"
10
+ #RUBY_VERSION == "1.8.5" or
11
+ # raise "ruby lib version (1.8.5) doesn't match executable version (#{RUBY_VERSION})"
12
12
 
13
13
  TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/i386-mingw32")
14
14
  DESTDIR = '' unless defined? DESTDIR
data/rcov.vim ADDED
@@ -0,0 +1,38 @@
1
+ " Vim compiler file
2
+ " Language: Ruby
3
+ " Function: Code coverage information with rcov
4
+ " Maintainer: Mauricio Fernandez <mfp at acm dot org>
5
+ " Info:
6
+ " URL: http://eigenclass.org/hiki.rb?rcov
7
+ " ----------------------------------------------------------------------------
8
+ "
9
+ " Changelog:
10
+ " 0.1: initial version, shipped with rcov 0.6.0
11
+ "
12
+ " Comments:
13
+ " Initial attempt.
14
+ " ----------------------------------------------------------------------------
15
+
16
+ if exists("current_compiler")
17
+ finish
18
+ endif
19
+ let current_compiler = "rcov"
20
+
21
+ if exists(":CompilerSet") != 2 " older Vim always used :setlocal
22
+ command -nargs=* CompilerSet setlocal <args>
23
+ endif
24
+
25
+ let s:cpo_save = &cpo
26
+ set cpo-=C
27
+
28
+ CompilerSet makeprg=rake\ $*\ RCOVOPTS=\"-D\ --no-html\ --no-color\"\ $*
29
+
30
+ CompilerSet errorformat=
31
+ \%+W\#\#\#\ %f:%l\,
32
+ \%-C\ \ \ ,
33
+ \%-C!!\
34
+
35
+ let &cpo = s:cpo_save
36
+ unlet s:cpo_save
37
+
38
+ " vim: nowrap sw=2 sts=2 ts=8 ff=unix :
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
2
+ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: rcov
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.6.0.1
7
- date: 2006-06-12 00:00:00 +02:00
6
+ version: 0.7.0.1
7
+ date: 2006-08-04 00:00:00 +02:00
8
8
  summary: Code coverage analysis tool for Ruby
9
9
  require_paths:
10
10
  - lib
@@ -25,6 +25,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: mswin32
26
26
  signing_key:
27
27
  cert_chain:
28
+ post_install_message:
28
29
  authors:
29
30
  - Mauricio Fernandez
30
31
  files:
@@ -36,7 +37,8 @@ files:
36
37
  - lib/rcov/rant.rb
37
38
  - lib/rcov/report.rb
38
39
  - ext/rcovrt/extconf.rb
39
- - ext/rcovrt/rcov.c
40
+ - ext/rcovrt/rcovrt.c
41
+ - ext/rcovrt/callsite.c
40
42
  - LEGAL
41
43
  - LICENSE
42
44
  - Rakefile
@@ -55,6 +57,7 @@ files:
55
57
  - test/turn_off_rcovrt.rb
56
58
  - test/test_CallSiteAnalyzer.rb
57
59
  - mingw-rbconfig.rb
60
+ - rcov.vim
58
61
  - setup.rb
59
62
  - BLURB
60
63
  - CHANGES