covered 0.22.1 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c83b08be821b20f583a8e9f7c0c5eff4ded0852016e73e93d3a29f63ed33d79b
4
- data.tar.gz: 8a8cf40418633108d9b5bbb491eaf0c06dc7be5f53a11f2bbc3fac4abfca5cd3
3
+ metadata.gz: 6101920cc470784c2969e8d78252c81678104f6cd882038a306e633f3ec34267
4
+ data.tar.gz: 213bc88224aba333120b869360a663f02355ace3f1dcb4106c5fcdbebd61cd7e
5
5
  SHA512:
6
- metadata.gz: 25f75fb59e078f2d89ca296a583a70d3b93817a4bb3e7863dbecc40a0bc13c21d0a0a66a536960c967483f27a036e25063960d40d52c20dde94fe320b34cb634
7
- data.tar.gz: 7e594df30c68df8df4cf71f0b8063f69dc0e3885d962cc176bbf0a2bf1c2408d6ab6fe2df31f524bcfc5d6162954a7e6f598084d76c851266fad317e0fbb65f0
6
+ metadata.gz: aabfd2999173af2de001ce8a4718483c9801497bb064b27c6892d8c6cb80dc8b2207db0de41a0eb8e4116deac5a2eaf8f68cc2febe8acbea84c4795b666992c1
7
+ data.tar.gz: 302d49b96fcad976a40bc86422976e1526d0b410ed72112190787a8c1ea75309015fe0c6c2fa8359b8d3cf60f9b93f63b021dab063b8e3c1a08d24cb9b79fb59
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2023, by Samuel Williams.
5
+
6
+ def initialize(context)
7
+ super
8
+
9
+ require_relative '../../lib/covered/config'
10
+ end
11
+
12
+ # Load the current coverage policy.
13
+ def current(paths: nil)
14
+ policy = Covered::Policy.new
15
+
16
+ # Load the default path if no paths are specified:
17
+ paths ||= Dir.glob(Covered::Persist::DEFAULT_PATH, base: context.root)
18
+
19
+ # If no paths are specified, raise an error:
20
+ if paths.empty?
21
+ raise ArgumentError, "No coverage paths specified!"
22
+ end
23
+
24
+ # Load all coverage information:
25
+ paths.each do |path|
26
+ # It would be nice to have a better algorithm here than just ignoring mtime - perhaps using checksums?
27
+ Covered::Persist.new(policy.output, path).load!(ignore_mtime: true)
28
+ end
29
+
30
+ return policy
31
+ end
32
+
33
+ # Validate the coverage of multiple test runs.
34
+ # @parameter paths [Array(String)] The coverage database paths.
35
+ # @parameter minimum [Float] The minimum required coverage in order to pass.
36
+ # @parameter input [Covered::Policy] The input policy to validate.
37
+ def statistics(paths: nil, minimum: 1.0, input:)
38
+ policy ||= context.lookup("covered:policy:current").call(paths: paths)
39
+
40
+ # Calculate statistics:
41
+ statistics = Covered::Statistics.new
42
+
43
+ policy.each do |coverage|
44
+ statistics << coverage
45
+ end
46
+
47
+ return statistics
48
+ end
@@ -12,22 +12,9 @@ end
12
12
  # Validate the coverage of multiple test runs.
13
13
  # @parameter paths [Array(String)] The coverage database paths.
14
14
  # @parameter minimum [Float] The minimum required coverage in order to pass.
15
- def validate(paths: nil, minimum: 1.0)
16
- policy = Covered::Policy.new
17
-
18
- # Load the default path if no paths are specified:
19
- paths ||= Dir.glob(Covered::Persist::DEFAULT_PATH, base: context.root)
20
-
21
- # If no paths are specified, raise an error:
22
- if paths.empty?
23
- raise ArgumentError, "No coverage paths specified!"
24
- end
25
-
26
- # Load all coverage information:
27
- paths.each do |path|
28
- # It would be nice to have a better algorithm here than just ignoring mtime - perhaps using checksums?
29
- Covered::Persist.new(policy.output, path).load!(ignore_mtime: true)
30
- end
15
+ # @parameter input [Covered::Policy] The input policy to validate.
16
+ def validate(paths: nil, minimum: 1.0, input:)
17
+ policy ||= context.lookup("covered:policy:current").call(paths: paths)
31
18
 
32
19
  # Calculate statistics:
33
20
  statistics = Covered::Statistics.new
@@ -3,10 +3,12 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2023, by Samuel Williams.
5
5
 
6
+ require_relative 'source'
7
+
6
8
  module Covered
7
9
  module Ratio
8
10
  def ratio
9
- return 0 if executable_count.zero?
11
+ return 1.0 if executable_count.zero?
10
12
 
11
13
  Rational(executed_count, executable_count)
12
14
  end
@@ -20,78 +22,72 @@ module Covered
20
22
  end
21
23
  end
22
24
 
23
- class Source
24
- def self.for(path, code, line_offset)
25
- self.new(path, code: code, line_offset: line_offset)
26
- end
25
+ class Coverage
26
+ include Ratio
27
27
 
28
- def initialize(path, code: nil, line_offset: 1, modified_time: nil)
29
- @path = path
30
- @code = code
31
- @line_offset = line_offset
32
- @modified_time = modified_time
28
+ def self.for(path, **options)
29
+ self.new(Source.for(path, **options))
33
30
  end
34
31
 
35
- attr_accessor :path
36
- attr :code
37
- attr :line_offset
38
- attr :modified_time
39
-
40
- def to_s
41
- "\#<#{self.class} path=#{path}>"
32
+ def initialize(source, counts = [], annotations = {})
33
+ @source = source
34
+ @counts = counts
35
+ @annotations = annotations
42
36
  end
43
37
 
44
- def read(&block)
45
- if block_given?
46
- File.open(self.path, "r", &block)
47
- else
48
- File.read(self.path)
49
- end
50
- end
38
+ attr_accessor :source
39
+ attr :counts
40
+ attr :annotations
51
41
 
52
- # The actual code which is being covered. If a template generates the source, this is the generated code, while the path refers to the template itself.
53
- def code!
54
- self.code || self.read
42
+ def total
43
+ counts.sum{|count| count || 0}
55
44
  end
56
45
 
57
- def code?
58
- !!self.code
46
+ # Create an empty coverage with the same source.
47
+ def empty
48
+ self.class.new(@source, [nil] * @counts.size)
59
49
  end
60
50
 
61
- def serialize(packer)
62
- packer.write(self.path)
63
- packer.write(self.code)
64
- packer.write(self.line_offset)
65
- packer.write(self.modified_time)
51
+ def annotate(line_number, annotation)
52
+ @annotations[line_number] ||= []
53
+ @annotations[line_number] << annotation
66
54
  end
67
55
 
68
- def self.deserialize(unpacker)
69
- path = unpacker.read
70
- code = unpacker.read
71
- line_offset = unpacker.read
72
- modified_time = unpacker.read
73
-
74
- self.new(path, code: code, line_offset: line_offset, modified_time: modified_time)
56
+ def mark(line_number, value = 1)
57
+ # As currently implemented, @counts is base-zero rather than base-one.
58
+ # 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.
59
+ Array(value).each_with_index do |value, index|
60
+ offset = line_number + index
61
+ if @counts[offset]
62
+ @counts[offset] += value
63
+ else
64
+ @counts[offset] = value
65
+ end
66
+ end
75
67
  end
76
- end
77
-
78
- class Coverage
79
- include Ratio
80
68
 
81
- def self.for(path, **options)
82
- self.new(Source.new(path, **options))
69
+ def merge!(other)
70
+ other.counts.each_with_index do |count, index|
71
+ if count
72
+ @counts[index] ||= 0
73
+ @counts[index] += count
74
+ end
75
+ end
76
+
77
+ @annotations.merge!(other.annotations) do |line_number, a, b|
78
+ Array(a) + Array(b)
79
+ end
83
80
  end
84
81
 
85
- def initialize(source, counts = [], annotations = {}, total = nil)
86
- @source = source
87
- @counts = counts
88
- @annotations = annotations
89
-
90
- @total = total || counts.sum{|count| count || 0}
82
+ # Construct a new coverage object for the given line numbers. Only the given line numbers will be considered for the purposes of computing coverage.
83
+ # @parameter line_numbers [Array(Integer)] The line numbers to include in the new coverage object.
84
+ def for_lines(line_numbers)
85
+ counts = [nil] * @counts.size
86
+ line_numbers.each do |line_number|
87
+ counts[line_number] = @counts[line_number]
88
+ end
91
89
 
92
- # Memoized metrics:
93
- @executable_lines = nil
94
- @executed_lines = nil
90
+ self.class.new(@source, counts, @annotations)
95
91
  end
96
92
 
97
93
  def path
@@ -104,8 +100,8 @@ module Covered
104
100
 
105
101
  def fresh?
106
102
  if @source.modified_time.nil?
107
- # We don't know when the file was last modified, so we assume it is fresh:
108
- return true
103
+ # We don't know when the file was last modified, so we assume it is stale:
104
+ return false
109
105
  end
110
106
 
111
107
  unless File.exist?(@source.path)
@@ -121,13 +117,6 @@ module Covered
121
117
  return false
122
118
  end
123
119
 
124
- attr_accessor :source
125
-
126
- attr :counts
127
- attr :total
128
-
129
- attr :annotations
130
-
131
120
  def read(&block)
132
121
  @source.read(&block)
133
122
  end
@@ -146,15 +135,15 @@ module Covered
146
135
  end
147
136
 
148
137
  def zero?
149
- @total.zero?
138
+ total.zero?
150
139
  end
151
140
 
152
- def [] lineno
153
- @counts[lineno]
141
+ def [] line_number
142
+ @counts[line_number]
154
143
  end
155
144
 
156
145
  def executable_lines
157
- @executable_lines ||= @counts.compact
146
+ @counts.compact
158
147
  end
159
148
 
160
149
  def executable_count
@@ -162,7 +151,7 @@ module Covered
162
151
  end
163
152
 
164
153
  def executed_lines
165
- @executed_lines ||= executable_lines.reject(&:zero?)
154
+ executable_lines.reject(&:zero?)
166
155
  end
167
156
 
168
157
  def executed_count
@@ -178,23 +167,30 @@ module Covered
178
167
  end
179
168
 
180
169
  def to_s
181
- "\#<#{self.class} path=#{self.path} #{self.summary.percentage.to_f.round(2)}% covered>"
170
+ "\#<#{self.class} path=#{self.path} #{self.percentage.to_f.round(2)}% covered>"
171
+ end
172
+
173
+ def as_json
174
+ {
175
+ counts: counts,
176
+ executable_count: executable_count,
177
+ executed_count: executed_count,
178
+ percentage: percentage.to_f.round(2),
179
+ }
182
180
  end
183
181
 
184
182
  def serialize(packer)
185
183
  packer.write(@source)
186
184
  packer.write(@counts)
187
185
  packer.write(@annotations)
188
- packer.write(@total)
189
186
  end
190
187
 
191
188
  def self.deserialize(unpacker)
192
189
  source = unpacker.read
193
190
  counts = unpacker.read
194
191
  annotations = unpacker.read
195
- total = unpacker.read
196
192
 
197
- self.new(source, counts, annotations, total)
193
+ self.new(source, counts, annotations)
198
194
  end
199
195
  end
200
196
  end
data/lib/covered/files.rb CHANGED
@@ -10,60 +10,6 @@ require 'set'
10
10
 
11
11
  module Covered
12
12
  class Files < Base
13
- class State
14
- def self.for(path, **options)
15
- self.new(Source.new(path, **options))
16
- end
17
-
18
- def initialize(source)
19
- @source = source
20
- @counts = []
21
- @annotations = {}
22
- end
23
-
24
- def [](lineno)
25
- @counts[lineno]
26
- end
27
-
28
- attr :counts
29
- attr :annotations
30
-
31
- def annotate(lineno, annotation)
32
- @annotations[lineno] ||= []
33
- @annotations[lineno] << annotation
34
- end
35
-
36
- def mark(lineno, value = 1)
37
- # As currently implemented, @counts is base-zero rather than base-one.
38
- # 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.
39
- Array(value).each_with_index do |value, index|
40
- offset = lineno + index
41
- if @counts[offset]
42
- @counts[offset] += value
43
- else
44
- @counts[offset] = value
45
- end
46
- end
47
- end
48
-
49
- def merge!(coverage)
50
- coverage.counts.each_with_index do |count, index|
51
- if count
52
- @counts[index] ||= 0
53
- @counts[index] += count
54
- end
55
- end
56
-
57
- @annotations.merge!(coverage.annotations) do |lineno, a, b|
58
- Array(a) + Array(b)
59
- end
60
- end
61
-
62
- def coverage
63
- Coverage.new(@source, @counts, @annotations)
64
- end
65
- end
66
-
67
13
  def initialize(*)
68
14
  super
69
15
 
@@ -73,19 +19,19 @@ module Covered
73
19
  attr_accessor :paths
74
20
 
75
21
  def [](path)
76
- @paths[path] ||= State.for(path)
22
+ @paths[path] ||= Coverage.for(path)
77
23
  end
78
24
 
79
25
  def empty?
80
26
  @paths.empty?
81
27
  end
82
28
 
83
- def mark(path, lineno, value)
84
- self[path].mark(lineno, value)
29
+ def mark(path, line_number, value)
30
+ self[path].mark(line_number, value)
85
31
  end
86
32
 
87
- def annotate(path, lineno, value)
88
- self[path].annotate(lineno, value)
33
+ def annotate(path, line_number, value)
34
+ self[path].annotate(line_number, value)
89
35
  end
90
36
 
91
37
  def add(coverage)
@@ -95,8 +41,8 @@ module Covered
95
41
  def each
96
42
  return to_enum unless block_given?
97
43
 
98
- @paths.each_value do |state|
99
- yield state.coverage
44
+ @paths.each_value do |coverage|
45
+ yield coverage
100
46
  end
101
47
  end
102
48
 
@@ -21,9 +21,7 @@ module Covered
21
21
  end
22
22
 
23
23
  if $covered.record?
24
- class << Minitest
25
- prepend Covered::Minitest
26
- end
24
+ Minitest.singleton_class.prepend(Covered::Minitest)
27
25
 
28
26
  Minitest.after_run do
29
27
  $covered.finish
@@ -26,8 +26,13 @@ module Covered
26
26
  coverage.path = path
27
27
  end
28
28
 
29
- add(coverage)
29
+ if ignore_mtime || coverage.fresh?
30
+ add(coverage)
31
+ return true
32
+ end
30
33
  end
34
+
35
+ return false
31
36
  end
32
37
 
33
38
  def serialize(coverage)
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2018-2023, by Samuel Williams.
5
+
6
+ module Covered
7
+ class Source
8
+ def self.for(path, **options)
9
+ if File.exist?(path)
10
+ options[:code] ||= File.read(path)
11
+ options[:modified_time] ||= File.mtime(path)
12
+ end
13
+
14
+ self.new(path, **options)
15
+ end
16
+
17
+ def initialize(path, code: nil, line_offset: 1, modified_time: nil)
18
+ @path = path
19
+ @code = code
20
+ @line_offset = line_offset
21
+ @modified_time = modified_time
22
+ end
23
+
24
+ attr_accessor :path
25
+ attr :code
26
+ attr :line_offset
27
+ attr :modified_time
28
+
29
+ def to_s
30
+ "\#<#{self.class} path=#{path}>"
31
+ end
32
+
33
+ def read(&block)
34
+ if block_given?
35
+ File.open(self.path, "r", &block)
36
+ else
37
+ File.read(self.path)
38
+ end
39
+ end
40
+
41
+ # The actual code which is being covered. If a template generates the source, this is the generated code, while the path refers to the template itself.
42
+ def code!
43
+ self.code || self.read
44
+ end
45
+
46
+ def code?
47
+ !!self.code
48
+ end
49
+
50
+ def serialize(packer)
51
+ packer.write(self.path)
52
+ packer.write(self.code)
53
+ packer.write(self.line_offset)
54
+ packer.write(self.modified_time)
55
+ end
56
+
57
+ def self.deserialize(unpacker)
58
+ path = unpacker.read
59
+ code = unpacker.read
60
+ line_offset = unpacker.read
61
+ modified_time = unpacker.read
62
+
63
+ self.new(path, code: code, line_offset: line_offset, modified_time: modified_time)
64
+ end
65
+ end
66
+ end
@@ -10,39 +10,116 @@ module Covered
10
10
  class CoverageError < StandardError
11
11
  end
12
12
 
13
- class Statistics < Wrapper
13
+ class Statistics
14
+ include Ratio
15
+
16
+ def self.for(coverage)
17
+ self.new.tap do |statistics|
18
+ statistics << coverage
19
+ end
20
+ end
21
+
22
+ class Aggregate
23
+ include Ratio
24
+
25
+ def initialize
26
+ @count = 0
27
+ @executable_count = 0
28
+ @executed_count = 0
29
+ end
30
+
31
+ # Total number of files added.
32
+ attr :count
33
+
34
+ # The number of lines which could have been executed.
35
+ attr :executable_count
36
+
37
+ # The number of lines that were executed.
38
+ attr :executed_count
39
+
40
+ def as_json
41
+ {
42
+ count: count,
43
+ executable_count: executable_count,
44
+ executed_count: executed_count,
45
+ percentage: percentage.to_f.round(2),
46
+ }
47
+ end
48
+
49
+ def to_json(options)
50
+ as_json.to_json(options)
51
+ end
52
+
53
+ def << coverage
54
+ @count += 1
55
+
56
+ @executable_count += coverage.executable_count
57
+ @executed_count += coverage.executed_count
58
+ end
59
+ end
60
+
14
61
  def initialize
15
- @count = 0
16
- @executable_count = 0
17
- @executed_count = 0
62
+ @total = Aggregate.new
63
+ @paths = Hash.new
18
64
  end
19
65
 
20
- # Total number of files added.
21
- attr :count
66
+ def count
67
+ @paths.size
68
+ end
22
69
 
23
- # The number of lines which could have been executed.
24
- attr :executable_count
70
+ def executable_count
71
+ @total.executable_count
72
+ end
25
73
 
26
- # The number of lines that were executed.
27
- attr :executed_count
74
+ def executed_count
75
+ @total.executed_count
76
+ end
28
77
 
29
78
  def << coverage
30
- @count += 1
31
-
32
- @executable_count += coverage.executable_count
33
- @executed_count += coverage.executed_count
79
+ @total << coverage
80
+ (@paths[coverage.path] ||= coverage.empty).merge!(coverage)
34
81
  end
35
82
 
36
- include Ratio
83
+ attr :total
84
+
85
+ def [](path)
86
+ @paths[path]
87
+ end
88
+
89
+ def as_json
90
+ {
91
+ total: total.as_json,
92
+ paths: @paths.map{|path, coverage| [path, coverage.as_json]}.to_h,
93
+ }
94
+ end
95
+
96
+ def to_json(options)
97
+ as_json.to_json(options)
98
+ end
99
+
100
+ COMPLETE = [
101
+ "Enter the code dojo: 100% coverage attained, bugs defeated with one swift strike.",
102
+ "Nirvana reached: 100% code coverage, where bugs meditate and vanish like a passing cloud.",
103
+ "With 100% coverage, your code has unlocked the path to enlightenment – bugs have no place to hide.",
104
+ "In the realm of code serenity, 100% coverage is your ticket to coding enlightenment.",
105
+ "100% coverage, where code and bugs coexist in perfect harmony, like Yin and Yang.",
106
+ "Achieving the Zen of code coverage, your code is a peaceful garden where bugs find no shelter.",
107
+ "Congratulations on coding enlightenment! 100% coverage means your code is one with the universe.",
108
+ "With 100% coverage, your code is a tranquil pond where bugs cause no ripples.",
109
+ "At the peak of code mastery: 100% coverage, where bugs bow down before the wisdom of your code.",
110
+ "100% code coverage: Zen achieved! Bugs in harmony, code at peace.",
111
+ ]
37
112
 
38
113
  def print(output)
39
- output.puts "* #{count} files checked; #{executed_count}/#{executable_count} lines executed; #{percentage.to_f.round(2)}% covered."
114
+ output.puts "#{count} files checked; #{@total.executed_count}/#{@total.executable_count} lines executed; #{@total.percentage.to_f.round(2)}% covered."
40
115
 
41
- # Could output funny message here, especially for 100% coverage.
116
+ if self.complete?
117
+ output.puts "🧘 #{COMPLETE.sample}"
118
+ end
42
119
  end
43
120
 
44
121
  def validate!(minimum = 1.0)
45
- if self.ratio < minimum
122
+ if total.ratio < minimum
46
123
  raise CoverageError, "Coverage of #{self.percentage.to_f.round(2)}% is less than required minimum of #{(minimum * 100.0).round(2)}%!"
47
124
  end
48
125
  end
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2018-2023, by Samuel Williams.
5
5
 
6
6
  module Covered
7
- VERSION = "0.22.1"
7
+ VERSION = "0.24.0"
8
8
  end
data/readme.md CHANGED
@@ -1,86 +1,40 @@
1
1
  # Covered
2
2
 
3
- [![Development Status](https://github.com/ioquatix/covered/workflows/Test/badge.svg)](https://github.com/ioquatix/covered/actions?workflow=Test)
3
+ ![Screenshot](media/example.png)
4
4
 
5
- Covered uses modern Ruby features to generate comprehensive coverage, including support for templates which are compiled into Ruby.
5
+ Covered uses modern Ruby features to generate comprehensive coverage, including support for templates which are compiled
6
+ into Ruby.
6
7
 
7
- - Incremental coverage - if you run your full test suite, and the run a subset, it will still report the correct coverage - so you can incrementally work on improving coverage.
8
- - Integration with RSpec, Minitest, Travis & Coveralls - no need to configure anything - out of the box support for these platforms.
8
+ - Incremental coverage - if you run your full test suite, and the run a subset, it will still report the correct
9
+ coverage - so you can incrementally work on improving coverage.
10
+ - Integration with Sus, Git, RSpec and Minitest- no need to configure anything - out of the box support for these
11
+ platforms.
9
12
  - Supports coverage of views - templates compiled to Ruby code can be tracked for coverage reporting.
10
13
 
11
- ![Screenshot](media/example.png)
14
+ [![Development
15
+ Status](https://github.com/ioquatix/covered/workflows/Test/badge.svg)](https://github.com/ioquatix/covered/actions?workflow=Test)
12
16
 
13
17
  ## Motivation
14
18
 
15
- Existing Ruby coverage tools are unable to handle `eval`ed code. This is because the `coverage` module built into Ruby doesn't expose the necessary hooks to capture it. Using the [parser](https://github.com/whitequark/parser) gem allows us to do our own source code analysis to compute executable lines, thus making it possible to compute coverage for "templates".
16
-
17
- It's still tricky to do it correctly, but it is feasible now to compute coverage of web application "views" by using this technique. This gem is an exploration to see what is possible.
18
-
19
- ## Installation
20
-
21
- Add this line to your application's `Gemfile`:
22
-
23
- ``` ruby
24
- gem 'covered'
25
- ```
26
-
27
- ### RSpec Integration
28
-
29
- In your `spec/spec_helper.rb` add the following before loading any other code:
30
-
31
- ``` ruby
32
- require 'covered/rspec'
33
- ```
34
-
35
- Ensure that you have a `.rspec` file with `--require spec_helper`:
36
-
37
- --require spec_helper
38
- --format documentation
39
- --warnings
40
-
41
- ### Minitest Integration
19
+ Originally, Ruby coverage tools were unable to handle `eval`ed code. This is because the `coverage` module built into
20
+ Ruby doesn't expose the necessary hooks to capture it. Using the [parser](https://github.com/whitequark/parser) gem and
21
+ trace points allows us to do our own source code analysis to compute executable lines, thus making it possible to
22
+ compute coverage for "templates".
42
23
 
43
- In your `test/test_helper.rb` add the following before loading any other code:
44
-
45
- ``` ruby
46
- require 'covered/minitest'
47
- require 'minitest/autorun'
48
- ```
49
-
50
- In your test files, e.g. `test/dummy_test.rb` add the following at the top:
51
-
52
- ``` ruby
53
- require_relative 'test_helper'
54
- ```
24
+ After this concept prooved useful, [it was integrated directly into Ruby](https://bugs.ruby-lang.org/issues/19008).
55
25
 
56
26
  ## Usage
57
27
 
58
- When running `rspec`, you can specify the kind of coverage analysis you would like:
59
-
60
- COVERAGE=Summary rspec
61
-
62
- If no `COVERAGE` is specified, coverage tracking will be finishd.
63
-
64
- ### Template Coverage
65
-
66
- Covered supports coverage of templates which are compiled into Ruby code. This is only supported on Ruby 3.2+ due to enhancements in the coverage interface.
67
-
68
- ### Partial Summary
69
-
70
- COVERAGE=PartialSummary rspec
71
-
72
- This report only shows snippets of source code with incomplete coverage.
73
-
74
- ### Brief Summary
75
-
76
- COVERAGE=BriefSummary rspec
28
+ Please see the [project documentation](https://github.com/ioquatix/covered) for more details.
77
29
 
78
- This report lists several files in order of least coverage.l
30
+ - [Getting Started](https://github.com/ioquatix/coveredguides/getting-started/index) - This guide explains how to get
31
+ started with `covered` and integrate it with your test suite.
79
32
 
80
33
  ## See Also
81
34
 
82
- - [coveralls-ruby](https://github.com/lemurheavy/coveralls-ruby) – the official Coveralls implementation for Ruby.
83
- - [simplecov](https://github.com/colszowka/simplecov) – one of the original coverage implementations for Ruby, uses the built-in `coverage` library.
35
+ - [simplecov](https://github.com/colszowka/simplecov) – one of the original coverage implementations for Ruby, uses
36
+ the built-in `coverage` library.
37
+ - [sus](https://github.com/ioquatix/sus) - a test framework which uses `covered` to generate coverage reports.
84
38
 
85
39
  ## Contributing
86
40
 
@@ -94,8 +48,10 @@ We welcome contributions to this project.
94
48
 
95
49
  ### Developer Certificate of Origin
96
50
 
97
- This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
51
+ This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this
52
+ project must agree to this document to have their contributions accepted.
98
53
 
99
54
  ### Contributor Covenant
100
55
 
101
- This project is governed by [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
56
+ This project is governed by [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and
57
+ participants agree to abide by its terms.
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.22.1
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -42,7 +42,7 @@ cert_chain:
42
42
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
43
43
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
44
44
  -----END CERTIFICATE-----
45
- date: 2023-07-17 00:00:00.000000000 Z
45
+ date: 2023-07-20 00:00:00.000000000 Z
46
46
  dependencies:
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: console
@@ -79,6 +79,7 @@ extensions: []
79
79
  extra_rdoc_files: []
80
80
  files:
81
81
  - bake/covered/debug.rb
82
+ - bake/covered/policy.rb
82
83
  - bake/covered/validate.rb
83
84
  - lib/covered.rb
84
85
  - lib/covered/autostart.rb
@@ -92,6 +93,7 @@ files:
92
93
  - lib/covered/persist.rb
93
94
  - lib/covered/policy.rb
94
95
  - lib/covered/rspec.rb
96
+ - lib/covered/source.rb
95
97
  - lib/covered/statistics.rb
96
98
  - lib/covered/summary.rb
97
99
  - lib/covered/sus.rb
metadata.gz.sig CHANGED
Binary file