Feature #9508 » pull-request-511.patch
| compile.c | ||
|---|---|---|
|
iseq->compile_data->last_coverable_line = (line); \
|
||
|
ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_COVERAGE)); \
|
||
|
} \
|
||
|
if ((event) == RUBY_EVENT_DEFN && iseq->method_coverage) { \
|
||
|
/*iseq->compile_data->last_coverable_line = (line); \
|
||
|
VALUE info = rb_hash_new(); \
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), INT2FIX(0));*/ \
|
||
|
rb_hash_aset(iseq->method_coverage, LONG2FIX(line), Qnil); \
|
||
|
} \
|
||
|
if ((event) == RUBY_EVENT_CALL && iseq->method_coverage && \
|
||
|
(line) != iseq->compile_data->last_coverable_line) { \
|
||
|
iseq->compile_data->last_coverable_line = (line); \
|
||
|
ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_MCOVERAGE)); \
|
||
|
} \
|
||
|
if (iseq->compile_data->option->trace_instruction) { \
|
||
|
ADD_INSN1((seq), (line), trace, INT2FIX(event)); \
|
||
|
} \
|
||
| ... | ... | |
|
debugp_param("defn/iseq", iseqval);
|
||
|
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_DEFN);
|
||
|
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||
|
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
|
||
|
ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
|
||
| ext/coverage/coverage.c | ||
|---|---|---|
|
VALUE path = (VALUE)key;
|
||
|
VALUE coverage = (VALUE)val;
|
||
|
VALUE coverages = (VALUE)h;
|
||
|
coverage = rb_ary_dup(coverage);
|
||
|
rb_ary_clear((VALUE)val);
|
||
|
VALUE line_coverage = rb_hash_lookup(coverage, ID2SYM(rb_intern("lines")));
|
||
|
line_coverage = rb_ary_dup(line_coverage);
|
||
|
coverage = rb_hash_dup(coverage);
|
||
|
rb_hash_clear((VALUE)val);
|
||
|
rb_hash_freeze(line_coverage);
|
||
|
rb_hash_aset(coverage, ID2SYM(rb_intern("lines")), line_coverage);
|
||
|
rb_ary_freeze(coverage);
|
||
|
rb_hash_aset(coverages, path, coverage);
|
||
|
return ST_CONTINUE;
|
||
| include/ruby/ruby.h | ||
|---|---|---|
|
#define RUBY_EVENT_C_CALL 0x0020
|
||
|
#define RUBY_EVENT_C_RETURN 0x0040
|
||
|
#define RUBY_EVENT_RAISE 0x0080
|
||
|
#define RUBY_EVENT_DEFN 0x0090
|
||
|
#define RUBY_EVENT_ALL 0x00ff
|
||
|
/* for TracePoint extended events */
|
||
| ... | ... | |
|
/* special events */
|
||
|
#define RUBY_EVENT_SPECIFIED_LINE 0x010000
|
||
|
#define RUBY_EVENT_COVERAGE 0x020000
|
||
|
#define RUBY_EVENT_MCOVERAGE 0x040000
|
||
|
/* internal events */
|
||
|
#define RUBY_INTERNAL_EVENT_SWITCH 0x040000
|
||
| iseq.c | ||
|---|---|---|
|
RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->klass);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->coverage);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->method_coverage);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->orig);
|
||
|
if (iseq->compile_data != 0) {
|
||
| ... | ... | |
|
iseq->compile_data->last_coverable_line = -1;
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->method_coverage, Qfalse);
|
||
|
if (!GET_THREAD()->parse_in_eval) {
|
||
|
VALUE coverages = rb_get_coverages();
|
||
|
if (RTEST(coverages)) {
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->coverage, rb_hash_lookup(coverages, path));
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->coverage,
|
||
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("lines"))));
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->method_coverage,
|
||
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("methods"))));
|
||
|
if (NIL_P(iseq->coverage)) RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
|
||
|
if (NIL_P(iseq->method_coverage)) RB_OBJ_WRITE(iseq->self, &iseq->method_coverage, Qfalse);
|
||
|
}
|
||
|
}
|
||
| parse.y | ||
|---|---|---|
|
VALUE coverages = rb_get_coverages();
|
||
|
if (RTEST(coverages) && RBASIC(coverages)->klass == 0) {
|
||
|
VALUE lines = rb_ary_new2(n);
|
||
|
VALUE rb_file_coverage = rb_hash_new();
|
||
|
VALUE methods = rb_hash_new();
|
||
|
int i;
|
||
|
RBASIC_CLEAR_CLASS(lines);
|
||
|
for (i = 0; i < n; i++) RARRAY_ASET(lines, i, Qnil);
|
||
|
RARRAY(lines)->as.heap.len = n;
|
||
|
rb_hash_aset(coverages, fname, lines);
|
||
|
rb_hash_aset(rb_file_coverage, ID2SYM(rb_intern("lines")), lines);
|
||
|
rb_hash_aset(rb_file_coverage, ID2SYM(rb_intern("methods")), methods);
|
||
|
rb_hash_aset(coverages, fname, rb_file_coverage);
|
||
|
return lines;
|
||
|
}
|
||
|
return 0;
|
||
| thread.c | ||
|---|---|---|
|
clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
|
||
|
{
|
||
|
int i;
|
||
|
VALUE lines = (VALUE)val;
|
||
|
VALUE lines = rb_hash_lookup(val, ID2SYM(rb_intern("lines")));
|
||
|
for (i = 0; i < RARRAY_LEN(lines); i++) {
|
||
|
if (RARRAY_AREF(lines, i) != Qnil) {
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
static void
|
||
|
update_method_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
||
|
{
|
||
|
VALUE method_coverage = GET_THREAD()->cfp->iseq->method_coverage;
|
||
|
if (method_coverage) {
|
||
|
long line = rb_sourceline();
|
||
|
VALUE info = rb_hash_lookup(method_coverage, LONG2FIX(line));
|
||
|
if (info == Qnil) {
|
||
|
VALUE info = rb_hash_new();
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), INT2FIX(1));
|
||
|
rb_hash_aset(method_coverage, LONG2FIX(line), info);
|
||
|
} else {
|
||
|
long count = FIX2LONG(rb_hash_lookup(info, ID2SYM(rb_intern("count")))) + 1;
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), LONG2FIX(count));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
VALUE
|
||
|
rb_get_coverages(void)
|
||
|
{
|
||
| ... | ... | |
|
{
|
||
|
GET_VM()->coverages = coverages;
|
||
|
rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);
|
||
|
rb_add_event_hook(update_method_coverage, RUBY_EVENT_MCOVERAGE, Qnil);
|
||
|
}
|
||
|
void
|
||
| vm_core.h | ||
|---|---|---|
|
VALUE *iseq_encoded; /* encoded iseq */
|
||
|
unsigned long iseq_size;
|
||
|
const VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
||
|
const VALUE coverage; /* coverage array */
|
||
|
const VALUE coverage; /* coverage array */
|
||
|
const VALUE method_coverage; /* method coverage array */
|
||
|
/* insn info, must be freed */
|
||
|
struct iseq_line_info_entry *line_info_table;
|
||
|
-
|
||
| compile.c | ||
|---|---|---|
|
iseq->compile_data->last_coverable_line = (line); \
|
||
|
ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_COVERAGE)); \
|
||
|
} \
|
||
|
if ((event) == RUBY_EVENT_DEFN && iseq->method_coverage) { \
|
||
|
/*iseq->compile_data->last_coverable_line = (line); \
|
||
|
VALUE info = rb_hash_new(); \
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), INT2FIX(0));*/ \
|
||
|
rb_hash_aset(iseq->method_coverage, LONG2FIX(line), Qnil); \
|
||
|
} \
|
||
|
if ((event) == RUBY_EVENT_CALL && iseq->method_coverage && \
|
||
|
(line) != iseq->compile_data->last_coverable_line) { \
|
||
|
iseq->compile_data->last_coverable_line = (line); \
|
||
| ... | ... | |
|
} \
|
||
|
} while (0)
|
||
|
#define ADD_COVERAGE_TRACE(seq, line, event) \
|
||
|
do { \
|
||
|
if ((event) == RUBY_EVENT_DEFN && iseq->method_coverage) { \
|
||
|
rb_hash_aset(iseq->method_coverage, LONG2FIX(line), INT2FIX(0)); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
/* add label */
|
||
|
#define ADD_LABEL(seq, label) \
|
||
|
ADD_ELEM((seq), (LINK_ELEMENT *) (label))
|
||
| ... | ... | |
|
debugp_param("defn/iseq", iseqval);
|
||
|
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_DEFN);
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node), RUBY_EVENT_DEFN);
|
||
|
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||
|
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
|
||
|
ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
|
||
| thread.c | ||
|---|---|---|
|
long line = rb_sourceline();
|
||
|
VALUE info = rb_hash_lookup(method_coverage, LONG2FIX(line));
|
||
|
if (info == Qnil) {
|
||
|
VALUE info = rb_hash_new();
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), INT2FIX(1));
|
||
|
rb_hash_aset(method_coverage, LONG2FIX(line), info);
|
||
|
} else {
|
||
|
long count = FIX2LONG(rb_hash_lookup(info, ID2SYM(rb_intern("count")))) + 1;
|
||
|
rb_hash_aset(info, ID2SYM(rb_intern("count")), LONG2FIX(count));
|
||
|
}
|
||
|
long count = FIX2LONG(info) + 1;
|
||
|
rb_hash_aset(method_coverage, LONG2FIX(line), LONG2FIX(count));
|
||
|
}
|
||
|
}
|
||
|
-
|
||
| compile.c | ||
|---|---|---|
|
if ((event) == RUBY_EVENT_DEFN && iseq->method_coverage) { \
|
||
|
rb_hash_aset(iseq->method_coverage, LONG2FIX(line), INT2FIX(0)); \
|
||
|
} \
|
||
|
if ((event) == RUBY_EVENT_BRANCH && iseq->branch_coverage) { \
|
||
|
rb_hash_aset(iseq->branch_coverage, LONG2FIX(line), INT2FIX(0)); \
|
||
|
ADD_INSN1((seq), (line), trace, INT2FIX(RUBY_EVENT_BCOVERAGE)); \
|
||
|
} \
|
||
|
} while (0)
|
||
|
/* add label */
|
||
| ... | ... | |
|
ADD_SEQ(ret, cond_seq);
|
||
|
ADD_LABEL(ret, then_label);
|
||
|
if (node->nd_body)
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node->nd_body), RUBY_EVENT_BRANCH);
|
||
|
ADD_SEQ(ret, then_seq);
|
||
|
ADD_INSNL(ret, line, jump, end_label);
|
||
|
ADD_LABEL(ret, else_label);
|
||
|
if (node->nd_else)
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node->nd_else), RUBY_EVENT_BRANCH);
|
||
|
ADD_SEQ(ret, else_seq);
|
||
|
ADD_LABEL(ret, end_label);
|
||
| include/ruby/ruby.h | ||
|---|---|---|
|
#define RUBY_EVENT_C_RETURN 0x0040
|
||
|
#define RUBY_EVENT_RAISE 0x0080
|
||
|
#define RUBY_EVENT_DEFN 0x0090
|
||
|
#define RUBY_EVENT_BRANCH 0x00a0
|
||
|
#define RUBY_EVENT_ALL 0x00ff
|
||
|
/* for TracePoint extended events */
|
||
| ... | ... | |
|
#define RUBY_EVENT_SPECIFIED_LINE 0x010000
|
||
|
#define RUBY_EVENT_COVERAGE 0x020000
|
||
|
#define RUBY_EVENT_MCOVERAGE 0x040000
|
||
|
#define RUBY_EVENT_BCOVERAGE 0x080000
|
||
|
/* internal events */
|
||
|
#define RUBY_INTERNAL_EVENT_SWITCH 0x040000
|
||
| iseq.c | ||
|---|---|---|
|
RUBY_MARK_UNLESS_NULL(iseq->klass);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->coverage);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->method_coverage);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->branch_coverage);
|
||
|
RUBY_MARK_UNLESS_NULL(iseq->orig);
|
||
|
if (iseq->compile_data != 0) {
|
||
| ... | ... | |
|
RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->method_coverage, Qfalse);
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->branch_coverage, Qfalse);
|
||
|
if (!GET_THREAD()->parse_in_eval) {
|
||
|
VALUE coverages = rb_get_coverages();
|
||
|
if (RTEST(coverages)) {
|
||
| ... | ... | |
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("lines"))));
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->method_coverage,
|
||
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("methods"))));
|
||
|
RB_OBJ_WRITE(iseq->self, &iseq->branch_coverage,
|
||
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("branches"))));
|
||
|
if (NIL_P(iseq->coverage)) RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
|
||
|
if (NIL_P(iseq->method_coverage)) RB_OBJ_WRITE(iseq->self, &iseq->method_coverage, Qfalse);
|
||
|
}
|
||
| parse.y | ||
|---|---|---|
|
VALUE lines = rb_ary_new2(n);
|
||
|
VALUE rb_file_coverage = rb_hash_new();
|
||
|
VALUE methods = rb_hash_new();
|
||
|
VALUE branches = rb_hash_new();
|
||
|
int i;
|
||
|
RBASIC_CLEAR_CLASS(lines);
|
||
|
for (i = 0; i < n; i++) RARRAY_ASET(lines, i, Qnil);
|
||
|
RARRAY(lines)->as.heap.len = n;
|
||
|
rb_hash_aset(rb_file_coverage, ID2SYM(rb_intern("lines")), lines);
|
||
|
rb_hash_aset(rb_file_coverage, ID2SYM(rb_intern("methods")), methods);
|
||
|
rb_hash_aset(rb_file_coverage, ID2SYM(rb_intern("branches")), branches);
|
||
|
rb_hash_aset(coverages, fname, rb_file_coverage);
|
||
|
return lines;
|
||
|
}
|
||
| thread.c | ||
|---|---|---|
|
}
|
||
|
static void
|
||
|
update_method_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
||
|
update_detailed_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
|
||
|
{
|
||
|
VALUE method_coverage = GET_THREAD()->cfp->iseq->method_coverage;
|
||
|
if (method_coverage) {
|
||
|
long line = rb_sourceline();
|
||
|
VALUE info = rb_hash_lookup(method_coverage, LONG2FIX(line));
|
||
|
VALUE coverage;
|
||
|
if (event == RUBY_EVENT_MCOVERAGE) {
|
||
|
coverage = GET_THREAD()->cfp->iseq->method_coverage;
|
||
|
} else if (event == RUBY_EVENT_BCOVERAGE) {
|
||
|
coverage = GET_THREAD()->cfp->iseq->branch_coverage;
|
||
|
} else {
|
||
|
rb_raise(rb_eArgError, "unknown detailed coverage event");
|
||
|
}
|
||
|
if (coverage) {
|
||
|
VALUE line = LONG2FIX(rb_sourceline());
|
||
|
VALUE count = rb_hash_lookup(coverage, line);
|
||
|
if (count == Qnil) {
|
||
|
return;
|
||
|
}
|
||
|
long count = FIX2LONG(info) + 1;
|
||
|
rb_hash_aset(method_coverage, LONG2FIX(line), LONG2FIX(count));
|
||
|
rb_hash_aset(coverage, line, LONG2FIX(FIX2LONG(count) + 1));
|
||
|
}
|
||
|
}
|
||
| ... | ... | |
|
{
|
||
|
GET_VM()->coverages = coverages;
|
||
|
rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);
|
||
|
rb_add_event_hook(update_method_coverage, RUBY_EVENT_MCOVERAGE, Qnil);
|
||
|
rb_add_event_hook(update_detailed_coverage, RUBY_EVENT_MCOVERAGE, Qnil);
|
||
|
rb_add_event_hook(update_detailed_coverage, RUBY_EVENT_BCOVERAGE, Qnil);
|
||
|
}
|
||
|
void
|
||
| vm_core.h | ||
|---|---|---|
|
const VALUE mark_ary; /* Array: includes operands which should be GC marked */
|
||
|
const VALUE coverage; /* coverage array */
|
||
|
const VALUE method_coverage; /* method coverage array */
|
||
|
const VALUE branch_coverage; /* branch coverage array */
|
||
|
/* insn info, must be freed */
|
||
|
struct iseq_line_info_entry *line_info_table;
|
||
|
-
|
||
| compile.c | ||
|---|---|---|
|
ADD_INSNL(ret, line, jump, end_label);
|
||
|
ADD_LABEL(ret, else_label);
|
||
|
if (node->nd_else)
|
||
|
/* do not trace elsif node */
|
||
|
if (node->nd_else && nd_type(node->nd_else) != NODE_IF)
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node->nd_else), RUBY_EVENT_BRANCH);
|
||
|
ADD_SEQ(ret, else_seq);
|
||
| ext/coverage/coverage.c | ||
|---|---|---|
|
VALUE path = (VALUE)key;
|
||
|
VALUE coverage = (VALUE)val;
|
||
|
VALUE coverages = (VALUE)h;
|
||
|
VALUE line_coverage = rb_hash_lookup(coverage, ID2SYM(rb_intern("lines")));
|
||
|
VALUE method_coverage = rb_hash_lookup(coverage, ID2SYM(rb_intern("methods")));
|
||
|
VALUE branch_coverage = rb_hash_lookup(coverage, ID2SYM(rb_intern("branches")));
|
||
|
line_coverage = rb_ary_dup(line_coverage);
|
||
|
method_coverage = rb_hash_dup(method_coverage);
|
||
|
branch_coverage = rb_hash_dup(branch_coverage);
|
||
|
rb_ary_clear(rb_hash_lookup(coverage, ID2SYM(rb_intern("lines"))));
|
||
|
rb_hash_clear(rb_hash_lookup(coverage, ID2SYM(rb_intern("methods"))));
|
||
|
rb_hash_clear(rb_hash_lookup(coverage, ID2SYM(rb_intern("branches"))));
|
||
|
coverage = rb_hash_dup(coverage);
|
||
|
rb_hash_clear((VALUE)val);
|
||
|
rb_hash_freeze(line_coverage);
|
||
|
rb_ary_freeze(line_coverage);
|
||
|
rb_hash_freeze(method_coverage);
|
||
|
rb_hash_freeze(branch_coverage);
|
||
|
rb_hash_aset(coverage, ID2SYM(rb_intern("lines")), line_coverage);
|
||
|
rb_hash_aset(coverage, ID2SYM(rb_intern("methods")), method_coverage);
|
||
|
rb_hash_aset(coverage, ID2SYM(rb_intern("branches")), branch_coverage);
|
||
|
rb_ary_freeze(coverage);
|
||
|
rb_hash_aset(coverages, path, coverage);
|
||
|
return ST_CONTINUE;
|
||
| iseq.c | ||
|---|---|---|
|
rb_hash_lookup(rb_hash_lookup(coverages, path), ID2SYM(rb_intern("branches"))));
|
||
|
if (NIL_P(iseq->coverage)) RB_OBJ_WRITE(iseq->self, &iseq->coverage, Qfalse);
|
||
|
if (NIL_P(iseq->method_coverage)) RB_OBJ_WRITE(iseq->self, &iseq->method_coverage, Qfalse);
|
||
|
if (NIL_P(iseq->branch_coverage)) RB_OBJ_WRITE(iseq->self, &iseq->branch_coverage, Qfalse);
|
||
|
}
|
||
|
}
|
||
| test/coverage/test_branch_coverage.rb | ||
|---|---|---|
|
require "test/unit"
|
||
|
require "coverage"
|
||
|
require "tmpdir"
|
||
|
class TestBranchCoverage < Test::Unit::TestCase
|
||
|
def test_branch_coverage
|
||
|
loaded_features = $".dup
|
||
|
Dir.mktmpdir {|tmp|
|
||
|
Dir.chdir(tmp) {
|
||
|
File.open("test.rb", "w") do |f|
|
||
|
f.puts <<-EOS
|
||
|
if 2+2 == 4
|
||
|
:ok
|
||
|
end
|
||
|
:ok unless [].size > 0
|
||
|
:bad unless [].size == 0
|
||
|
ary = [1,2,3]
|
||
|
if ary.include? 4
|
||
|
:bad
|
||
|
elsif ary.include? 5
|
||
|
:also_bad
|
||
|
else
|
||
|
:good
|
||
|
end
|
||
|
EOS
|
||
|
end
|
||
|
Coverage.start
|
||
|
require tmp + '/test.rb'
|
||
|
branch_coverage = Coverage.result[tmp + '/test.rb'][:branches]
|
||
|
assert_equal 6, branch_coverage.size
|
||
|
assert_equal 1, branch_coverage[2]
|
||
|
assert_equal 1, branch_coverage[5]
|
||
|
assert_equal 0, branch_coverage[6]
|
||
|
assert_equal 0, branch_coverage[10]
|
||
|
assert_equal 0, branch_coverage[12]
|
||
|
assert_equal 1, branch_coverage[14]
|
||
|
}
|
||
|
}
|
||
|
ensure
|
||
|
$".replace loaded_features
|
||
|
end
|
||
|
end
|
||
| test/coverage/test_coverage.rb | ||
|---|---|---|
|
def test_result_without_start
|
||
|
assert_raise(RuntimeError) {Coverage.result}
|
||
|
end
|
||
|
def test_result_with_nothing
|
||
|
Coverage.start
|
||
|
result = Coverage.result
|
||
|
assert_kind_of(Hash, result)
|
||
|
assert(! result.empty?)
|
||
|
result.each do |key, val|
|
||
|
assert_kind_of(String, key)
|
||
|
assert_kind_of(Array, val)
|
||
|
assert_kind_of(Hash, val)
|
||
|
assert_kind_of(Array, val[:lines])
|
||
|
assert_kind_of(Hash, val[:methods])
|
||
|
assert_kind_of(Hash, val[:branches])
|
||
|
end
|
||
|
end
|
||
| ... | ... | |
|
Coverage.start
|
||
|
require tmp + '/test.rb'
|
||
|
assert_equal 3, Coverage.result[tmp + '/test.rb'].size
|
||
|
assert_equal 3, Coverage.result[tmp + '/test.rb'][:lines].size
|
||
|
Coverage.start
|
||
|
coverage_test_method
|
||
|
assert_equal 0, Coverage.result[tmp + '/test.rb'].size
|
||
|
assert_equal 0, Coverage.result[tmp + '/test.rb'][:lines].size
|
||
|
}
|
||
|
}
|
||
|
ensure
|
||
| ... | ... | |
|
Coverage.start
|
||
|
require tmp + '/test.rb'
|
||
|
assert_equal 10003, Coverage.result[tmp + '/test.rb'].size
|
||
|
assert_equal 10003, Coverage.result[tmp + '/test.rb'][:lines].size
|
||
|
}
|
||
|
}
|
||
|
ensure
|
||
| test/coverage/test_method_coverage.rb | ||
|---|---|---|
|
require "test/unit"
|
||
|
require "coverage"
|
||
|
require "tmpdir"
|
||
|
class TestMethodCoverage < Test::Unit::TestCase
|
||
|
def test_method_coverage
|
||
|
loaded_features = $".dup
|
||
|
Dir.mktmpdir {|tmp|
|
||
|
Dir.chdir(tmp) {
|
||
|
File.open("test.rb", "w") do |f|
|
||
|
f.puts <<-EOS
|
||
|
def method_one
|
||
|
:one
|
||
|
end
|
||
|
def method_two
|
||
|
:two
|
||
|
end
|
||
|
method_two; method_two
|
||
|
EOS
|
||
|
end
|
||
|
Coverage.start
|
||
|
require tmp + '/test.rb'
|
||
|
method_coverage = Coverage.result[tmp + '/test.rb'][:methods]
|
||
|
assert_equal 2, method_coverage.size
|
||
|
assert_equal 0, method_coverage[1]
|
||
|
assert_equal 2, method_coverage[5]
|
||
|
}
|
||
|
}
|
||
|
ensure
|
||
|
$".replace loaded_features
|
||
|
end
|
||
|
end
|
||
| thread.c | ||
|---|---|---|
|
{
|
||
|
GET_VM()->coverages = Qfalse;
|
||
|
rb_remove_event_hook(update_coverage);
|
||
|
rb_remove_event_hook(update_detailed_coverage);
|
||
|
}
|
||
|
VALUE
|
||
|
-
|
||
| compile.c | ||
|---|---|---|
|
l1 = NEW_LABEL(line);
|
||
|
ADD_LABEL(body_seq, l1);
|
||
|
if (node->nd_body)
|
||
|
ADD_COVERAGE_TRACE(body_seq, nd_line(node->nd_body), RUBY_EVENT_BRANCH);
|
||
|
ADD_INSN(body_seq, line, pop);
|
||
|
COMPILE_(body_seq, "when body", node->nd_body, poped);
|
||
|
ADD_INSNL(body_seq, line, jump, endlabel);
|
||
| ... | ... | |
|
/* else */
|
||
|
if (node) {
|
||
|
ADD_LABEL(cond_seq, elselabel);
|
||
|
ADD_COVERAGE_TRACE(cond_seq, nd_line(node), RUBY_EVENT_BRANCH);
|
||
|
ADD_INSN(cond_seq, line, pop);
|
||
|
COMPILE_(cond_seq, "else", node, poped);
|
||
|
ADD_INSNL(cond_seq, line, jump, endlabel);
|
||
| ... | ... | |
|
while (node && nd_type(node) == NODE_WHEN) {
|
||
|
LABEL *l1 = NEW_LABEL(line = nd_line(node));
|
||
|
ADD_LABEL(body_seq, l1);
|
||
|
if (node->nd_body)
|
||
|
ADD_COVERAGE_TRACE(body_seq, nd_line(node->nd_body), RUBY_EVENT_BRANCH);
|
||
|
COMPILE_(body_seq, "when", node->nd_body, poped);
|
||
|
ADD_INSNL(body_seq, line, jump, endlabel);
|
||
| ... | ... | |
|
node = node->nd_next;
|
||
|
}
|
||
|
/* else */
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node), RUBY_EVENT_BRANCH);
|
||
|
COMPILE_(ret, "else", node, poped);
|
||
|
ADD_INSNL(ret, nd_line(orig_node), jump, endlabel);
|
||
| ... | ... | |
|
debugp_param("defs/iseq", iseqval);
|
||
|
ADD_COVERAGE_TRACE(ret, nd_line(node), RUBY_EVENT_DEFN);
|
||
|
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||
|
COMPILE(ret, "defs: recv", node->nd_recv);
|
||
|
ADD_INSN1(ret, line, putobject, ID2SYM(node->nd_mid));
|
||
| test/coverage/test_branch_coverage.rb | ||
|---|---|---|
|
require "tmpdir"
|
||
|
class TestBranchCoverage < Test::Unit::TestCase
|
||
|
def test_branch_coverage
|
||
|
def test_if_else_coverage
|
||
|
loaded_features = $".dup
|
||
|
Dir.mktmpdir {|tmp|
|
||
| ... | ... | |
|
ensure
|
||
|
$".replace loaded_features
|
||
|
end
|
||
|
def test_when_coverage
|
||
|
loaded_features = $".dup
|
||
|
Dir.mktmpdir {|tmp|
|
||
|
Dir.chdir(tmp) {
|
||
|
File.open("test.rb", "w") do |f|
|
||
|
f.puts <<-EOS
|
||
|
case
|
||
|
when 2 + 2 == 5
|
||
|
x = :bad
|
||
|
x = :math
|
||
|
when 2 + 2 == 4
|
||
|
x = :good
|
||
|
else
|
||
|
x = :also_bad
|
||
|
end
|
||
|
case [1,2,3]
|
||
|
when String
|
||
|
:string?
|
||
|
else
|
||
|
:else
|
||
|
end
|
||
|
EOS
|
||
|
end
|
||
|
Coverage.start
|
||
|
require tmp + '/test.rb'
|
||
|
branch_coverage = Coverage.result[tmp + '/test.rb'][:branches]
|
||
|
assert_equal 5, branch_coverage.size
|
||
|
assert_equal 0, branch_coverage[3]
|
||
|
assert_equal 1, branch_coverage[6]
|
||
|
assert_equal 0, branch_coverage[8]
|
||
|
assert_equal 0, branch_coverage[13]
|
||
|
assert_equal 1, branch_coverage[15]
|
||
|
}
|
||
|
}
|
||
|
ensure
|
||
|
$".replace loaded_features
|
||
|
end
|
||
|
end
|
||