Measure the test coverage without SimpleCov

Now `make test-all COVERAGE=true` measures the test coverage by using
`coverage.so` directly, and visualize the result by simplecov-html.

There has been some problems in coverage measurement with SimpleCov.
(They are not SimpleCov's fault, though.)

(1) It is difficult to extract the measured data as a machine-readable
format, such as Marshal.  I want to visualize the coverage data with
other coverage tools, such as LCOV and Cobertura.
(I know we can use SimpleCov's formatter mechanism, but I don't want
to depend upon SimpleCov so much.)

(2) SimpleCov seems to miss some coverage data.  For example,
`lib/cgi.rb` and `lib/ostruct.rb` are dropped.  I don't know why.

(3) I have a plan to enhance `coverage.so` with branch coverage.
It would be difficult to continue to only use SimpleCov as is.
This is the most important reason.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@59770 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
mame 2017-09-07 15:40:29 +00:00
parent 1a643bac88
commit ccaf52e244
3 changed files with 80 additions and 8 deletions

1
.gitignore vendored
View File

@ -116,6 +116,7 @@ lcov*.info
/run.gdb
/sizes.c
/test.rb
/test-coverage.dat
/tmp
/transdb.h
/uncommon.mk

View File

@ -26,14 +26,7 @@ require_relative 'lib/zombie_hunter'
require_relative 'lib/iseq_loader_checker'
if ENV['COVERAGE']
%w[doclie simplecov-html simplecov].each do |f|
$LOAD_PATH.unshift "#{src_testdir}/../coverage/#{f}/lib"
end
require 'simplecov'
SimpleCov.start do
add_filter "/test/"
end
require "tool/test-coverage.rb"
end
begin

78
tool/test-coverage.rb Normal file
View File

@ -0,0 +1,78 @@
require "coverage"
Coverage.start
TEST_COVERAGE_DATA_FILE = "test-coverage.dat"
def merge_coverage_data(res1, res2)
res1.each do |path, cov1|
cov2 = res2[path]
if cov2
cov1.each_with_index do |count1, i|
next unless count1
if cov2[i]
cov2[i] += count1
else
cov2[i] = count1
end
end
else
res2[path] = cov1
end
end
res2
end
def save_coverage_data(res1)
File.open(TEST_COVERAGE_DATA_FILE, File::RDWR | File::CREAT | File::BINARY) do |f|
f.flock(File::LOCK_EX)
s = f.read
res2 = s.size > 0 ? Marshal.load(s) : {}
res1 = merge_coverage_data(res1, res2)
f.rewind
f << Marshal.dump(res2)
f.flush
f.truncate(f.pos)
end
end
def invoke_simplecov_formatter
%w[doclie simplecov-html simplecov].each do |f|
$LOAD_PATH.unshift "#{__dir__}/../coverage/#{f}/lib"
end
require "simplecov"
res = Marshal.load(File.binread(TEST_COVERAGE_DATA_FILE))
simplecov_result = {}
base_dir = File.dirname(__dir__)
res.each do |path, cov|
next unless path.start_with?(base_dir)
next if path.start_with?(File.join(base_dir, "test"))
simplecov_result[path] = cov
end
res = SimpleCov::Result.new(simplecov_result)
res.command_name = "Ruby's `make test-all`"
SimpleCov::Formatter::HTMLFormatter.new.format(res)
end
pid = $$
pwd = Dir.pwd
at_exit do
exit_exc = $!
Dir.chdir(pwd) do
save_coverage_data(Coverage.result)
if pid == $$
begin
nil while Process.waitpid(-1)
rescue Errno::ECHILD
invoke_simplecov_formatter
end
end
end
raise exit_exc if exit_exc
end