covered 0.5.2 → 0.6.2
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
- data/covered.gemspec +1 -1
- data/lib/covered/capture.rb +56 -5
- data/lib/covered/coverage.rb +23 -0
- data/lib/covered/policy.rb +10 -4
- data/lib/covered/rspec.rb +24 -5
- data/lib/covered/source.rb +24 -16
- data/lib/covered/summary.rb +84 -36
- data/lib/covered/version.rb +1 -1
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0394e15e8b2b00303b22171cf122a90b0ca1172e1a2af3d7a5789cf69c08ad3
|
4
|
+
data.tar.gz: 4043a560028ca031e155c2a578995afd6a799b6119d5dbd40f8f342ed0d5a327
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb55691abee0a0fc745591e17c206ccabaa88e7a66f496730c4a377b0777e2e44a30dc84b15f9ea885c336cd88713e320114894753779fe24ee11518bcde9725
|
7
|
+
data.tar.gz: 44a25c1e34d4546ce7a90dae4082f7236be2380d385ded731d648088ce99e4c6c3473022fedd3d80953a31ebdd499d522b1c38e28a0f65e4c9f34347058caf46
|
data/covered.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_development_dependency "trenni", "~> 3.6"
|
26
26
|
|
27
|
-
spec.add_development_dependency "bundler"
|
27
|
+
spec.add_development_dependency "bundler"
|
28
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
29
29
|
spec.add_development_dependency "rspec", "~> 3.0"
|
30
30
|
end
|
data/lib/covered/capture.rb
CHANGED
@@ -20,20 +20,20 @@
|
|
20
20
|
|
21
21
|
require_relative 'wrapper'
|
22
22
|
|
23
|
+
require 'coverage'
|
24
|
+
|
23
25
|
module Covered
|
24
26
|
class Capture < Wrapper
|
25
27
|
def initialize(output)
|
26
28
|
super(output)
|
27
29
|
|
28
|
-
@trace = TracePoint.new(:line, :call) do |
|
29
|
-
if path =
|
30
|
-
@output.mark(path,
|
30
|
+
@trace = TracePoint.new(:line, :call) do |event|
|
31
|
+
if path = event.path
|
32
|
+
@output.mark(path, event.lineno)
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
attr :paths
|
36
|
-
|
37
37
|
def enable
|
38
38
|
super
|
39
39
|
|
@@ -46,4 +46,55 @@ module Covered
|
|
46
46
|
super
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
class Cache < Wrapper
|
51
|
+
def initialize(output)
|
52
|
+
super(output)
|
53
|
+
@marks = []
|
54
|
+
end
|
55
|
+
|
56
|
+
def mark(path, lineno, count = 1)
|
57
|
+
@marks << path << lineno << count
|
58
|
+
end
|
59
|
+
|
60
|
+
def enable
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def flush
|
65
|
+
@marks.each_slice(3) do |path, lineno, count|
|
66
|
+
@output.mark(path, lineno, count)
|
67
|
+
end
|
68
|
+
|
69
|
+
@marks.clear
|
70
|
+
end
|
71
|
+
|
72
|
+
def disable
|
73
|
+
super
|
74
|
+
|
75
|
+
flush
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# class Capture < Wrapper
|
80
|
+
# def enable
|
81
|
+
# super
|
82
|
+
#
|
83
|
+
# ::Coverage.start
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# def disable
|
87
|
+
# result = ::Coverage.result
|
88
|
+
#
|
89
|
+
# puts result.inspect
|
90
|
+
#
|
91
|
+
# result.each do |path, lines|
|
92
|
+
# lines.each_with_index do |lineno, count|
|
93
|
+
# @output.mark(path, lineno, count)
|
94
|
+
# end
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# super
|
98
|
+
# end
|
99
|
+
# end
|
49
100
|
end
|
data/lib/covered/coverage.rb
CHANGED
@@ -39,6 +39,9 @@ module Covered
|
|
39
39
|
def initialize(path, counts = [])
|
40
40
|
@path = path
|
41
41
|
@counts = counts
|
42
|
+
@total = 0
|
43
|
+
|
44
|
+
@annotations = {}
|
42
45
|
|
43
46
|
@executable_lines = nil
|
44
47
|
@executed_lines = nil
|
@@ -46,22 +49,38 @@ module Covered
|
|
46
49
|
|
47
50
|
attr :path
|
48
51
|
attr :counts
|
52
|
+
attr :total
|
53
|
+
|
54
|
+
attr :annotations
|
49
55
|
|
50
56
|
def freeze
|
51
57
|
return if frozen?
|
52
58
|
|
53
59
|
@counts.freeze
|
60
|
+
@annotations.freeze
|
61
|
+
|
54
62
|
executable_lines
|
55
63
|
executed_lines
|
56
64
|
|
57
65
|
super
|
58
66
|
end
|
59
67
|
|
68
|
+
def zero?
|
69
|
+
@total.zero?
|
70
|
+
end
|
71
|
+
|
60
72
|
def [] lineno
|
61
73
|
@counts[lineno]
|
62
74
|
end
|
63
75
|
|
76
|
+
def annotate(lineno, annotation)
|
77
|
+
@annotations[lineno] ||= []
|
78
|
+
@annotations[lineno] << annotation
|
79
|
+
end
|
80
|
+
|
64
81
|
def mark(lineno, value = 1)
|
82
|
+
@total += value
|
83
|
+
|
65
84
|
if @counts[lineno]
|
66
85
|
@counts[lineno] += value
|
67
86
|
else
|
@@ -85,6 +104,10 @@ module Covered
|
|
85
104
|
executed_lines.count
|
86
105
|
end
|
87
106
|
|
107
|
+
def missing_count
|
108
|
+
executable_count - executed_count
|
109
|
+
end
|
110
|
+
|
88
111
|
include Ratio
|
89
112
|
|
90
113
|
def print_summary(output)
|
data/lib/covered/policy.rb
CHANGED
@@ -37,13 +37,19 @@ module Covered
|
|
37
37
|
class Policy < Wrapper
|
38
38
|
def initialize
|
39
39
|
super(Files.new)
|
40
|
+
|
41
|
+
@threshold = 1.0
|
42
|
+
@summary_class = PartialSummary
|
40
43
|
end
|
41
44
|
|
45
|
+
attr_accessor :summary_class
|
46
|
+
attr_accessor :threshold
|
47
|
+
|
42
48
|
def freeze
|
43
49
|
return if frozen?
|
44
50
|
|
45
51
|
capture
|
46
|
-
summary
|
52
|
+
summary(threshold: @threshold)
|
47
53
|
|
48
54
|
super
|
49
55
|
end
|
@@ -69,7 +75,7 @@ module Covered
|
|
69
75
|
end
|
70
76
|
|
71
77
|
def capture
|
72
|
-
@capture ||= Capture.new(@output)
|
78
|
+
@capture ||= Capture.new(Cache.new(@output))
|
73
79
|
end
|
74
80
|
|
75
81
|
def enable
|
@@ -81,11 +87,11 @@ module Covered
|
|
81
87
|
end
|
82
88
|
|
83
89
|
def summary(*args)
|
84
|
-
@summary ||=
|
90
|
+
@summary ||= @summary_class.new(@output, *args)
|
85
91
|
end
|
86
92
|
|
87
93
|
def print_summary(*args)
|
88
|
-
summary.
|
94
|
+
summary.print_summary(*args)
|
89
95
|
end
|
90
96
|
end
|
91
97
|
end
|
data/lib/covered/rspec.rb
CHANGED
@@ -32,6 +32,12 @@ $covered = Covered.policy do
|
|
32
32
|
include "lib/**/*.rb"
|
33
33
|
|
34
34
|
source
|
35
|
+
|
36
|
+
if coverage = ENV['COVERAGE']
|
37
|
+
self.summary_class = Covered.const_get(coverage)
|
38
|
+
else
|
39
|
+
self.summary_class = Covered::BriefSummary
|
40
|
+
end
|
35
41
|
end
|
36
42
|
|
37
43
|
module Covered
|
@@ -47,18 +53,31 @@ module Covered
|
|
47
53
|
$covered.print_summary(@output)
|
48
54
|
end
|
49
55
|
end
|
56
|
+
|
57
|
+
module Policy
|
58
|
+
def load_spec_files
|
59
|
+
$covered.enable
|
60
|
+
|
61
|
+
super
|
62
|
+
end
|
63
|
+
|
64
|
+
def covered
|
65
|
+
$covered
|
66
|
+
end
|
67
|
+
|
68
|
+
def covered= policy
|
69
|
+
$covered = policy
|
70
|
+
end
|
71
|
+
end
|
50
72
|
end
|
51
73
|
end
|
52
74
|
|
75
|
+
RSpec::Core::Configuration.prepend(Covered::RSpec::Policy)
|
76
|
+
|
53
77
|
RSpec.configure do |config|
|
54
78
|
config.add_formatter(Covered::RSpec::Formatter)
|
55
79
|
|
56
|
-
config.before(:suite) do
|
57
|
-
end
|
58
|
-
|
59
80
|
config.after(:suite) do
|
60
81
|
$covered.disable
|
61
82
|
end
|
62
83
|
end
|
63
|
-
|
64
|
-
$covered.enable
|
data/lib/covered/source.rb
CHANGED
@@ -29,7 +29,7 @@ module Covered
|
|
29
29
|
EXECUTABLE = /(.?CALL|.VAR|.ASGN|DEFN)/.freeze
|
30
30
|
|
31
31
|
# Deviate from the standard policy above, because all the files are already loaded, so we skip NODE_FCALL.
|
32
|
-
DOGFOOD = /(
|
32
|
+
DOGFOOD = /(^V?CALL|.VAR|.ASGN|DEFN)/.freeze
|
33
33
|
|
34
34
|
# Ruby trace points don't trigger for argument execution.
|
35
35
|
# Constants are loaded when the file loads, so they are less interesting.
|
@@ -43,6 +43,8 @@ module Covered
|
|
43
43
|
|
44
44
|
@executable = executable
|
45
45
|
@ignore = ignore
|
46
|
+
|
47
|
+
@annotations = {}
|
46
48
|
end
|
47
49
|
|
48
50
|
def enable
|
@@ -76,24 +78,30 @@ module Covered
|
|
76
78
|
node.nil? or node.type.to_s =~ @ignore
|
77
79
|
end
|
78
80
|
|
79
|
-
def expand(node,
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
81
|
+
def expand(node, coverage, level = 0)
|
82
|
+
if node.is_a? RubyVM::AbstractSyntaxTree::Node
|
83
|
+
if ignore?(node)
|
84
|
+
coverage.annotate(node.first_lineno, "ignoring #{node.type}")
|
85
|
+
else
|
86
|
+
if executable?(node)
|
87
|
+
# coverage.annotate(node.first_lineno, "executable #{node.type}")
|
88
|
+
coverage.counts[node.first_lineno] ||= 0
|
89
|
+
else
|
90
|
+
# coverage.annotate(node.first_lineno, "not executable #{node.type}")
|
91
|
+
end
|
92
|
+
|
93
|
+
expand(node.children, coverage, level + 1)
|
94
|
+
end
|
95
|
+
elsif node.is_a? Array
|
96
|
+
node.each do |child|
|
97
|
+
expand(child, coverage, level)
|
98
|
+
end
|
99
|
+
else
|
100
|
+
return false
|
91
101
|
end
|
92
102
|
end
|
93
103
|
|
94
104
|
def parse(path)
|
95
|
-
# puts "Parse #{path}"
|
96
|
-
|
97
105
|
if source = @paths[path]
|
98
106
|
RubyVM::AbstractSyntaxTree.parse(source)
|
99
107
|
elsif File.exist?(path)
|
@@ -107,7 +115,7 @@ module Covered
|
|
107
115
|
@output.each do |coverage|
|
108
116
|
# This is a little bit inefficient, perhaps add a cache layer?
|
109
117
|
if top = parse(coverage.path)
|
110
|
-
expand(top, coverage
|
118
|
+
self.expand(top, coverage)
|
111
119
|
end
|
112
120
|
|
113
121
|
yield coverage.freeze
|
data/lib/covered/summary.rb
CHANGED
@@ -28,26 +28,38 @@ module Covered
|
|
28
28
|
def initialize(output, threshold: 1.0)
|
29
29
|
super(output)
|
30
30
|
|
31
|
-
@statistics = nil
|
32
|
-
|
33
31
|
@threshold = threshold
|
34
32
|
end
|
35
33
|
|
36
34
|
def each
|
37
|
-
|
35
|
+
statistics = Statistics.new
|
38
36
|
|
39
37
|
super do |coverage|
|
40
|
-
|
38
|
+
statistics << coverage
|
41
39
|
|
42
|
-
if coverage.ratio < @threshold
|
40
|
+
if @threshold.nil? or coverage.ratio < @threshold
|
43
41
|
yield coverage
|
44
42
|
end
|
45
43
|
end
|
44
|
+
|
45
|
+
return statistics
|
46
|
+
end
|
47
|
+
|
48
|
+
def print_annotations(output, coverage, line, line_offset)
|
49
|
+
if annotations = coverage.annotations[line_offset]
|
50
|
+
output.write("#{line_offset}|".rjust(8))
|
51
|
+
output.write("*|".rjust(8))
|
52
|
+
|
53
|
+
output.write line.match(/^\s+/)
|
54
|
+
output.write '# '
|
55
|
+
|
56
|
+
output.puts Rainbow(annotations.join(", ")).bright
|
57
|
+
end
|
46
58
|
end
|
47
59
|
|
48
60
|
# A coverage array gives, for each line, the number of line execution by the interpreter. A nil value means coverage is disabled for this line (lines like else and end).
|
49
61
|
def print_summary(output = $stdout)
|
50
|
-
self.each do |coverage|
|
62
|
+
statistics = self.each do |coverage|
|
51
63
|
line_offset = 1
|
52
64
|
output.puts "", Rainbow(coverage.path).bold.underline
|
53
65
|
|
@@ -57,8 +69,10 @@ module Covered
|
|
57
69
|
file.each_line do |line|
|
58
70
|
count = counts[line_offset]
|
59
71
|
|
72
|
+
print_annotations(output, coverage, line, line_offset)
|
73
|
+
|
60
74
|
output.write("#{line_offset}|".rjust(8))
|
61
|
-
output.write("#{count}
|
75
|
+
output.write("#{count}|".rjust(8))
|
62
76
|
|
63
77
|
if count == nil
|
64
78
|
output.write Rainbow(line).faint
|
@@ -80,45 +94,79 @@ module Covered
|
|
80
94
|
coverage.print_summary(output)
|
81
95
|
end
|
82
96
|
|
83
|
-
|
97
|
+
statistics.print_summary(output)
|
84
98
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
99
|
+
end
|
100
|
+
|
101
|
+
class BriefSummary < Summary
|
102
|
+
def print_summary(output = $stdout, before: 4, after: 4)
|
103
|
+
ordered = []
|
104
|
+
|
105
|
+
statistics = self.each do |coverage|
|
106
|
+
ordered << coverage unless coverage.complete?
|
107
|
+
end
|
88
108
|
|
89
|
-
|
109
|
+
output.puts
|
110
|
+
statistics.print_summary(output)
|
111
|
+
|
112
|
+
if ordered.any?
|
113
|
+
output.puts "", "Least Coverage:"
|
114
|
+
ordered.sort_by!(&:missing_count).reverse!
|
115
|
+
|
116
|
+
ordered.first(5).each do |coverage|
|
117
|
+
output.write Rainbow(coverage.path).orange
|
118
|
+
output.puts ": #{coverage.missing_count} lines not executed!"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class PartialSummary < Summary
|
125
|
+
def print_summary(output = $stdout, before: 4, after: 4)
|
126
|
+
statistics = self.each do |coverage|
|
90
127
|
line_offset = 1
|
91
128
|
output.puts "", Rainbow(coverage.path).bold.underline
|
92
129
|
|
93
130
|
counts = coverage.counts
|
131
|
+
last_line = nil
|
94
132
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
if counts[range]&.include?(0)
|
100
|
-
count = counts[line_offset]
|
101
|
-
|
102
|
-
prefix = "#{line_offset} ".rjust(8) + "#{count} ".rjust(8)
|
133
|
+
unless coverage.zero?
|
134
|
+
File.open(coverage.path, "r") do |file|
|
135
|
+
file.each_line do |line|
|
136
|
+
range = Range.new([line_offset - before, 0].max, line_offset+after)
|
103
137
|
|
104
|
-
if
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
output
|
112
|
-
|
138
|
+
if counts[range]&.include?(0)
|
139
|
+
count = counts[line_offset]
|
140
|
+
|
141
|
+
if last_line and last_line != line_offset-1
|
142
|
+
output.puts ":".rjust(16)
|
143
|
+
end
|
144
|
+
|
145
|
+
print_annotations(output, coverage, line, line_offset)
|
146
|
+
|
147
|
+
prefix = "#{line_offset}|".rjust(8) + "#{count}|".rjust(8)
|
148
|
+
|
149
|
+
if count == nil
|
150
|
+
output.write prefix
|
151
|
+
output.write Rainbow(line).faint
|
152
|
+
elsif count == 0
|
153
|
+
output.write Rainbow(prefix).background(:darkred)
|
154
|
+
output.write Rainbow(line).red
|
155
|
+
else
|
156
|
+
output.write Rainbow(prefix).background(:darkgreen)
|
157
|
+
output.write Rainbow(line).green
|
158
|
+
end
|
159
|
+
|
160
|
+
# If there was no newline at end of file, we add one:
|
161
|
+
unless line.end_with? $/
|
162
|
+
output.puts
|
163
|
+
end
|
164
|
+
|
165
|
+
last_line = line_offset
|
113
166
|
end
|
114
167
|
|
115
|
-
|
116
|
-
unless line.end_with? $/
|
117
|
-
output.puts
|
118
|
-
end
|
168
|
+
line_offset += 1
|
119
169
|
end
|
120
|
-
|
121
|
-
line_offset += 1
|
122
170
|
end
|
123
171
|
end
|
124
172
|
|
@@ -126,7 +174,7 @@ module Covered
|
|
126
174
|
end
|
127
175
|
|
128
176
|
output.puts
|
129
|
-
|
177
|
+
statistics.print_summary(output)
|
130
178
|
end
|
131
179
|
end
|
132
180
|
end
|
data/lib/covered/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: covered
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rainbow
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
requirements: []
|
128
|
-
|
129
|
-
rubygems_version: 2.7.8
|
128
|
+
rubygems_version: 3.0.0.beta3
|
130
129
|
signing_key:
|
131
130
|
specification_version: 4
|
132
131
|
summary: A modern approach to code coverage.
|