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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2da5bcb0da1de420cf2833d1f2dfbc4ff26cf1eb85e1552d3b5e79902f09ff5c
4
- data.tar.gz: 6bcbbd747726ac1ec443b97401058b85fce046abd5a777085288e105d0f2010d
3
+ metadata.gz: e0394e15e8b2b00303b22171cf122a90b0ca1172e1a2af3d7a5789cf69c08ad3
4
+ data.tar.gz: 4043a560028ca031e155c2a578995afd6a799b6119d5dbd40f8f342ed0d5a327
5
5
  SHA512:
6
- metadata.gz: e733ded2af93f6c93cd77a09e43a9cdaf297880c518c834596382be8c4283a417f0720b2e942b85e4260470165c75f14b021637e0c9f8421c3e5816f4ab44463
7
- data.tar.gz: 247193bd7021f51519cf39ee6d61e801bfd0bf9677dcf65b6c1f6e925c38dd62b17606a1d5546a19d6a2d09d56be69c942641161a58785adc820342c57e8b1e5
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", "~> 2.0"
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
@@ -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 |trace_point|
29
- if path = trace_point.path
30
- @output.mark(path, trace_point.lineno)
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
@@ -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)
@@ -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 ||= Summary.new(@output, *args)
90
+ @summary ||= @summary_class.new(@output, *args)
85
91
  end
86
92
 
87
93
  def print_summary(*args)
88
- summary.print_partial_summary(*args)
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
@@ -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 = /([V]?CALL|.VAR|.ASGN|DEFN)/.freeze
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, counts, level = 0)
80
- # puts "#{node.first_lineno}: #{node.inspect}"
81
-
82
- counts[node.first_lineno] ||= 0 if executable?(node)
83
-
84
- # puts "#{"\t"*level}#{node.type} (#{node.first_lineno})"
85
- node.children.each do |child|
86
- next unless child.is_a? RubyVM::AbstractSyntaxTree::Node
87
-
88
- next if ignore?(child)
89
-
90
- expand(child, counts, level + 1)
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.counts)
118
+ self.expand(top, coverage)
111
119
  end
112
120
 
113
121
  yield coverage.freeze
@@ -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
- @statistics = Statistics.new
35
+ statistics = Statistics.new
38
36
 
39
37
  super do |coverage|
40
- @statistics << coverage
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}:".rjust(8))
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
- @statistics.print_summary(output)
97
+ statistics.print_summary(output)
84
98
  end
85
-
86
- def print_partial_summary(output = $stdout, before: 4, after: 4)
87
- statistics = Statistics.new
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
- self.each do |coverage|
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
- File.open(coverage.path, "r") do |file|
96
- file.each_line do |line|
97
- range = Range.new([line_offset - before, 0].max, line_offset+after)
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 count == nil
105
- output.write prefix
106
- output.write Rainbow(line).faint
107
- elsif count == 0
108
- output.write Rainbow(prefix).background(:darkred)
109
- output.write Rainbow(line).red
110
- else
111
- output.write Rainbow(prefix).background(:darkgreen)
112
- output.write Rainbow(line).green
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
- # If there was no newline at end of file, we add one:
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
- @statistics.print_summary(output)
177
+ statistics.print_summary(output)
130
178
  end
131
179
  end
132
180
  end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Covered
22
- VERSION = "0.5.2"
22
+ VERSION = "0.6.2"
23
23
  end
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.5.2
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-07 00:00:00.000000000 Z
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: '2.0'
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: '2.0'
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
- rubyforge_project:
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.