covered 0.23.0 → 0.24.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/covered/policy.rb +17 -0
- data/lib/covered/coverage.rb +68 -23
- data/lib/covered/files.rb +7 -61
- data/lib/covered/source.rb +1 -1
- data/lib/covered/statistics.rb +83 -25
- data/lib/covered/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +1 -1
- 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: 05e2a8d6cec9c00fffb320cdb4e6a2e7da8fd9a5361ee762d00353d576c98343
|
|
4
|
+
data.tar.gz: b167be6adaafcbaca11040da20e8593588c810cc20baeacccf344dad73315638
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc31923a4d1dfeaed6be0e7b460c3fd4dff9b9a4d5aaad7b5a6868047eb075c5be0569f981fd274ce4e0548d8c18797dd0fc05ff0ef10a4994edda2a0e1990ab
|
|
7
|
+
data.tar.gz: 1a298bd1af4ac74b56418f46f4cac2d2c0d7618a34c836a404481cc6c31e38795047a7b427ac93d2a2ae85ed3f52eec4b02292e97ad3b8ce8ce26bf1bb9a17d2
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/bake/covered/policy.rb
CHANGED
|
@@ -29,3 +29,20 @@ def current(paths: nil)
|
|
|
29
29
|
|
|
30
30
|
return policy
|
|
31
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/lib/covered/coverage.rb
CHANGED
|
@@ -8,7 +8,7 @@ require_relative 'source'
|
|
|
8
8
|
module Covered
|
|
9
9
|
module Ratio
|
|
10
10
|
def ratio
|
|
11
|
-
return 0 if executable_count.zero?
|
|
11
|
+
return 1.0 if executable_count.zero?
|
|
12
12
|
|
|
13
13
|
Rational(executed_count, executable_count)
|
|
14
14
|
end
|
|
@@ -29,22 +29,67 @@ module Covered
|
|
|
29
29
|
self.new(Source.for(path, **options))
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def initialize(source, counts = [], annotations = {}
|
|
32
|
+
def initialize(source, counts = [], annotations = {})
|
|
33
33
|
@source = source
|
|
34
34
|
@counts = counts
|
|
35
35
|
@annotations = annotations
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_accessor :source
|
|
39
|
+
attr :counts
|
|
40
|
+
attr :annotations
|
|
41
|
+
|
|
42
|
+
def total
|
|
43
|
+
counts.sum{|count| count || 0}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Create an empty coverage with the same source.
|
|
47
|
+
def empty
|
|
48
|
+
self.class.new(@source, [nil] * @counts.size)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def annotate(line_number, annotation)
|
|
52
|
+
@annotations[line_number] ||= []
|
|
53
|
+
@annotations[line_number] << annotation
|
|
54
|
+
end
|
|
55
|
+
|
|
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
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def merge!(other)
|
|
70
|
+
# If the counts are non-zero and don't match, that can indicate a problem.
|
|
36
71
|
|
|
37
|
-
|
|
72
|
+
other.counts.each_with_index do |count, index|
|
|
73
|
+
if count
|
|
74
|
+
@counts[index] ||= 0
|
|
75
|
+
@counts[index] += count
|
|
76
|
+
end
|
|
77
|
+
end
|
|
38
78
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
79
|
+
@annotations.merge!(other.annotations) do |line_number, a, b|
|
|
80
|
+
Array(a) + Array(b)
|
|
81
|
+
end
|
|
42
82
|
end
|
|
43
83
|
|
|
44
84
|
# Construct a new coverage object for the given line numbers. Only the given line numbers will be considered for the purposes of computing coverage.
|
|
45
85
|
# @parameter line_numbers [Array(Integer)] The line numbers to include in the new coverage object.
|
|
46
86
|
def for_lines(line_numbers)
|
|
47
|
-
|
|
87
|
+
counts = [nil] * @counts.size
|
|
88
|
+
line_numbers.each do |line_number|
|
|
89
|
+
counts[line_number] = @counts[line_number]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
self.class.new(@source, counts, @annotations)
|
|
48
93
|
end
|
|
49
94
|
|
|
50
95
|
def path
|
|
@@ -74,13 +119,6 @@ module Covered
|
|
|
74
119
|
return false
|
|
75
120
|
end
|
|
76
121
|
|
|
77
|
-
attr_accessor :source
|
|
78
|
-
|
|
79
|
-
attr :counts
|
|
80
|
-
attr :total
|
|
81
|
-
|
|
82
|
-
attr :annotations
|
|
83
|
-
|
|
84
122
|
def read(&block)
|
|
85
123
|
@source.read(&block)
|
|
86
124
|
end
|
|
@@ -99,15 +137,15 @@ module Covered
|
|
|
99
137
|
end
|
|
100
138
|
|
|
101
139
|
def zero?
|
|
102
|
-
|
|
140
|
+
total.zero?
|
|
103
141
|
end
|
|
104
142
|
|
|
105
|
-
def []
|
|
106
|
-
@counts[
|
|
143
|
+
def [] line_number
|
|
144
|
+
@counts[line_number]
|
|
107
145
|
end
|
|
108
146
|
|
|
109
147
|
def executable_lines
|
|
110
|
-
@
|
|
148
|
+
@counts.compact
|
|
111
149
|
end
|
|
112
150
|
|
|
113
151
|
def executable_count
|
|
@@ -115,7 +153,7 @@ module Covered
|
|
|
115
153
|
end
|
|
116
154
|
|
|
117
155
|
def executed_lines
|
|
118
|
-
|
|
156
|
+
executable_lines.reject(&:zero?)
|
|
119
157
|
end
|
|
120
158
|
|
|
121
159
|
def executed_count
|
|
@@ -131,23 +169,30 @@ module Covered
|
|
|
131
169
|
end
|
|
132
170
|
|
|
133
171
|
def to_s
|
|
134
|
-
"\#<#{self.class} path=#{self.path} #{self.
|
|
172
|
+
"\#<#{self.class} path=#{self.path} #{self.percentage.to_f.round(2)}% covered>"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def as_json
|
|
176
|
+
{
|
|
177
|
+
counts: counts,
|
|
178
|
+
executable_count: executable_count,
|
|
179
|
+
executed_count: executed_count,
|
|
180
|
+
percentage: percentage.to_f.round(2),
|
|
181
|
+
}
|
|
135
182
|
end
|
|
136
183
|
|
|
137
184
|
def serialize(packer)
|
|
138
185
|
packer.write(@source)
|
|
139
186
|
packer.write(@counts)
|
|
140
187
|
packer.write(@annotations)
|
|
141
|
-
packer.write(@total)
|
|
142
188
|
end
|
|
143
189
|
|
|
144
190
|
def self.deserialize(unpacker)
|
|
145
191
|
source = unpacker.read
|
|
146
192
|
counts = unpacker.read
|
|
147
193
|
annotations = unpacker.read
|
|
148
|
-
total = unpacker.read
|
|
149
194
|
|
|
150
|
-
self.new(source, counts, annotations
|
|
195
|
+
self.new(source, counts, annotations)
|
|
151
196
|
end
|
|
152
197
|
end
|
|
153
198
|
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.for(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/source.rb
CHANGED
data/lib/covered/statistics.rb
CHANGED
|
@@ -10,34 +10,86 @@ module Covered
|
|
|
10
10
|
class CoverageError < StandardError
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
class Statistics
|
|
13
|
+
class Statistics
|
|
14
|
+
include Ratio
|
|
15
|
+
|
|
14
16
|
def self.for(coverage)
|
|
15
17
|
self.new.tap do |statistics|
|
|
16
18
|
statistics << coverage
|
|
17
19
|
end
|
|
18
20
|
end
|
|
19
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
|
+
|
|
20
61
|
def initialize
|
|
21
|
-
@
|
|
22
|
-
@
|
|
23
|
-
@executed_count = 0
|
|
62
|
+
@total = Aggregate.new
|
|
63
|
+
@paths = Hash.new
|
|
24
64
|
end
|
|
25
65
|
|
|
26
|
-
|
|
27
|
-
|
|
66
|
+
def count
|
|
67
|
+
@paths.size
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def executable_count
|
|
71
|
+
@total.executable_count
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def executed_count
|
|
75
|
+
@total.executed_count
|
|
76
|
+
end
|
|
28
77
|
|
|
29
|
-
|
|
30
|
-
|
|
78
|
+
def << coverage
|
|
79
|
+
@total << coverage
|
|
80
|
+
(@paths[coverage.path] ||= coverage.empty).merge!(coverage)
|
|
81
|
+
end
|
|
31
82
|
|
|
32
|
-
|
|
33
|
-
|
|
83
|
+
attr :total
|
|
84
|
+
|
|
85
|
+
def [](path)
|
|
86
|
+
@paths[path]
|
|
87
|
+
end
|
|
34
88
|
|
|
35
89
|
def as_json
|
|
36
90
|
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
executed_count: executed_count,
|
|
40
|
-
percentage: percentage.to_f.round(2),
|
|
91
|
+
total: total.as_json,
|
|
92
|
+
paths: @paths.map{|path, coverage| [path, coverage.as_json]}.to_h,
|
|
41
93
|
}
|
|
42
94
|
end
|
|
43
95
|
|
|
@@ -45,23 +97,29 @@ module Covered
|
|
|
45
97
|
as_json.to_json(options)
|
|
46
98
|
end
|
|
47
99
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
]
|
|
56
112
|
|
|
57
113
|
def print(output)
|
|
58
|
-
output.puts "
|
|
114
|
+
output.puts "#{count} files checked; #{@total.executed_count}/#{@total.executable_count} lines executed; #{@total.percentage.to_f.round(2)}% covered."
|
|
59
115
|
|
|
60
|
-
|
|
116
|
+
if self.complete?
|
|
117
|
+
output.puts "🧘 #{COMPLETE.sample}"
|
|
118
|
+
end
|
|
61
119
|
end
|
|
62
120
|
|
|
63
121
|
def validate!(minimum = 1.0)
|
|
64
|
-
if
|
|
122
|
+
if total.ratio < minimum
|
|
65
123
|
raise CoverageError, "Coverage of #{self.percentage.to_f.round(2)}% is less than required minimum of #{(minimum * 100.0).round(2)}%!"
|
|
66
124
|
end
|
|
67
125
|
end
|
data/lib/covered/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
|
Binary file
|