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



127
128
129
130
# File 'lib/polyrun/coverage/track_files.rb', line 127

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

.blank_or_comment?(line) ⇒ Boolean

Returns:

  • (Boolean)


62
63
64
65
# File 'lib/polyrun/coverage/track_files.rb', line 62

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)


138
139
140
141
142
143
# File 'lib/polyrun/coverage/track_files.rb', line 138

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”.



71
72
73
74
75
76
77
78
79
80
# File 'lib/polyrun/coverage/track_files.rb', line 71

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



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/polyrun/coverage/track_files.rb', line 82

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



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/polyrun/coverage/track_files.rb', line 104

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

.keep_tracked_files(blob, root, track_files) ⇒ Object

Keeps only loaded files that match configured track_files globs.



26
27
28
29
30
31
32
# File 'lib/polyrun/coverage/track_files.rb', line 26

def keep_tracked_files(blob, root, track_files)
  tracked = expand_globs(root, track_files).each_with_object({}) { |abs, acc| acc[abs] = true }
  blob.each_with_object({}) do |(path, entry), out|
    abs = File.expand_path(path.to_s)
    out[abs] = entry if tracked[abs]
  end
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.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/polyrun/coverage/track_files.rb', line 36

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



132
133
134
135
136
# File 'lib/polyrun/coverage/track_files.rb', line 132

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



145
146
147
# File 'lib/polyrun/coverage/track_files.rb', line 145

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

.simulated_lines_for_unloaded(path) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/polyrun/coverage/track_files.rb', line 52

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