covered 0.28.5 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77e334ba3c73dc1b32ce1e9491d299391c7a61bb5b1b97ccbd9bc6714e8d3dde
4
- data.tar.gz: 3cae6b72958a0cc467a812e33fecc05da115ae97c02999aa27786714186a2f0b
3
+ metadata.gz: 0c4bbf71292213867fe6b7edfd7e35b65eedbbb6bfe1a5f985fadb2535af22ee
4
+ data.tar.gz: 96b6183060c491be6ca61d1e6c5397bae731024b6c67a53852872f49d282db31
5
5
  SHA512:
6
- metadata.gz: cfc2a3eca1dd46c39ed3432950872adea86a3ee138f982c11dba1e45f858faa86c9fb9f39ae7dd3fed558bc8d90c2d1ba4dcd6d229b6088d9a587a17033d08ce
7
- data.tar.gz: 28a14c5e7a85f45a590415124fcc88bc1bf503e0dff67a7374c756f35579165bc08406faf1cdf4939502009ebafcddf18225e106737f039eedc7e755885e9535
6
+ metadata.gz: 620ad151084106eaabb854b255a571e52613050d1cd44eb6bbe3af86b17c94088dcdd7f82d1e57748a09fa8ea7de41d06b617d03e88ae51a0354bfcfcd7c53b8
7
+ data.tar.gz: cc520d2837f572ecdf76b53bd9c61058b948cf84036ef988ae17f6b6bbba8e2822191e826486fd5583e2c16c8a04640cbcd632829b4198193aba13fa35e1ce6d
checksums.yaml.gz.sig CHANGED
Binary file
@@ -5,23 +5,36 @@
5
5
 
6
6
  require_relative "wrapper"
7
7
 
8
- require "coverage"
8
+ require "ruby/coverage"
9
9
 
10
10
  module Covered
11
11
  # Captures Ruby coverage data and forwards it to another coverage output.
12
12
  class Capture < Wrapper
13
+ # Initialize capture with independent tracer state.
14
+ def initialize(...)
15
+ super
16
+
17
+ @tracer = nil
18
+ @files = {}
19
+ end
20
+
13
21
  # Start Ruby coverage collection.
14
22
  def start
15
23
  super
16
24
 
17
- ::Coverage.start(lines: true, eval: true)
25
+ @files = {}
26
+ @tracer = build_tracer
27
+ @tracer.start
18
28
  end
19
29
 
20
30
  # Clear any collected coverage data without stopping coverage.
21
31
  def clear
22
32
  super
23
33
 
24
- ::Coverage.result(stop: false, clear: true)
34
+ @tracer&.stop
35
+ @files = {}
36
+ @tracer = build_tracer
37
+ @tracer.start
25
38
  end
26
39
 
27
40
  EVAL_PATHS = {
@@ -33,22 +46,25 @@ module Covered
33
46
  # Stop coverage collection and add the collected results to the output.
34
47
  # Ignores Ruby's anonymous eval paths and files that no longer exist.
35
48
  def finish
36
- results = ::Coverage.result
49
+ @tracer&.stop
37
50
 
38
- results.each do |path, result|
51
+ @files.each do |path, lines|
39
52
  next if EVAL_PATHS.include?(path)
40
53
 
41
54
  path = self.expand_path(path)
42
55
 
43
56
  # Skip files which don't exist. This can happen if `eval` is used with an invalid/incorrect path:
44
57
  if File.exist?(path)
45
- @output.mark(path, 1, result[:lines])
58
+ @output.mark(path, 0, lines)
46
59
  else
47
60
  # warn "Skipping coverage for #{path.inspect} because it doesn't exist!"
48
61
  # Ignore.
49
62
  end
50
63
  end
51
64
 
65
+ @tracer = nil
66
+ @files = {}
67
+
52
68
  super
53
69
  end
54
70
 
@@ -63,5 +79,19 @@ module Covered
63
79
  ensure
64
80
  finish
65
81
  end
82
+
83
+ private
84
+
85
+ def build_tracer
86
+ ::Ruby::Coverage::Tracer.new do |path, iseq|
87
+ @files[path] ||= begin
88
+ lines = []
89
+ ::Ruby::Coverage.executable_lines(iseq).each do |line|
90
+ lines[line] = 0
91
+ end
92
+ lines
93
+ end
94
+ end
95
+ end
66
96
  end
67
97
  end
@@ -190,9 +190,7 @@ module Covered
190
190
 
191
191
  ENV["RUBYOPT"] = rubyopt
192
192
 
193
- unless ENV["COVERED_ROOT"]
194
- ENV["COVERED_ROOT"] = @root
195
- end
193
+ ENV["COVERED_ROOT"] = @root
196
194
 
197
195
  # Don't report coverage in child processes:
198
196
  ENV.delete("COVERAGE")
@@ -51,6 +51,16 @@ module Covered
51
51
  @annotations = annotations
52
52
  end
53
53
 
54
+ # Initialize a copy of this coverage object.
55
+ # @parameter other [Covered::Coverage] The coverage object to copy.
56
+ def initialize_copy(other)
57
+ super
58
+
59
+ @source = other.source.dup
60
+ @counts = other.counts.dup
61
+ @annotations = other.annotations.transform_values(&:dup)
62
+ end
63
+
54
64
  # @attribute [Covered::Source] The covered source metadata.
55
65
  attr_accessor :source
56
66
 
@@ -84,10 +94,10 @@ module Covered
84
94
  # @parameter line_number [Integer] The first line number to mark.
85
95
  # @parameter value [Integer | Array(Integer)] The execution count or counts to add.
86
96
  def mark(line_number, value = 1)
87
- # As currently implemented, @counts is base-zero rather than base-one.
88
- # Line numbers generally start at line 1, so the first line, line 1, is at index 1. This means that index[0] is usually nil.
89
97
  Array(value).each_with_index do |value, index|
90
98
  offset = line_number + index
99
+ next if offset < 1
100
+
91
101
  if @counts[offset]
92
102
  @counts[offset] += value
93
103
  else
data/lib/covered/forks.rb CHANGED
@@ -17,7 +17,7 @@ module Covered
17
17
 
18
18
  # Stop tracking coverage and remove the fork handler state.
19
19
  def finish
20
- Handler.finish
20
+ Handler.finish(self)
21
21
 
22
22
  super
23
23
  end
@@ -27,26 +27,30 @@ module Covered
27
27
  LOCK = Mutex.new
28
28
 
29
29
  class << self
30
- # @attribute [Covered::Forks | Nil] The currently registered coverage wrapper.
31
- attr :coverage
30
+ # The currently registered coverage wrapper.
31
+ # @returns [Covered::Forks | Nil]
32
+ def coverage
33
+ LOCK.synchronize do
34
+ @coverages&.last
35
+ end
36
+ end
32
37
 
33
38
  # Register coverage for fork handling.
34
39
  # @parameter coverage [Covered::Forks] The coverage wrapper to use in forked children.
35
- # @raises [ArgumentError] If coverage is already registered.
36
40
  def start(coverage)
37
41
  LOCK.synchronize do
38
- if @coverage
39
- raise ArgumentError, "Coverage is already being tracked!"
40
- end
41
-
42
- @coverage = coverage
42
+ (@coverages ||= []) << coverage
43
43
  end
44
44
  end
45
45
 
46
46
  # Clear the registered coverage.
47
- def finish
47
+ def finish(coverage = nil)
48
48
  LOCK.synchronize do
49
- @coverage = nil
49
+ if coverage
50
+ @coverages&.delete(coverage)
51
+ else
52
+ @coverages&.pop
53
+ end
50
54
  end
51
55
  end
52
56
 
@@ -28,6 +28,17 @@ module Covered
28
28
  class Aggregate
29
29
  include Ratio
30
30
 
31
+ # Build aggregate statistics from coverage objects.
32
+ # @parameter coverages [Enumerable(Covered::Coverage)] The coverage objects to summarize.
33
+ # @returns [Covered::Statistics::Aggregate] The aggregate statistics.
34
+ def self.for(coverages)
35
+ self.new.tap do |aggregate|
36
+ coverages.each do |coverage|
37
+ aggregate << coverage
38
+ end
39
+ end
40
+ end
41
+
31
42
  # Initialize empty aggregate statistics.
32
43
  def initialize
33
44
  @count = 0
@@ -35,8 +46,7 @@ module Covered
35
46
  @executed_count = 0
36
47
  end
37
48
 
38
- # Total number of files added.
39
- # @returns [Integer] The number of coverage objects added.
49
+ # @attribute [Integer] The total number of coverage instances added.
40
50
  attr :count
41
51
 
42
52
  # The number of lines which could have been executed.
@@ -67,22 +77,28 @@ module Covered
67
77
 
68
78
  # Add coverage to these aggregate statistics.
69
79
  # @parameter coverage [Covered::Coverage] The coverage object to add.
80
+ # @returns [Covered::Statistics::Aggregate] This aggregate.
70
81
  def << coverage
71
82
  @count += 1
72
83
 
73
84
  @executable_count += coverage.executable_count
74
85
  @executed_count += coverage.executed_count
86
+
87
+ self
75
88
  end
76
89
  end
77
90
 
78
91
  # Initialize empty coverage statistics.
79
92
  def initialize
80
- @total = Aggregate.new
93
+ @total = nil
81
94
  @paths = Hash.new
82
95
  end
83
96
 
84
- # @attribute [Covered::Statistics::Aggregate] The total aggregate statistics.
85
- attr :total
97
+ # The total aggregate statistics.
98
+ # @returns [Covered::Statistics::Aggregate] The total aggregate statistics.
99
+ def total
100
+ @total ||= Aggregate.for(@paths.values)
101
+ end
86
102
 
87
103
  # @attribute [Hash(String, Covered::Coverage)] Coverage statistics indexed by path.
88
104
  attr :paths
@@ -96,20 +112,29 @@ module Covered
96
112
  # The total number of executable lines.
97
113
  # @returns [Integer] The total executable line count.
98
114
  def executable_count
99
- @total.executable_count
115
+ total.executable_count
100
116
  end
101
117
 
102
118
  # The total number of executed lines.
103
119
  # @returns [Integer] The total executed line count.
104
120
  def executed_count
105
- @total.executed_count
121
+ total.executed_count
106
122
  end
107
123
 
108
124
  # Add coverage to these statistics.
109
125
  # @parameter coverage [Covered::Coverage] The coverage object to add.
110
126
  def << coverage
111
- @total << coverage
112
- (@paths[coverage.path] ||= coverage.empty).merge!(coverage)
127
+ if current = @paths[coverage.path]
128
+ current.merge!(coverage)
129
+
130
+ @total = nil
131
+ else
132
+ coverage = @paths[coverage.path] = coverage.dup
133
+
134
+ @total << coverage if @total
135
+ end
136
+
137
+ self
113
138
  end
114
139
 
115
140
  # Get coverage for the given path.
@@ -124,7 +149,7 @@ module Covered
124
149
  def as_json
125
150
  {
126
151
  total: total.as_json,
127
- paths: @paths.map{|path, coverage| [path, coverage.as_json]}.to_h,
152
+ paths: paths.map{|path, coverage| [path, coverage.as_json]}.to_h,
128
153
  }
129
154
  end
130
155
 
@@ -151,7 +176,7 @@ module Covered
151
176
  # Print a human-readable coverage summary.
152
177
  # @parameter output [IO] The output stream.
153
178
  def print(output)
154
- output.puts "#{count} files checked; #{@total.executed_count}/#{@total.executable_count} lines executed; #{@total.percentage.to_f.round(2)}% covered."
179
+ output.puts "#{count} files checked; #{total.executed_count}/#{total.executable_count} lines executed; #{total.percentage.to_f.round(2)}% covered."
155
180
 
156
181
  if self.complete?
157
182
  output.puts "🧘 #{COMPLETE.sample}"
@@ -5,5 +5,5 @@
5
5
 
6
6
  # @namespace
7
7
  module Covered
8
- VERSION = "0.28.5"
8
+ VERSION = "0.29.1"
9
9
  end
data/readme.md CHANGED
@@ -34,6 +34,10 @@ Please see the [project documentation](https://socketry.github.io/covered/) for
34
34
 
35
35
  Please see the [project releases](https://socketry.github.io/covered/releases/index) for all releases.
36
36
 
37
+ ### v0.29.0
38
+
39
+ - Prefer `ruby-coverage` over `coverage` for improved coverage tracking.
40
+
37
41
  ### v0.28.5
38
42
 
39
43
  - Make coverage validation quiet when no reports are configured.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.29.0
4
+
5
+ - Prefer `ruby-coverage` over `coverage` for improved coverage tracking.
6
+
3
7
  ## v0.28.5
4
8
 
5
9
  - Make coverage validation quiet when no reports are configured.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: covered
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.28.5
4
+ version: 0.29.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -73,6 +73,20 @@ dependencies:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '1.0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: ruby-coverage
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.1'
76
90
  executables: []
77
91
  extensions: []
78
92
  extra_rdoc_files: []
metadata.gz.sig CHANGED
Binary file