[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / tool / test-coverage.rb
blob055577feea6c886dfc8e1fab6d32de8c95715105
1 require "coverage"
3 Coverage.start(lines: true, branches: true, methods: true)
5 TEST_COVERAGE_DATA_FILE = "test-coverage.dat"
7 FILTER_PATHS = %w[
8   lib/bundler/vendor
9   lib/rubygems/resolver/molinillo
10   lib/rubygems/tsort
11   lib/rubygems/optparse
12   tool
13   test
14   spec
17 def merge_coverage_data(res1, res2)
18   res1.each do |path, cov1|
19     cov2 = res2[path]
20     if cov2
21       cov1[:lines].each_with_index do |count1, i|
22         next unless count1
23         add_count(cov2[:lines], i, count1)
24       end
25       cov1[:branches].each do |base_key, targets1|
26         if cov2[:branches][base_key]
27           targets1.each do |target_key, count1|
28             add_count(cov2[:branches][base_key], target_key, count1)
29           end
30         else
31           cov2[:branches][base_key] = targets1
32         end
33       end
34       cov1[:methods].each do |key, count1|
35         add_count(cov2[:methods], key, count1)
36       end
37     else
38       res2[path] = cov1
39     end
40   end
41   res2
42 end
44 def add_count(h, key, count)
45   if h[key]
46     h[key] += count
47   else
48     h[key] = count
49   end
50 end
52 def save_coverage_data(res1)
53   res1.each do |_path, cov|
54     if cov[:methods]
55       h = {}
56       cov[:methods].each do |(klass, *key), count|
57         h[[klass.name, *key]] = count
58       end
59       cov[:methods].replace h
60     end
61   end
62   File.open(TEST_COVERAGE_DATA_FILE, File::RDWR | File::CREAT | File::BINARY) do |f|
63     f.flock(File::LOCK_EX)
64     s = f.read
65     res2 = s.size > 0 ? Marshal.load(s) : {}
66     res1 = merge_coverage_data(res1, res2)
67     f.rewind
68     f << Marshal.dump(res2)
69     f.flush
70     f.truncate(f.pos)
71   end
72 end
74 def invoke_simplecov_formatter
75   # XXX docile-x.y.z and simplecov-x.y.z, simplecov-html-x.y.z, simplecov_json_formatter-x.y.z
76   %w[simplecov simplecov-html simplecov_json_formatter docile].each do |f|
77     Dir.glob("#{__dir__}/../.bundle/gems/#{f}-*/lib").each do |d|
78       $LOAD_PATH.unshift d
79     end
80   end
82   require "simplecov"
83   res = Marshal.load(File.binread(TEST_COVERAGE_DATA_FILE))
84   simplecov_result = {}
85   base_dir = File.dirname(__dir__)
86   cur_dir = Dir.pwd
88   res.each do |path, cov|
89     next unless path.start_with?(base_dir) || path.start_with?(cur_dir)
90     next if FILTER_PATHS.any? {|dir| path.start_with?(File.join(base_dir, dir))}
91     simplecov_result[path] = cov
92   end
94   a, b = base_dir, cur_dir
95   until a == b
96     if a.size > b.size
97       a = File.dirname(a)
98     else
99       b = File.dirname(b)
100     end
101   end
102   root_dir = a
104   SimpleCov.configure do
105     root(root_dir)
106     coverage_dir(File.join(cur_dir, "coverage"))
107   end
108   res = SimpleCov::Result.new(simplecov_result)
109   res.command_name = "Ruby's `make test-all`"
110   SimpleCov::Formatter::HTMLFormatter.new.format(res)
113 pid = $$
114 pwd = Dir.pwd
116 at_exit do
117   exit_exc = $!
119   Dir.chdir(pwd) do
120     save_coverage_data(Coverage.result)
121     if pid == $$
122       begin
123         nil while Process.waitpid(-1)
124       rescue Errno::ECHILD
125         invoke_simplecov_formatter
126       end
127     end
128   end
130   raise exit_exc if exit_exc