Module: Polyrun::Coverage::TrackFiles

Defined in:
lib/polyrun/coverage/track_files.rb

Overview

SimpleCov-compatible track_files (globs from project root) and add_group statistics for the JSON payload (groups with lines.covered_percent per group).

Class Method Summary collapse

Class Method Details

.add_counts!(acc, delta) ⇒ Object



118
119
120
121
# File 'lib/polyrun/coverage/track_files.rb', line 118

def add_counts!(acc, delta)
  acc[:relevant] += delta[:relevant]
  acc[:covered] += delta[:covered]
end

.blank_or_comment?(line) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
# File 'lib/polyrun/coverage/track_files.rb', line 53

def blank_or_comment?(line)
  s = line.strip
  s.empty? || s.start_with?("#")
end

.expand_globs(root, track_files) ⇒ Object

Expands one or more glob patterns relative to root (supports {a,b}/*/.rb with File::FNM_EXTGLOB).



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/polyrun/coverage/track_files.rb', line 13

def expand_globs(root, track_files)
  root = File.expand_path(root)
  patterns = Array(track_files).map(&:to_s).reject(&:empty?)
  return [] if patterns.empty?

  patterns.flat_map do |pattern|
    Dir.chdir(root) do
      Dir.glob(pattern, File::FNM_EXTGLOB)
    end
  end.map { |rel| File.expand_path(rel, root) }.uniq
end

.file_matches_glob?(absolute_path, pattern, root) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
132
133
134
# File 'lib/polyrun/coverage/track_files.rb', line 129

def file_matches_glob?(absolute_path, pattern, root)
  rel = Pathname.new(absolute_path).relative_path_from(Pathname.new(root)).to_s
  File.fnmatch?(pattern, rel, File::FNM_PATHNAME | File::FNM_EXTGLOB)
rescue ArgumentError
  File.fnmatch?(pattern, absolute_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
end

.group_summaries(blob, root, groups) ⇒ Object

groups is a Hash of group_name => glob pattern (relative to root), SimpleCov add_group style. Produces the groups section of SimpleCov JSON: each group has lines.covered_percent. Assignment uses paths present in blob matching each glob (File.fnmatch?), not a fresh Dir.glob, so in-memory coverage lines up with reported files. Files matching no group get “Ungrouped”.



62
63
64
65
66
67
68
69
70
71
# File 'lib/polyrun/coverage/track_files.rb', line 62

def group_summaries(blob, root, groups)
  return {} if groups.nil? || groups.empty?

  root = File.expand_path(root)
  normalized = {}
  blob.each { |k, v| normalized[File.expand_path(k.to_s)] = v }

  accum, ungrouped, any_ungrouped = group_summaries_accumulate(normalized, root, groups)
  group_summaries_build_payload(groups, accum, ungrouped, any_ungrouped)
end

.group_summaries_accumulate(normalized, root, groups) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/polyrun/coverage/track_files.rb', line 73

def group_summaries_accumulate(normalized, root, groups)
  accum = Hash.new { |h, k| h[k] = {relevant: 0, covered: 0} }
  ungrouped = {relevant: 0, covered: 0}
  any_ungrouped_file = false

  normalized.each do |abs, entry|
    counts = Merge.line_counts(entry)
    matched = []
    groups.each do |name, glob_pattern|
      matched << name.to_s if file_matches_glob?(abs, glob_pattern, root)
    end
    if matched.empty?
      any_ungrouped_file = true
      ungrouped[:relevant] += counts[:relevant]
      ungrouped[:covered] += counts[:covered]
    else
      matched.each { |n| add_counts!(accum[n], counts) }
    end
  end
  [accum, ungrouped, any_ungrouped_file]
end

.group_summaries_build_payload(groups, accum, ungrouped, any_ungrouped_file) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/polyrun/coverage/track_files.rb', line 95

def group_summaries_build_payload(groups, accum, ungrouped, any_ungrouped_file)
  out = {}
  groups.each_key do |name|
    n = name.to_s
    a = accum[n]
    out[n] = {
      "lines" => {
        "covered_percent" => percent_from_counts(a[:relevant], a[:covered])
      }
    }
  end

  if any_ungrouped_file
    out["Ungrouped"] = {
      "lines" => {
        "covered_percent" => percent_from_counts(ungrouped[:relevant], ungrouped[:covered])
      }
    }
  end

  out
end

.merge_untracked_into_blob(blob, root, track_files) ⇒ Object

Adds tracked files that were never required, with simulated line arrays (blank/comment => nil, else 0). Matches SimpleCov add_not_loaded_files behavior for coverage completeness.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/polyrun/coverage/track_files.rb', line 27

def merge_untracked_into_blob(blob, root, track_files)
  root = File.expand_path(root)
  out = {}
  blob.each do |k, v|
    out[File.expand_path(k.to_s)] = v
  end

  expand_globs(root, track_files).each do |abs|
    next if out.key?(abs)
    next unless File.file?(abs)

    out[abs] = {"lines" => simulated_lines_for_unloaded(abs)}
  end
  out
end

.percent_from_counts(relevant, covered) ⇒ Object



123
124
125
126
127
# File 'lib/polyrun/coverage/track_files.rb', line 123

def percent_from_counts(relevant, covered)
  return round_percent(0.0) if relevant <= 0

  round_percent(100.0 * covered / relevant)
end

.round_percent(x) ⇒ Object



136
137
138
# File 'lib/polyrun/coverage/track_files.rb', line 136

def round_percent(x)
  x.to_f.round(2)
end

.simulated_lines_for_unloaded(path) ⇒ Object



43
44
45
46
47
48
49
50
51
# File 'lib/polyrun/coverage/track_files.rb', line 43

def simulated_lines_for_unloaded(path)
  lines = []
  File.foreach(path) do |line|
    lines << (blank_or_comment?(line) ? nil : 0)
  end
  lines
rescue Errno::ENOENT, Errno::EACCES
  []
end