summaryrefslogtreecommitdiff
path: root/tool/test-coverage.rb
blob: 0719e5e7032016355bc980d4aec4f65932cd528e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
require "coverage"

ENV["COVERAGE_EXPERIMENTAL_MODE"] = "true"
Coverage.start(lines: true, branches: true, methods: true)

TEST_COVERAGE_DATA_FILE = "test-coverage.dat"

def merge_coverage_data(res1, res2)
  res1.each do |path, cov1|
    cov2 = res2[path]
    if cov2
      cov1[:lines].each_with_index do |count1, i|
        next unless count1
        add_count(cov2[:lines], i, count1)
      end
      cov1[:branches].each do |base_key, targets1|
        if cov2[:branches][base_key]
          targets1.each do |target_key, count1|
            add_count(cov2[:branches][base_key], target_key, count1)
          end
        else
          cov2[:branches][base_key] = targets1
        end
      end
      cov1[:methods].each do |key, count1|
        add_count(cov2[:methods], key, count1)
      end
    else
      res2[path] = cov1
    end
  end
  res2
end

def add_count(h, key, count)
  if h[key]
    h[key] += count
  else
    h[key] = count
  end
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[:lines]
  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