rspec-cover_it 0.0.2 → 0.0.4
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/README.md +34 -1
- data/lib/rspec/cover_it/context.rb +7 -3
- data/lib/rspec/cover_it/context_coverage.rb +21 -5
- data/lib/rspec/cover_it/coverage_state.rb +13 -5
- data/lib/rspec/cover_it/pretest_coverage.rb +1 -1
- data/lib/rspec/cover_it/version.rb +1 -1
- data/lib/rspec/cover_it.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 66c4b3e0c88dffe53a1d435d40d4e1bdb52038661d8abb89ccc29ef6974398e2
|
4
|
+
data.tar.gz: 563d49e4e8656ea8da53defeb9e2d5f7ed9a91d36e5de0df126213f35dee6813
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e17ac79db233e4a1f9571f98d025c37cf2e3c304155838fc221507ef5ac6a24aecb47be2f0a6678423009254a0bb5eac442ce775f4ad8bb3f9a66554e9f09fd6
|
7
|
+
data.tar.gz: 0c9afcc6b5f019c185365e5c40925a3b96b4108133d1dcc6150edb182780c35e2a946693106fdf9299e507007a1adfb1dc33cbc341b95f729cea1faf202bbab2
|
data/README.md
CHANGED
@@ -78,7 +78,30 @@ We use `Object.const_source_location` to find the file that defines the
|
|
78
78
|
means that, if you are reopening the class somewhere else, that coverage won't
|
79
79
|
be checked; if you are including 15 Concerns, and don't intend to write separate
|
80
80
|
specs for them, be sure to list them as `covers:` metadata on the test. Also,
|
81
|
-
shame
|
81
|
+
shame!
|
82
|
+
|
83
|
+
## Output
|
84
|
+
|
85
|
+
When there's missing coverage on the class under test, you'll currently see
|
86
|
+
output like this:
|
87
|
+
|
88
|
+
```
|
89
|
+
❯ rspec
|
90
|
+
|
91
|
+
Randomized with seed 29392
|
92
|
+
...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
|
93
|
+
An error occurred in an `after(:context)` hook.
|
94
|
+
Failure/Error: fail(MissingCoverage, message)
|
95
|
+
Missing coverage in /Users/emueller/src/quiet_quality/lib/quiet_quality/message.rb on line 7
|
96
|
+
# /Users/emueller/src/rspec-cover_it/lib/rspec/cover_it/context_coverage.rb:40:in `enforce!'
|
97
|
+
# /Users/emueller/src/rspec-cover_it/lib/rspec/cover_it/coverage_state.rb:37:in `block in finish_tracking_for'
|
98
|
+
# /Users/emueller/src/rspec-cover_it/lib/rspec/cover_it/coverage_state.rb:35:in `finish_tracking_for'
|
99
|
+
# /Users/emueller/src/rspec-cover_it/lib/rspec/cover_it.rb:26:in `block (2 levels) in setup'
|
100
|
+
.....................................................................................................................................................................................................................................................................................................
|
101
|
+
|
102
|
+
Finished in 1.06 seconds (files took 0.28925 seconds to load)
|
103
|
+
852 examples, 0 failures, 1 error occurred outside of examples
|
104
|
+
```
|
82
105
|
|
83
106
|
## Drawbacks and Shortcomings
|
84
107
|
|
@@ -103,3 +126,13 @@ aren't a lot of controls - it works, but it's a bit ugly and doesn't really
|
|
103
126
|
give the right immediate impression. I'm contemplating using an `after(:suite)`
|
104
127
|
hook and aggregating them myself, but at the end of the day RSpec is in control
|
105
128
|
of the output stream, and we don't entirely fit its metaphor.
|
129
|
+
|
130
|
+
We're using `Object.const_source_location` to find the path of the source file
|
131
|
+
defining a given constant. That _mostly_ works, but it actually gives the path
|
132
|
+
of the _first_ source file that defined that constant. So if your gem defines
|
133
|
+
its version in `lib/foo/version.rb` (as an example), in a separate file from
|
134
|
+
lib/foo.rb, the _path_ for `Foo` may end up being the former. Which is.. not
|
135
|
+
going to have much coverable code, of course. This is an edge case, but one
|
136
|
+
that is likely to occur fairly regularly. I haven't thought of a _good_ solution
|
137
|
+
yet. Perhaps if the `covers` array includes a string, we should treat it as a
|
138
|
+
relative path?
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module RSpec
|
2
2
|
module CoverIt
|
3
3
|
class Context
|
4
|
-
def initialize(scope:, rspec_context:)
|
5
|
-
@scope, @rspec_context = scope, rspec_context
|
4
|
+
def initialize(scope:, rspec_context:, autoenforce:)
|
5
|
+
@scope, @rspec_context, @autoenforce = scope, rspec_context, autoenforce
|
6
6
|
end
|
7
7
|
|
8
8
|
def cover_it?
|
9
|
-
target_class && metadata.fetch(:cover_it,
|
9
|
+
target_class && metadata.fetch(:cover_it, autoenforce?)
|
10
10
|
end
|
11
11
|
|
12
12
|
def target_path
|
@@ -25,6 +25,10 @@ module RSpec
|
|
25
25
|
|
26
26
|
attr_reader :scope, :rspec_context
|
27
27
|
|
28
|
+
def autoenforce?
|
29
|
+
@autoenforce
|
30
|
+
end
|
31
|
+
|
28
32
|
def metadata
|
29
33
|
scope.metadata
|
30
34
|
end
|
@@ -8,6 +8,10 @@ module RSpec
|
|
8
8
|
|
9
9
|
attr_accessor :precontext_coverage, :postcontext_coverage
|
10
10
|
|
11
|
+
def pretest_coverage
|
12
|
+
@_pretest_coverage ||= pretest_results[target_path]
|
13
|
+
end
|
14
|
+
|
11
15
|
def local_coverage
|
12
16
|
return nil unless precontext_coverage && postcontext_coverage
|
13
17
|
@_local_coverage ||= pretest_coverage
|
@@ -20,18 +24,30 @@ module RSpec
|
|
20
24
|
covered_line_count.to_f / coverable_line_count.to_f
|
21
25
|
end
|
22
26
|
|
27
|
+
def enforce!
|
28
|
+
return if local_coverage.nil? || local_coverage_rate >= 1.0
|
29
|
+
lines = local_coverage.each_with_index.select { |v, _i| v&.zero? }.map(&:last)
|
30
|
+
|
31
|
+
summary =
|
32
|
+
if lines.length == 1
|
33
|
+
"on line #{lines.first}"
|
34
|
+
elsif lines.length <= 10
|
35
|
+
"on lines #{lines.map(&:to_s).join(", ")}"
|
36
|
+
else
|
37
|
+
"on #{lines.length} lines, including #{lines.first(10).map(&:to_s).join(", ")}"
|
38
|
+
end
|
39
|
+
message = "Missing coverage in #{context.target_path} #{summary}"
|
40
|
+
fail(MissingCoverage, message)
|
41
|
+
end
|
42
|
+
|
23
43
|
private
|
24
44
|
|
25
|
-
attr_reader :context, :pretest_results
|
45
|
+
attr_reader :context, :pretest_results
|
26
46
|
|
27
47
|
def target_path
|
28
48
|
@_target_path ||= context.target_path
|
29
49
|
end
|
30
50
|
|
31
|
-
def pretest_coverage
|
32
|
-
@_pretest_coverage ||= pretest_results[target_path]
|
33
|
-
end
|
34
|
-
|
35
51
|
# Really, we shouldn't see nil for any of these values unless they are all
|
36
52
|
# nil. We want the coverage we'd expect to have seen if we ran _just_ this
|
37
53
|
# groups of examples, which ought boe the pretest coverage, plus the
|
@@ -3,8 +3,8 @@ module RSpec
|
|
3
3
|
class CoverageState
|
4
4
|
attr_reader :filter
|
5
5
|
|
6
|
-
def initialize(filter:)
|
7
|
-
@filter = filter
|
6
|
+
def initialize(filter: nil, autoenforce: false)
|
7
|
+
@filter, @autoenforce = filter, autoenforce
|
8
8
|
@pretest_results = nil
|
9
9
|
@context_coverages = {}
|
10
10
|
end
|
@@ -20,7 +20,7 @@ module RSpec
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def start_tracking_for(scope, rspec_context)
|
23
|
-
context =
|
23
|
+
context = context_for(scope, rspec_context)
|
24
24
|
return unless context.cover_it?
|
25
25
|
|
26
26
|
context_coverage_for(context).tap do |context_coverage|
|
@@ -29,12 +29,12 @@ module RSpec
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def finish_tracking_for(scope, rspec_context)
|
32
|
-
context =
|
32
|
+
context = context_for(scope, rspec_context)
|
33
33
|
return unless context.cover_it?
|
34
34
|
|
35
35
|
context_coverage_for(context).tap do |context_coverage|
|
36
36
|
context_coverage.postcontext_coverage = Coverage.peek_result[context.target_path]
|
37
|
-
|
37
|
+
context_coverage.enforce!
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -42,6 +42,14 @@ module RSpec
|
|
42
42
|
|
43
43
|
attr_reader :pretest_results
|
44
44
|
|
45
|
+
def autoenforce?
|
46
|
+
@autoenforce
|
47
|
+
end
|
48
|
+
|
49
|
+
def context_for(scope, rspec_context)
|
50
|
+
Context.new(scope: scope, rspec_context: rspec_context, autoenforce: autoenforce?)
|
51
|
+
end
|
52
|
+
|
45
53
|
def context_coverage_for(context)
|
46
54
|
@context_coverages[context.target_class] ||= ContextCoverage.new(
|
47
55
|
context: context,
|
data/lib/rspec/cover_it.rb
CHANGED
@@ -16,8 +16,8 @@ module RSpec
|
|
16
16
|
attr_accessor :state
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.setup(filter:)
|
20
|
-
RSpec::CoverIt.state = CoverageState.new(filter: filter)
|
19
|
+
def self.setup(filter: nil, autoenforce: false)
|
20
|
+
RSpec::CoverIt.state = CoverageState.new(filter: filter, autoenforce: autoenforce)
|
21
21
|
RSpec::CoverIt.state.start_tracking
|
22
22
|
|
23
23
|
RSpec.configure do |config|
|