From bb03c9b515e4823bef3ad781c79de06d456c39f2 Mon Sep 17 00:00:00 2001 From: mame Date: Thu, 7 Sep 2017 15:40:29 +0000 Subject: 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 --- tool/test-coverage.rb | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tool/test-coverage.rb (limited to 'tool') diff --git a/tool/test-coverage.rb b/tool/test-coverage.rb new file mode 100644 index 0000000000..0c002f4d1a --- /dev/null +++ b/tool/test-coverage.rb @@ -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 -- cgit v1.2.3