Module: SimpleCov::ResultMerger::ResultsetFile

Defined in:
lib/simplecov/result_merger/resultset_file.rb

Overview

Read + parse a .resultset.json file with the same tolerance the historical ResultMerger had: a missing or empty file quietly returns {}, an unparseable one warns and returns {}, and parse success returns the decoded Hash with any malformed entries warned about and dropped.

Class Method Summary collapse

Class Method Details

.decode(content) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/simplecov/result_merger/resultset_file.rb', line 35

def decode(content)
  return {} unless content

  parsed = JSON.parse(content)
  return {} if parsed.nil? # a "null" file has long meant an empty resultset

  # Valid JSON need not be an object ("[1,2]" and "\"x\"" parse
  # fine), but everything downstream iterates command => data
  # pairs, so anything else would crash out of the middle of a
  # merge. Same tolerance as a parse failure: warn and move on.
  parsed.is_a?(Hash) ? drop_malformed_entries(parsed) : invalid_resultset
rescue StandardError
  invalid_resultset
end

.drop_malformed_entries(resultset) ⇒ Object

Each surviving entry must have the shape every consumer relies on: a Hash carrying a Numeric "timestamp" (the merge-timeout check) and a Hash "coverage" (the merge fold). A truncated or hand-edited entry would otherwise crash out of the middle of an at_exit merge, so it gets the same warn-and-move-on treatment as an unparseable file.



56
57
58
59
60
61
62
# File 'lib/simplecov/result_merger/resultset_file.rb', line 56

def drop_malformed_entries(resultset)
  malformed, valid = resultset.partition { |_command_name, data| !well_formed_entry?(data) }
  return resultset if malformed.empty?

  warn "[SimpleCov]: Warning! Ignoring malformed resultset entries: #{malformed.map(&:first).sort.join(', ')}"
  valid.to_h
end

.invalid_resultsetObject



68
69
70
71
# File 'lib/simplecov/result_merger/resultset_file.rb', line 68

def invalid_resultset
  warn "[SimpleCov]: Warning! Parsing JSON content of resultset file failed"
  {}
end

.parse(path) ⇒ Object



15
16
17
18
# File 'lib/simplecov/result_merger/resultset_file.rb', line 15

def parse(path)
  data = read(path)
  decode(data)
end

.read(path) ⇒ Object

A missing or blank file quietly means "no results yet"; anything else — a 1-byte truncation included — flows through decode so corruption warns instead of silently vanishing (the old length < 2 check swallowed exactly those). Read first and rescue rather than check exist? (racy against a concurrent clean).



26
27
28
29
30
31
32
33
# File 'lib/simplecov/result_merger/resultset_file.rb', line 26

def read(path)
  data = File.read(path)
  return if data.match?(/\A\s*\z/)

  data
rescue Errno::ENOENT
  nil
end

.well_formed_entry?(data) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/simplecov/result_merger/resultset_file.rb', line 64

def well_formed_entry?(data)
  data.is_a?(Hash) && data["timestamp"].is_a?(Numeric) && data["coverage"].is_a?(Hash)
end