[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / tool / run-lcov.rb
blobf27578200a482879229884afad290ea59b0fbbb3
1 #!ruby
2 require "pathname"
3 require "open3"
4 require "tmpdir"
6 def backup_gcda_files(gcda_files)
7   gcda_files = gcda_files.map do |gcda|
8     [gcda, gcda.sub_ext(".bak")]
9   end
10   begin
11     gcda_files.each do |before, after|
12       before.rename(after)
13     end
14     yield
15   ensure
16     gcda_files.each do |before, after|
17       after.rename(before)
18     end
19   end
20 end
22 def run_lcov(*args)
23   system("lcov", "--rc", "lcov_branch_coverage=1", *args)
24 end
26 $info_files = []
27 def run_lcov_capture(dir, info)
28   $info_files << info
29   run_lcov("--capture", "-d", dir, "-o", info)
30 end
32 def run_lcov_merge(files, info)
33   run_lcov(*files.flat_map {|f| ["--add-tracefile", f] }, "-o", info)
34 end
36 def run_lcov_remove(info_src, info_out)
37   dirs = %w(/usr/*)
38   dirs << File.join(Dir.tmpdir, "*")
39   %w(
40     test/*
41     ext/-test-/*
42     ext/nkf/nkf-utf8/nkf.c
43   ).each {|f| dirs << File.join(File.dirname(__dir__), f) }
44   run_lcov("--remove", info_src, *dirs, "-o", info_out)
45 end
47 def run_genhtml(info, out)
48   system("genhtml", "--branch-coverage", "--ignore-errors", "source", info, "-o", out)
49 end
51 def gen_rb_lcov(file)
52   res = Marshal.load(File.binread(file))
54   open("lcov-rb-all.info", "w") do |f|
55     f.puts "TN:" # no test name
56     base_dir = File.dirname(__dir__)
57     res.each do |path, cov|
58       next unless path.start_with?(base_dir)
59       next if path.start_with?(File.join(base_dir, "test"))
60       f.puts "SF:#{ path }"
62       total = covered = 0
63       cov.each_with_index do |count, lineno|
64         next unless count
65         f.puts "DA:#{ lineno + 1 },#{ count }"
66         total += 1
67         covered += 1 if count > 0
68       end
69       f.puts "LF:#{ total }"
70       f.puts "LH:#{ covered }"
72       f.puts "end_of_record"
73     end
74   end
75 end
77 def gen_rb_lcov(file)
78   res = Marshal.load(File.binread(file))
80   open("lcov-rb-all.info", "w") do |f|
81     f.puts "TN:" # no test name
82     base_dir = File.dirname(File.dirname(__dir__))
83     res.each do |path, cov|
84       next unless path.start_with?(base_dir)
85       next if path.start_with?(File.join(base_dir, "test"))
86       f.puts "SF:#{ path }"
88       # function coverage
89       total = covered = 0
90       cov[:methods].each do |(klass, name, lineno), count|
91         f.puts "FN:#{ lineno },#{ klass }##{ name }"
92         total += 1
93         covered += 1 if count > 0
94       end
95       f.puts "FNF:#{ total }"
96       f.puts "FNF:#{ covered }"
97       cov[:methods].each do |(klass, name, _), count|
98         f.puts "FNDA:#{ count },#{ klass }##{ name }"
99       end
101       # line coverage
102       total = covered = 0
103       cov[:lines].each_with_index do |count, lineno|
104         next unless count
105         f.puts "DA:#{ lineno + 1 },#{ count }"
106         total += 1
107         covered += 1 if count > 0
108       end
109       f.puts "LF:#{ total }"
110       f.puts "LH:#{ covered }"
112       # branch coverage
113       total = covered = 0
114       id = 0
115       cov[:branches].each do |(_base_type, _, base_lineno), targets|
116         i = 0
117         targets.each do |(_target_type, _target_lineno), count|
118           f.puts "BRDA:#{ base_lineno },#{ id },#{ i },#{ count }"
119           total += 1
120           covered += 1 if count > 0
121           i += 1
122         end
123         id += 1
124       end
125       f.puts "BRF:#{ total }"
126       f.puts "BRH:#{ covered }"
127       f.puts "end_of_record"
128     end
129   end
132 gcda_files = Pathname.glob("**/*.gcda")
133 ext_gcda_files = gcda_files.select {|f| f.fnmatch("ext/*") }
134 rubyspec_temp_gcda_files = gcda_files.select {|f| f.fnmatch("rubyspec_temp/*") }
136 backup_gcda_files(rubyspec_temp_gcda_files) do
137   if ext_gcda_files != []
138     backup_gcda_files(ext_gcda_files) do
139       info = "lcov-root.info"
140       run_lcov_capture(".", info)
141     end
142   end
143   ext_gcda_files.group_by {|f| f.descend.to_a[1] }.each do |key, files|
144     info = "lcov-#{ key.to_s.gsub(File::Separator, "-") }.info"
145     run_lcov_capture(key.to_s, info)
146   end
148 if $info_files != []
149   run_lcov_merge($info_files, "lcov-c-all.info")
150   run_lcov_remove("lcov-c-all.info", "lcov-c-all-filtered.info")
151   run_genhtml("lcov-c-all-filtered.info", "lcov-c-out")
154 if File.readable?("test-coverage.dat")
155   gen_rb_lcov("test-coverage.dat")
156   run_lcov_remove("lcov-rb-all.info", "lcov-rb-all-filtered.info")
157   run_genhtml("lcov-rb-all-filtered.info", "lcov-rb-out")
160 if File.readable?("lcov-c-all.info") && File.readable?("lcov-rb-all.info")
161   run_lcov_merge(%w(lcov-c-all.info lcov-rb-all.info), "lcov-all.info")
162   run_lcov_remove("lcov-all.info", "lcov-all-filtered.info")
163   run_genhtml("lcov-all-filtered.info", "lcov-out")