summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c14
-rw-r--r--ext/coverage/coverage.c18
-rw-r--r--test/coverage/test_coverage.rb25
-rw-r--r--thread.c28
4 files changed, 83 insertions, 2 deletions
diff --git a/compile.c b/compile.c
index 0c317d4488..026eb3b18a 100644
--- a/compile.c
+++ b/compile.c
@@ -277,6 +277,19 @@ struct iseq_compile_data_ensure_node_stack {
ADD_INSN2((seq), (line), trace2, INT2FIX(RUBY_EVENT_COVERAGE), INT2FIX(counter_idx * 16 + COVERAGE_INDEX_BRANCHES)); \
} \
} while (0)
+#define ADD_TRACE_METHOD_COVERAGE(seq, line, method_name) \
+ do { \
+ if (ISEQ_COVERAGE(iseq) && \
+ ISEQ_METHOD_COVERAGE(iseq) && \
+ (line) > 0) { \
+ VALUE methods = ISEQ_METHOD_COVERAGE(iseq); \
+ long counter_idx = RARRAY_LEN(methods) / 3; \
+ rb_ary_push(methods, ID2SYM(method_name)); \
+ rb_ary_push(methods, INT2FIX(line)); \
+ rb_ary_push(methods, INT2FIX(0)); \
+ ADD_INSN2((seq), (line), trace2, INT2FIX(RUBY_EVENT_COVERAGE), INT2FIX(counter_idx * 16 + COVERAGE_INDEX_METHODS)); \
+ } \
+ } while (0)
#define ADD_TRACE(seq, line, event) \
do { \
@@ -637,6 +650,7 @@ rb_iseq_compile_node(rb_iseq_t *iseq, NODE *node)
case ISEQ_TYPE_METHOD:
{
ADD_TRACE(ret, FIX2INT(iseq->body->location.first_lineno), RUBY_EVENT_CALL);
+ ADD_TRACE_METHOD_COVERAGE(ret, FIX2INT(iseq->body->location.first_lineno), rb_intern_str(iseq->body->location.label));
CHECK(COMPILE(ret, "scoped node", node->nd_body));
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
break;
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 5bf85631b4..dd3819cb56 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -92,6 +92,22 @@ branch_coverage(VALUE branches)
return ret;
}
+static VALUE
+method_coverage(VALUE methods)
+{
+ VALUE ret = rb_hash_new();
+ int i, id;
+
+ for (i = 0; i < RARRAY_LEN(methods); ) {
+ VALUE method_name = RARRAY_AREF(methods, i++);
+ VALUE lineno = RARRAY_AREF(methods, i++);
+ VALUE counter = RARRAY_AREF(methods, i++);
+ rb_hash_aset(ret, rb_ary_new_from_args(3, method_name, INT2FIX(id++), lineno), counter);
+ }
+
+ return ret;
+}
+
static int
coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
{
@@ -121,7 +137,7 @@ coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
}
if (methods) {
- rb_hash_aset(h, ID2SYM(rb_intern("methods")), methods);
+ rb_hash_aset(h, ID2SYM(rb_intern("methods")), method_coverage(methods));
}
rb_hash_freeze(h);
diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb
index af22d98e6c..7f210c2fab 100644
--- a/test/coverage/test_coverage.rb
+++ b/test/coverage/test_coverage.rb
@@ -280,4 +280,29 @@ class TestCoverage < Test::Unit::TestCase
}
}
end
+
+ def test_method_coverage
+ Dir.mktmpdir {|tmp|
+ Dir.chdir(tmp) {
+ File.open("test.rb", "w") do |f|
+ f.puts 'def foo; end'
+ f.puts 'def bar'
+ f.puts 'end'
+ f.puts 'def baz; end'
+ f.puts ''
+ f.puts 'foo'
+ f.puts 'foo'
+ f.puts 'bar'
+ end
+
+ assert_in_out_err(%w[-W0 -rcoverage], <<-"end;", ["{:methods=>{[:foo, 0, 1]=>2, [:bar, 1, 2]=>1, [:baz, 2, 4]=>0}}"], [])
+ ENV["COVERAGE_EXPERIMENTAL_MODE"] = "true"
+ Coverage.start(methods: true)
+ tmp = Dir.pwd
+ require tmp + '/test.rb'
+ p Coverage.result[tmp + "/test.rb"]
+ end;
+ }
+ }
+ end
end
diff --git a/thread.c b/thread.c
index 1eea4886ff..cded44b68b 100644
--- a/thread.c
+++ b/thread.c
@@ -4094,6 +4094,7 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
VALUE coverage = (VALUE)val;
VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES);
VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES);
+ VALUE methods = RARRAY_AREF(coverage, COVERAGE_INDEX_METHODS);
if (lines) {
for (i = 0; i < RARRAY_LEN(lines); i++) {
@@ -4108,6 +4109,11 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
RARRAY_ASET(counters, i, INT2FIX(0));
}
}
+ if (methods) {
+ for (i = 2; i < RARRAY_LEN(methods); i += 3) {
+ RARRAY_ASET(methods, i, INT2FIX(0));
+ }
+ }
return ST_CONTINUE;
}
@@ -5016,6 +5022,19 @@ update_coverage(VALUE data, const rb_trace_arg_t *trace_arg)
}
break;
}
+ case COVERAGE_INDEX_METHODS: {
+ VALUE methods = RARRAY_AREF(coverage, COVERAGE_INDEX_METHODS);
+ if (methods) {
+ long count;
+ long idx = arg / 16 * 3 + 2;
+ VALUE num = RARRAY_AREF(methods, idx);
+ count = FIX2LONG(num) + 1;
+ if (POSFIXABLE(count)) {
+ RARRAY_ASET(methods, idx, LONG2FIX(count));
+ }
+ }
+ break;
+ }
}
}
}
@@ -5088,7 +5107,14 @@ rb_default_coverage(int n)
RARRAY_ASET(coverage, COVERAGE_INDEX_BRANCHES, branches);
if (mode & COVERAGE_TARGET_METHODS) {
- /* not implemented yet */
+ methods = rb_ary_tmp_new(0);
+ /* internal data structures for method coverage:
+ *
+ * [symbol_of_method_name, lineno_of_method_head, counter,
+ * ...]
+ *
+ * Example: [:foobar, 1, 0, ...]
+ */
}
RARRAY_ASET(coverage, COVERAGE_INDEX_METHODS, methods);