covered 0.22.1 → 0.24.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/covered/policy.rb +48 -0
- data/bake/covered/validate.rb +3 -16
- data/lib/covered/coverage.rb +70 -74
- data/lib/covered/files.rb +7 -61
- data/lib/covered/minitest.rb +1 -3
- data/lib/covered/persist.rb +6 -1
- data/lib/covered/source.rb +66 -0
- data/lib/covered/statistics.rb +95 -18
- data/lib/covered/version.rb +1 -1
- data/readme.md +24 -68
- data.tar.gz.sig +0 -0
- metadata +4 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6101920cc470784c2969e8d78252c81678104f6cd882038a306e633f3ec34267
|
4
|
+
data.tar.gz: 213bc88224aba333120b869360a663f02355ace3f1dcb4106c5fcdbebd61cd7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/bake/covered/validate.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
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
|
data/lib/covered/coverage.rb
CHANGED
@@ -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
|
24
|
-
|
25
|
-
self.new(path, code: code, line_offset: line_offset)
|
26
|
-
end
|
25
|
+
class Coverage
|
26
|
+
include Ratio
|
27
27
|
|
28
|
-
def
|
29
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
else
|
48
|
-
File.read(self.path)
|
49
|
-
end
|
50
|
-
end
|
38
|
+
attr_accessor :source
|
39
|
+
attr :counts
|
40
|
+
attr :annotations
|
51
41
|
|
52
|
-
|
53
|
-
|
54
|
-
self.code || self.read
|
42
|
+
def total
|
43
|
+
counts.sum{|count| count || 0}
|
55
44
|
end
|
56
45
|
|
57
|
-
|
58
|
-
|
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
|
62
|
-
|
63
|
-
|
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
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
82
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
108
|
-
return
|
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
|
-
|
138
|
+
total.zero?
|
150
139
|
end
|
151
140
|
|
152
|
-
def []
|
153
|
-
@counts[
|
141
|
+
def [] line_number
|
142
|
+
@counts[line_number]
|
154
143
|
end
|
155
144
|
|
156
145
|
def executable_lines
|
157
|
-
@
|
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
|
-
|
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.
|
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
|
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] ||=
|
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,
|
84
|
-
self[path].mark(
|
29
|
+
def mark(path, line_number, value)
|
30
|
+
self[path].mark(line_number, value)
|
85
31
|
end
|
86
32
|
|
87
|
-
def annotate(path,
|
88
|
-
self[path].annotate(
|
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 |
|
99
|
-
yield
|
44
|
+
@paths.each_value do |coverage|
|
45
|
+
yield coverage
|
100
46
|
end
|
101
47
|
end
|
102
48
|
|
data/lib/covered/minitest.rb
CHANGED
data/lib/covered/persist.rb
CHANGED
@@ -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
|
data/lib/covered/statistics.rb
CHANGED
@@ -10,39 +10,116 @@ module Covered
|
|
10
10
|
class CoverageError < StandardError
|
11
11
|
end
|
12
12
|
|
13
|
-
class Statistics
|
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
|
-
@
|
16
|
-
@
|
17
|
-
@executed_count = 0
|
62
|
+
@total = Aggregate.new
|
63
|
+
@paths = Hash.new
|
18
64
|
end
|
19
65
|
|
20
|
-
|
21
|
-
|
66
|
+
def count
|
67
|
+
@paths.size
|
68
|
+
end
|
22
69
|
|
23
|
-
|
24
|
-
|
70
|
+
def executable_count
|
71
|
+
@total.executable_count
|
72
|
+
end
|
25
73
|
|
26
|
-
|
27
|
-
|
74
|
+
def executed_count
|
75
|
+
@total.executed_count
|
76
|
+
end
|
28
77
|
|
29
78
|
def << coverage
|
30
|
-
@
|
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
|
-
|
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 "
|
114
|
+
output.puts "#{count} files checked; #{@total.executed_count}/#{@total.executable_count} lines executed; #{@total.percentage.to_f.round(2)}% covered."
|
40
115
|
|
41
|
-
|
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
|
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
|
data/lib/covered/version.rb
CHANGED
data/readme.md
CHANGED
@@ -1,86 +1,40 @@
|
|
1
1
|
# Covered
|
2
2
|
|
3
|
-
|
3
|
+

|
4
4
|
|
5
|
-
Covered uses modern Ruby features to generate comprehensive coverage, including support for templates which are compiled
|
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
|
8
|
-
|
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
|
-
](https://github.com/ioquatix/covered/actions?workflow=Test)
|
12
16
|
|
13
17
|
## Motivation
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
- [
|
83
|
-
|
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
|
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
|
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.
|
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-
|
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
|