зеркало из https://github.com/github/ruby.git
Add branch coverage for if statement
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59876 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
c171ca1efd
Коммит
ce570370f0
37
compile.c
37
compile.c
|
@ -251,6 +251,32 @@ struct iseq_compile_data_ensure_node_stack {
|
|||
ADD_INSN2((seq), (line), trace2, INT2FIX(RUBY_EVENT_COVERAGE), INT2FIX(COVERAGE_INDEX_LINES)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DECL_BRANCH_BASE(branches, line, type) \
|
||||
do { \
|
||||
if (ISEQ_COVERAGE(iseq) && \
|
||||
ISEQ_BRANCH_COVERAGE(iseq) && \
|
||||
(line) > 0) { \
|
||||
VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0); \
|
||||
branches = rb_ary_tmp_new(0); \
|
||||
rb_ary_push(structure, branches); \
|
||||
rb_ary_push(branches, ID2SYM(rb_intern(type))); \
|
||||
rb_ary_push(branches, INT2FIX(line)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define ADD_TRACE_BRANCH_COVERAGE(seq, line, type, branches) \
|
||||
do { \
|
||||
if (ISEQ_COVERAGE(iseq) && \
|
||||
ISEQ_BRANCH_COVERAGE(iseq) && \
|
||||
(line) > 0) { \
|
||||
VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1); \
|
||||
long counter_idx = RARRAY_LEN(counters); \
|
||||
rb_ary_push(counters, INT2FIX(0)); \
|
||||
rb_ary_push(branches, ID2SYM(rb_intern(type))); \
|
||||
rb_ary_push(branches, INT2FIX(line)); \
|
||||
rb_ary_push(branches, INT2FIX(counter_idx)); \
|
||||
ADD_INSN2((seq), (line), trace2, INT2FIX(RUBY_EVENT_COVERAGE), INT2FIX(counter_idx * 16 + COVERAGE_INDEX_BRANCHES)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ADD_TRACE(seq, line, event) \
|
||||
do { \
|
||||
|
@ -4145,6 +4171,7 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped)
|
|||
DECL_ANCHOR(then_seq);
|
||||
DECL_ANCHOR(else_seq);
|
||||
LABEL *then_label, *else_label, *end_label;
|
||||
VALUE branches;
|
||||
|
||||
INIT_ANCHOR(cond_seq);
|
||||
INIT_ANCHOR(then_seq);
|
||||
|
@ -4160,8 +4187,15 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped)
|
|||
|
||||
ADD_SEQ(ret, cond_seq);
|
||||
|
||||
if (then_label->refcnt && else_label->refcnt) {
|
||||
DECL_BRANCH_BASE(branches, line, "if");
|
||||
}
|
||||
|
||||
if (then_label->refcnt) {
|
||||
ADD_LABEL(ret, then_label);
|
||||
if (else_label->refcnt) {
|
||||
ADD_TRACE_BRANCH_COVERAGE(ret, node->nd_body ? nd_line(node->nd_body) : line, "then", branches);
|
||||
}
|
||||
ADD_SEQ(ret, then_seq);
|
||||
end_label = NEW_LABEL(line);
|
||||
ADD_INSNL(ret, line, jump, end_label);
|
||||
|
@ -4169,6 +4203,9 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, NODE *node, int popped)
|
|||
|
||||
if (else_label->refcnt) {
|
||||
ADD_LABEL(ret, else_label);
|
||||
if (then_label->refcnt) {
|
||||
ADD_TRACE_BRANCH_COVERAGE(ret, node->nd_else ? nd_line(node->nd_else) : line, "else", branches);
|
||||
}
|
||||
ADD_SEQ(ret, else_seq);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,31 @@ rb_coverage_start(int argc, VALUE *argv, VALUE klass)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
branch_coverage(VALUE branches)
|
||||
{
|
||||
VALUE ret = rb_hash_new();
|
||||
VALUE structure = rb_ary_dup(RARRAY_AREF(branches, 0));
|
||||
VALUE counters = rb_ary_dup(RARRAY_AREF(branches, 1));
|
||||
int i, j, id = 0;
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(structure); i++) {
|
||||
VALUE branches = RARRAY_AREF(structure, i);
|
||||
VALUE base_type = RARRAY_AREF(branches, 0);
|
||||
VALUE base_lineno = RARRAY_AREF(branches, 1);
|
||||
VALUE children = rb_hash_new();
|
||||
rb_hash_aset(ret, rb_ary_new_from_args(3, base_type, INT2FIX(id++), base_lineno), children);
|
||||
for (j = 2; j < RARRAY_LEN(branches); j += 3) {
|
||||
VALUE target_label = RARRAY_AREF(branches, j);
|
||||
VALUE target_lineno = RARRAY_AREF(branches, j + 1);
|
||||
int idx = FIX2INT(RARRAY_AREF(branches, j + 2));
|
||||
rb_hash_aset(children, rb_ary_new_from_args(3, target_label, INT2FIX(id++), target_lineno), RARRAY_AREF(counters, idx));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
|
||||
{
|
||||
|
@ -92,7 +117,7 @@ coverage_peek_result_i(st_data_t key, st_data_t val, st_data_t h)
|
|||
}
|
||||
|
||||
if (branches) {
|
||||
rb_hash_aset(h, ID2SYM(rb_intern("branches")), branches);
|
||||
+ rb_hash_aset(h, ID2SYM(rb_intern("branches")), branch_coverage(branches));
|
||||
}
|
||||
|
||||
if (methods) {
|
||||
|
|
|
@ -175,4 +175,31 @@ class TestCoverage < Test::Unit::TestCase
|
|||
end
|
||||
end;
|
||||
end
|
||||
|
||||
def test_branch_coverage_for_if_statement
|
||||
Dir.mktmpdir {|tmp|
|
||||
Dir.chdir(tmp) {
|
||||
File.open("test.rb", "w") do |f|
|
||||
f.puts 'def foo(x)'
|
||||
f.puts ' if x == 0'
|
||||
f.puts ' 0'
|
||||
f.puts ' else'
|
||||
f.puts ' 1'
|
||||
f.puts ' end'
|
||||
f.puts 'end'
|
||||
f.puts 'foo(0)'
|
||||
f.puts 'foo(0)'
|
||||
f.puts 'foo(1)'
|
||||
end
|
||||
|
||||
assert_in_out_err(%w[-W0 -rcoverage], <<-"end;", ["{:branches=>{[:if, 0, 2]=>{[:then, 1, 3]=>2, [:else, 2, 5]=>1}}}"], [])
|
||||
ENV["COVERAGE_EXPERIMENTAL_MODE"] = "true"
|
||||
Coverage.start(branches: true)
|
||||
tmp = Dir.pwd
|
||||
require tmp + '/test.rb'
|
||||
p Coverage.result[tmp + "/test.rb"]
|
||||
end;
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
45
thread.c
45
thread.c
|
@ -4093,6 +4093,7 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
|
|||
int i;
|
||||
VALUE coverage = (VALUE)val;
|
||||
VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES);
|
||||
VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES);
|
||||
|
||||
if (lines) {
|
||||
for (i = 0; i < RARRAY_LEN(lines); i++) {
|
||||
|
@ -4101,6 +4102,12 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (branches) {
|
||||
VALUE counters = RARRAY_AREF(branches, 1);
|
||||
for (i = 0; i < RARRAY_LEN(counters); i++) {
|
||||
RARRAY_ASET(counters, i, INT2FIX(0));
|
||||
}
|
||||
}
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
@ -4975,7 +4982,8 @@ update_coverage(VALUE data, const rb_trace_arg_t *trace_arg)
|
|||
{
|
||||
VALUE coverage = rb_iseq_coverage(GET_THREAD()->ec.cfp->iseq);
|
||||
if (RB_TYPE_P(coverage, T_ARRAY) && !RBASIC_CLASS(coverage)) {
|
||||
switch (FIX2INT(trace_arg->data)) {
|
||||
long arg = FIX2INT(trace_arg->data);
|
||||
switch (arg % 16) {
|
||||
case COVERAGE_INDEX_LINES: {
|
||||
VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES);
|
||||
if (lines) {
|
||||
|
@ -4994,6 +5002,20 @@ update_coverage(VALUE data, const rb_trace_arg_t *trace_arg)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case COVERAGE_INDEX_BRANCHES: {
|
||||
VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES);
|
||||
if (branches) {
|
||||
long count;
|
||||
long idx = arg / 16;
|
||||
VALUE counters = RARRAY_AREF(branches, 1);
|
||||
VALUE num = RARRAY_AREF(counters, idx);
|
||||
count = FIX2LONG(num) + 1;
|
||||
if (POSFIXABLE(count)) {
|
||||
RARRAY_ASET(counters, idx, LONG2FIX(count));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5018,7 +5040,9 @@ reset_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);
|
||||
rb_ary_clear(lines);
|
||||
VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES);
|
||||
if (lines) rb_ary_clear(lines);
|
||||
if (branches) rb_ary_clear(branches);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -5044,7 +5068,22 @@ rb_default_coverage(int n)
|
|||
RARRAY_ASET(coverage, COVERAGE_INDEX_LINES, lines);
|
||||
|
||||
if (mode & COVERAGE_TARGET_BRANCHES) {
|
||||
/* not implemented yet */
|
||||
branches = rb_ary_tmp_new_fill(2);
|
||||
/* internal data structures for branch coverage:
|
||||
*
|
||||
* [[base_type, base_lineno,
|
||||
* target_type_1, target_lineno_1, target_counter_index_1,
|
||||
* target_type_2, target_lineno_2, target_counter_index_2, ...],
|
||||
* ...]
|
||||
*
|
||||
* Example: [[:case, 1,
|
||||
* :when, 2, 0,
|
||||
* :when, 3, 1, ...],
|
||||
* ...]
|
||||
*/
|
||||
RARRAY_ASET(branches, 0, rb_ary_tmp_new(0));
|
||||
/* branch execution counters */
|
||||
RARRAY_ASET(branches, 1, rb_ary_tmp_new(0));
|
||||
}
|
||||
RARRAY_ASET(coverage, COVERAGE_INDEX_BRANCHES, branches);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче