ruby-changes:47770
From: mame <ko1@a...>
Date: Thu, 14 Sep 2017 14:12:41 +0900 (JST)
Subject: [ruby-changes:47770] mame:r59888 (trunk): Add method coverage
mame 2017-09-14 14:12:34 +0900 (Thu, 14 Sep 2017) New Revision: 59888 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59888 Log: Add method coverage Modified files: trunk/compile.c trunk/ext/coverage/coverage.c trunk/test/coverage/test_coverage.rb trunk/thread.c Index: ext/coverage/coverage.c =================================================================== --- ext/coverage/coverage.c (revision 59887) +++ ext/coverage/coverage.c (revision 59888) @@ -92,6 +92,22 @@ branch_coverage(VALUE branches) https://github.com/ruby/ruby/blob/trunk/ext/coverage/coverage.c#L92 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 https://github.com/ruby/ruby/blob/trunk/ext/coverage/coverage.c#L137 } 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); Index: compile.c =================================================================== --- compile.c (revision 59887) +++ compile.c (revision 59888) @@ -277,6 +277,19 @@ struct iseq_compile_data_ensure_node_sta https://github.com/ruby/ruby/blob/trunk/compile.c#L277 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, NO https://github.com/ruby/ruby/blob/trunk/compile.c#L650 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; Index: test/coverage/test_coverage.rb =================================================================== --- test/coverage/test_coverage.rb (revision 59887) +++ test/coverage/test_coverage.rb (revision 59888) @@ -280,4 +280,29 @@ class TestCoverage < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/test/coverage/test_coverage.rb#L280 } } 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 Index: thread.c =================================================================== --- thread.c (revision 59887) +++ thread.c (revision 59888) @@ -4094,6 +4094,7 @@ clear_coverage_i(st_data_t key, st_data_ https://github.com/ruby/ruby/blob/trunk/thread.c#L4094 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_ https://github.com/ruby/ruby/blob/trunk/thread.c#L4109 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_tra https://github.com/ruby/ruby/blob/trunk/thread.c#L5022 } 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) https://github.com/ruby/ruby/blob/trunk/thread.c#L5107 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); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/