From: Yusuke Endoh Date: 2011-05-29T13:51:04+09:00 Subject: [ruby-core:36541] [Ruby 1.9 - Feature #4796][Assigned] Coverage should be restartable Issue #4796 has been updated by Yusuke Endoh. Category set to lib Status changed from Open to Assigned Assignee set to Yusuke Endoh Target version set to 1.9.3 Hello. As a maintainer of ext/coverage, I like to approve this feature unless there is objection. But I'd like to confirm some points. 2011/5/29 Xavier Shay : > The problem is that `Coverage.start` doesn't track any files loaded before it is called. This is probably desired behaviour so that stdlib files are not tracked, but it limits the usefulness of Coverage. First of all, it is difficult to track files loaded before `start' is first called. This is because the VM compiler inserts instructions to measure coverage after `start' is first called. Since the mechanism have considerable overhead, it cannot be enabled by default. You are talking about second (or later) calls to Coverage.start, right? > Specifically, I am trying to collate coverage reports from workers in multiple processes. I cannot understand why the feature is needed for this use case. Could you elaborate this? > Also I want to associate coverages with specific tests (this test executed this code, etc...). This is very difficult without being able to restart. I can understand this. Here is a patch. diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c index 29ac709..3a26aaa 100644 --- a/ext/coverage/coverage.c +++ b/ext/coverage/coverage.c @@ -11,6 +11,8 @@ #include "ruby.h" #include "vm_core.h" +static VALUE rb_coverages = Qundef; + /* * call-seq: * Coverage.start => nil @@ -21,19 +23,25 @@ static VALUE rb_coverage_start(VALUE klass) { if (!RTEST(rb_get_coverages())) { - VALUE coverages = rb_hash_new(); - RBASIC(coverages)->klass = 0; - rb_set_coverages(coverages); + if (rb_coverages == Qundef) { + rb_coverages = rb_hash_new(); + RBASIC(rb_coverages)->klass = 0; + } + rb_set_coverages(rb_coverages); } return Qnil; } static int -coverage_result_i(st_data_t key, st_data_t val, st_data_t dummy) +coverage_result_i(st_data_t key, st_data_t val, st_data_t h) { + VALUE path = (VALUE)key; VALUE coverage = (VALUE)val; - RBASIC(coverage)->klass = rb_cArray; + VALUE coverages = (VALUE)h; + coverage = rb_ary_dup(coverage); + rb_ary_clear((VALUE)val); rb_ary_freeze(coverage); + rb_hash_aset(coverages, path, coverage); return ST_CONTINUE; } @@ -48,14 +56,14 @@ static VALUE rb_coverage_result(VALUE klass) { VALUE coverages = rb_get_coverages(); + VALUE ncoverages = rb_hash_new(); if (!RTEST(coverages)) { rb_raise(rb_eRuntimeError, "coverage measurement is not enabled"); } - RBASIC(coverages)->klass = rb_cHash; - st_foreach(RHASH_TBL(coverages), coverage_result_i, 0); - rb_hash_freeze(coverages); + st_foreach(RHASH_TBL(coverages), coverage_result_i, ncoverages); + rb_hash_freeze(ncoverages); rb_reset_coverages(); - return coverages; + return ncoverages; } /* Coverage provides coverage measurement feature for Ruby. -- Yusuke Endoh ---------------------------------------- Feature #4796: Coverage should be restartable http://redmine.ruby-lang.org/issues/4796 Author: Xavier Shay Status: Assigned Priority: Normal Assignee: Yusuke Endoh Category: lib Target version: 1.9.3 I would like a way to be able to make the following test past: require "test/unit" require "coverage" require 'tmpdir' class TestCoverage < Test::Unit::TestCase def test_restarting_coverage Dir.mktmpdir {|tmp| Dir.chdir(tmp) { File.open("test.rb", "w") do |f| f.puts <<-EOS def coverage_test_method puts :ok end EOS end Coverage.start require tmp + '/test.rb' Coverage.result Coverage.start coverage_test_method assert_equal 1, Coverage.result.size } } end end The problem is that `Coverage.start` doesn't track any files loaded before it is called. This is probably desired behaviour so that stdlib files are not tracked, but it limits the usefulness of Coverage. Specifically, I am trying to collate coverage reports from workers in multiple processes. Also I want to associate coverages with specific tests (this test executed this code, etc...). This is very difficult without being able to restart. What would be involved in doing this? If you point me in the right direction I can perhaps have a go. -- http://redmine.ruby-lang.org