deep-cover 0.5.2 → 0.5.3
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 +5 -5
- data/.deep_cover.rb +8 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +15 -1
- data/.travis.yml +1 -0
- data/README.md +30 -1
- data/Rakefile +10 -1
- data/bin/cov +1 -1
- data/deep_cover.gemspec +4 -5
- data/exe/deep-cover +5 -3
- data/lib/deep_cover.rb +1 -1
- data/lib/deep_cover/analyser/node.rb +1 -1
- data/lib/deep_cover/analyser/ruby25_like_branch.rb +209 -0
- data/lib/deep_cover/auto_run.rb +19 -19
- data/lib/deep_cover/autoload_tracker.rb +181 -44
- data/lib/deep_cover/backports.rb +3 -1
- data/lib/deep_cover/base.rb +13 -8
- data/lib/deep_cover/basics.rb +1 -1
- data/lib/deep_cover/cli/debugger.rb +2 -2
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +21 -8
- data/lib/deep_cover/cli/runner.rb +126 -0
- data/lib/deep_cover/config_setter.rb +1 -0
- data/lib/deep_cover/core_ext/autoload_overrides.rb +82 -14
- data/lib/deep_cover/core_ext/coverage_replacement.rb +34 -5
- data/lib/deep_cover/core_ext/exec_callbacks.rb +27 -0
- data/lib/deep_cover/core_ext/load_overrides.rb +4 -6
- data/lib/deep_cover/core_ext/require_overrides.rb +1 -3
- data/lib/deep_cover/coverage.rb +105 -2
- data/lib/deep_cover/coverage/analysis.rb +30 -28
- data/lib/deep_cover/coverage/persistence.rb +60 -70
- data/lib/deep_cover/covered_code.rb +16 -49
- data/lib/deep_cover/custom_requirer.rb +112 -51
- data/lib/deep_cover/load.rb +10 -6
- data/lib/deep_cover/memoize.rb +1 -3
- data/lib/deep_cover/module_override.rb +7 -0
- data/lib/deep_cover/node/assignments.rb +2 -1
- data/lib/deep_cover/node/base.rb +6 -6
- data/lib/deep_cover/node/block.rb +10 -8
- data/lib/deep_cover/node/case.rb +3 -3
- data/lib/deep_cover/node/collections.rb +8 -0
- data/lib/deep_cover/node/if.rb +19 -3
- data/lib/deep_cover/node/literals.rb +28 -7
- data/lib/deep_cover/node/mixin/can_augment_children.rb +4 -4
- data/lib/deep_cover/node/mixin/child_can_be_empty.rb +1 -1
- data/lib/deep_cover/node/mixin/filters.rb +6 -2
- data/lib/deep_cover/node/mixin/has_child.rb +8 -8
- data/lib/deep_cover/node/mixin/has_child_handler.rb +3 -3
- data/lib/deep_cover/node/mixin/has_tracker.rb +7 -3
- data/lib/deep_cover/node/root.rb +1 -1
- data/lib/deep_cover/node/send.rb +53 -7
- data/lib/deep_cover/node/short_circuit.rb +11 -3
- data/lib/deep_cover/parser_ext/range.rb +11 -27
- data/lib/deep_cover/problem_with_diagnostic.rb +1 -1
- data/lib/deep_cover/reporter.rb +0 -1
- data/lib/deep_cover/reporter/base.rb +68 -0
- data/lib/deep_cover/reporter/html.rb +1 -1
- data/lib/deep_cover/reporter/html/index.rb +4 -8
- data/lib/deep_cover/reporter/html/site.rb +10 -18
- data/lib/deep_cover/reporter/html/source.rb +3 -3
- data/lib/deep_cover/reporter/html/template/source.html.erb +1 -1
- data/lib/deep_cover/reporter/istanbul.rb +86 -56
- data/lib/deep_cover/reporter/text.rb +5 -13
- data/lib/deep_cover/reporter/{util/tree.rb → tree/util.rb} +19 -21
- data/lib/deep_cover/tools/blank.rb +25 -0
- data/lib/deep_cover/tools/builtin_coverage.rb +8 -8
- data/lib/deep_cover/tools/dump_covered_code.rb +2 -9
- data/lib/deep_cover/tools/execute_sample.rb +17 -6
- data/lib/deep_cover/tools/format_generated_code.rb +1 -1
- data/lib/deep_cover/tools/indent_string.rb +26 -0
- data/lib/deep_cover/tools/our_coverage.rb +2 -2
- data/lib/deep_cover/tools/strip_heredoc.rb +18 -0
- data/lib/deep_cover/tracker_bucket.rb +50 -0
- data/lib/deep_cover/tracker_hits_per_path.rb +35 -0
- data/lib/deep_cover/tracker_storage.rb +76 -0
- data/lib/deep_cover/tracker_storage_per_path.rb +34 -0
- data/lib/deep_cover/version.rb +1 -1
- data/lib/deep_cover_entry.rb +3 -0
- metadata +30 -37
- data/bin/gemcov +0 -8
- data/bin/selfcov +0 -21
- data/lib/deep_cover/cli/deep_cover.rb +0 -126
- data/lib/deep_cover/coverage/base.rb +0 -81
- data/lib/deep_cover/coverage/istanbul.rb +0 -34
- data/lib/deep_cover/tools/transform_keys.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f6177553f2233c0751899ecb895cc73ae75777977f26330b76e51507e875eb05
|
4
|
+
data.tar.gz: 213472177be49d89c862b8e0c334c6e5d86ec97d9abc193f201b9ca863092d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 375e33c302f38bda95139adaf8ee2d4500e935ce980794e6dcd382bcd6af42ba8a58c1aa98c830cfd0974ed21763f17bc8341b5720f40900f855a9e7a584e9fd
|
7
|
+
data.tar.gz: b62f8dd1c0978a69b2c0b80850def8adcfda8c8c861dc8c33e803b670ea6cd779c726678f703037f53c0b93ec72c2868dfb73a447baa2bd5799e7d030b295bb7
|
data/.deep_cover.rb
ADDED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -26,6 +26,9 @@ Layout/IndentArray:
|
|
26
26
|
Layout/IndentHash:
|
27
27
|
EnforcedStyle: align_braces
|
28
28
|
|
29
|
+
Layout/IndentHeredoc:
|
30
|
+
Enabled: false
|
31
|
+
|
29
32
|
Layout/MultilineArrayBraceLayout:
|
30
33
|
EnforcedStyle: new_line
|
31
34
|
|
@@ -127,7 +130,10 @@ Style/StringLiterals:
|
|
127
130
|
Style/TrailingCommaInArguments:
|
128
131
|
Enabled: false
|
129
132
|
|
130
|
-
Style/
|
133
|
+
Style/TrailingCommaInArrayLiteral:
|
134
|
+
EnforcedStyleForMultiline: consistent_comma
|
135
|
+
|
136
|
+
Style/TrailingCommaInHashLiteral:
|
131
137
|
EnforcedStyleForMultiline: consistent_comma
|
132
138
|
|
133
139
|
Naming/VariableNumber:
|
@@ -236,3 +242,11 @@ Style/EvalWithLocation:
|
|
236
242
|
|
237
243
|
Lint/BooleanSymbol:
|
238
244
|
Enabled: false
|
245
|
+
|
246
|
+
Naming/UncommunicativeMethodParamName:
|
247
|
+
Exclude:
|
248
|
+
- spec/**/*
|
249
|
+
|
250
|
+
Layout/SpaceInsideReferenceBrackets:
|
251
|
+
Exclude:
|
252
|
+
- spec/**/*
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -41,6 +41,35 @@ These examples are direct outputs from our HTML reporter:
|
|
41
41
|
* [Rails' `activesupport`](https://deep-cover.github.io/rails-cover/activesupport/)
|
42
42
|
* [Rails' `activerecord`](https://deep-cover.github.io/rails-cover/activerecord/)
|
43
43
|
|
44
|
+
## DeepCover vs builtin coverage
|
45
|
+
|
46
|
+
Feature | MRI | DeepCover
|
47
|
+
-------------------|:----------:|:--------:
|
48
|
+
Line coverage | partial | ✓
|
49
|
+
Statement coverage | no | ✓
|
50
|
+
Branch coverage | partial | ✓
|
51
|
+
Method coverage | ✓ | ~
|
52
|
+
Slowdown | < 1% | ~20%
|
53
|
+
Platform support | Ruby 2.5+ | Ruby 2.1+, JRuby
|
54
|
+
|
55
|
+
**Line coverage**: MRI doesn't cover some lines (e.g. `when some_value`).
|
56
|
+
|
57
|
+
**Statement coverage**: MRI provides no way to tell which parts of any line is evaluated. DeepCover covers everything.
|
58
|
+
|
59
|
+
**Method coverage**: MRI considers every method defined, including methods defined on objects or via `define_method`, `class_eval`, etc. For Istanbul output, DeepCover has a different approach and covers all `def` and all blocks.
|
60
|
+
|
61
|
+
**Branch coverage** | MRI | DeepCover
|
62
|
+
------------------------|:---:|:--------:
|
63
|
+
`if` / `unless` / `?:` | ✓ | ✓
|
64
|
+
`case` / `when` | ✓ | ✓
|
65
|
+
`❘❘` / `&&` | no | ✓
|
66
|
+
`foo&.bar` | ✓ | ✓
|
67
|
+
`{❘foo = 42, bar: 43❘}` | no | ✓
|
68
|
+
`while` / `until` | ✓ | !
|
69
|
+
|
70
|
+
*Note on loops (!)*: DeepCover doesn't consider loops to be branches, but it's
|
71
|
+
easy to support it if needed.
|
72
|
+
|
44
73
|
## Installation
|
45
74
|
|
46
75
|
gem install deep-cover
|
@@ -115,7 +144,7 @@ To make it easier to transition for projects already using the builtin `Coverage
|
|
115
144
|
|
116
145
|
Add to your Gemfile `gem 'deep-cover'`, then run `bundle`.
|
117
146
|
|
118
|
-
Before you require `coverage` or `simplecov`, do a `require '
|
147
|
+
Before you require `coverage` or `simplecov`, do a `require 'deep_cover/builtin_takeover'`.
|
119
148
|
|
120
149
|
For example, the `test/test_helper.rb` file for `simplecov` users will look like
|
121
150
|
|
data/Rakefile
CHANGED
@@ -4,7 +4,9 @@ require 'bundler/gem_tasks'
|
|
4
4
|
require 'rspec/core/rake_task'
|
5
5
|
require 'rubocop/rake_task'
|
6
6
|
|
7
|
-
RuboCop::RakeTask.new
|
7
|
+
RuboCop::RakeTask.new(:rubocop) do |t|
|
8
|
+
t.options = ['-a']
|
9
|
+
end
|
8
10
|
|
9
11
|
RSpec::Core::RakeTask.new(:spec).tap { |task| task.pattern = 'spec/*_spec.rb, spec/*/*_spec.rb' }
|
10
12
|
|
@@ -18,6 +20,13 @@ multitask default: RUBY_VERSION > '2.1' ? [:rubocop, :spec] : :spec
|
|
18
20
|
multitask 'test:all' => RUBY_VERSION > '2.1' ? [:rubocop, 'spec:all'] : 'spec:all'
|
19
21
|
|
20
22
|
namespace :dev do
|
23
|
+
desc 'Self cover'
|
24
|
+
task :cov do
|
25
|
+
command = "exe/deep-cover . --no-bundle --command 'rake spec:all'"
|
26
|
+
puts command
|
27
|
+
system command
|
28
|
+
end
|
29
|
+
|
21
30
|
desc 'Setup extra things required to run the spec suite'
|
22
31
|
task :install do
|
23
32
|
commands = []
|
data/bin/cov
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
module DeepCover
|
3
3
|
require 'bundler/setup'
|
4
4
|
|
5
|
-
$LOAD_PATH.unshift('../covered_deep_cover') if ENV['CC']
|
6
5
|
require 'deep_cover'
|
7
6
|
require_relative '../spec/specs_tools'
|
8
7
|
require 'deep_cover/cli/debugger'
|
@@ -10,6 +9,7 @@ module DeepCover
|
|
10
9
|
example = ARGV[0] || 'simple_if'
|
11
10
|
fn = "./spec/samples/#{example}.rb"
|
12
11
|
fn = "./spec/char_cover/#{example}.rb" unless File.exist?(fn)
|
12
|
+
fn = example unless File.exist?(fn)
|
13
13
|
if File.exist?(fn)
|
14
14
|
fn = File.absolute_path(fn)
|
15
15
|
source = File.read(fn)
|
data/deep_cover.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'deep_cover/version'
|
6
6
|
|
@@ -26,14 +26,14 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.required_ruby_version = '>= 2.1.0'
|
27
27
|
|
28
28
|
# Main dependency
|
29
|
-
spec.add_runtime_dependency 'parser'
|
30
|
-
spec.add_runtime_dependency 'parser_tree_rewriter'
|
29
|
+
spec.add_runtime_dependency 'parser', '~> 2.5.0'
|
31
30
|
|
32
31
|
# Support
|
33
32
|
spec.add_runtime_dependency 'backports', '>= 3.11.0'
|
34
33
|
spec.add_runtime_dependency 'binding_of_caller'
|
35
34
|
|
36
35
|
# CLI
|
36
|
+
spec.add_runtime_dependency 'bundler'
|
37
37
|
spec.add_runtime_dependency 'highline'
|
38
38
|
spec.add_runtime_dependency 'slop', '~> 4.0'
|
39
39
|
spec.add_runtime_dependency 'term-ansicolor'
|
@@ -46,10 +46,9 @@ Gem::Specification.new do |spec|
|
|
46
46
|
spec.add_runtime_dependency 'pry'
|
47
47
|
|
48
48
|
### Dev dependencies
|
49
|
-
spec.add_development_dependency 'activesupport', '~> 4.0'
|
50
49
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
51
50
|
spec.add_development_dependency 'psych', '>= 2.0'
|
52
51
|
spec.add_development_dependency 'rake', '~> 12.0'
|
53
52
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
54
|
-
spec.add_development_dependency 'rubocop', '0.
|
53
|
+
spec.add_development_dependency 'rubocop', '0.53.0' # About every single release breaks something
|
55
54
|
end
|
data/exe/deep-cover
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
$LOAD_PATH.unshift(File.expand_path('
|
5
|
-
require 'deep_cover/cli/deep_cover'
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
6
5
|
|
7
|
-
|
6
|
+
require_relative '../lib/deep_cover_entry'
|
7
|
+
require 'deep_cover/cli/runner'
|
8
|
+
|
9
|
+
DeepCover::CLI::Runner.go
|
data/lib/deep_cover.rb
CHANGED
@@ -0,0 +1,209 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'subset'
|
4
|
+
|
5
|
+
module DeepCover
|
6
|
+
class Analyser::Ruby25LikeBranch < Analyser
|
7
|
+
def self.human_name
|
8
|
+
'Ruby25 branches'
|
9
|
+
end
|
10
|
+
include Analyser::Subset
|
11
|
+
SUBSET_CLASSES = [Node::Case, Node::Csend, Node::If, Node::ShortCircuit,
|
12
|
+
Node::Until, Node::UntilPost, Node::While, Node::WhilePost,
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
def initialize(*args)
|
16
|
+
super
|
17
|
+
@loc_index = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def results
|
21
|
+
extractor = NodeCoverageExtrator.new
|
22
|
+
each_node.map do |node|
|
23
|
+
extractor.branch_coverage(node)
|
24
|
+
end.to_h
|
25
|
+
end
|
26
|
+
|
27
|
+
# This is the class doing the work. Since everything is about the node, the class delegates
|
28
|
+
# missing methods to the node, simplifying the code.
|
29
|
+
class NodeCoverageExtrator < SimpleDelegator
|
30
|
+
def initialize(node = nil)
|
31
|
+
self.node = node
|
32
|
+
@loc_index = 0
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :node=, :__setobj__
|
36
|
+
alias_method :node, :__getobj__
|
37
|
+
|
38
|
+
def branch_coverage(node)
|
39
|
+
self.node = node
|
40
|
+
case node
|
41
|
+
when Node::Case
|
42
|
+
handle_case
|
43
|
+
when Node::Csend
|
44
|
+
handle_csend
|
45
|
+
when Node::If
|
46
|
+
handle_if
|
47
|
+
when Node::ShortCircuit
|
48
|
+
handle_short_circuit
|
49
|
+
when Node::Until, Node::While, Node::UntilPost, Node::WhilePost
|
50
|
+
handle_until_while
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle_case
|
55
|
+
cond_info = [:case, *node_loc_infos]
|
56
|
+
|
57
|
+
sub_keys = [:when] * (branches.size - 1) + [:else]
|
58
|
+
empty_fallbacks = whens.map { |w| (w.loc_hash[:begin] || w.loc_hash[:expression]).wrap_rwhitespace_and_comments.end }
|
59
|
+
empty_fallbacks.map!(&:begin)
|
60
|
+
|
61
|
+
if loc_hash[:else]
|
62
|
+
empty_fallbacks << loc_hash[:end].begin
|
63
|
+
else
|
64
|
+
# DeepCover manually inserts a `else` for Case when there isn't one for tracker purposes.
|
65
|
+
# The normal behavior of ruby25's branch coverage when there is no else is to return the loc of the node
|
66
|
+
# So we sent that fallback.
|
67
|
+
empty_fallbacks << expression
|
68
|
+
end
|
69
|
+
|
70
|
+
branches_locs = whens.map do |when_node|
|
71
|
+
next when_node.body if when_node.body.is_a?(Node::EmptyBody)
|
72
|
+
|
73
|
+
start_at = when_node.loc_hash[:begin]
|
74
|
+
start_at = start_at.wrap_rwhitespace_and_comments.end if start_at
|
75
|
+
start_at ||= when_node.body.expression.begin
|
76
|
+
|
77
|
+
end_at = when_node.body.expression.end
|
78
|
+
start_at.with(end_pos: end_at.end_pos)
|
79
|
+
end
|
80
|
+
|
81
|
+
branches_locs << node.else
|
82
|
+
clauses_infos = infos_for_branches(branches_locs, sub_keys, empty_fallbacks, execution_counts: branches.map(&:execution_count))
|
83
|
+
|
84
|
+
[cond_info, clauses_infos]
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_csend
|
88
|
+
cond_info = [:"&.", *node_loc_infos]
|
89
|
+
false_branch, true_branch = branches
|
90
|
+
[cond_info, {[:then, *node_loc_infos] => true_branch.execution_count,
|
91
|
+
[:else, *node_loc_infos] => false_branch.execution_count,
|
92
|
+
},
|
93
|
+
]
|
94
|
+
end
|
95
|
+
|
96
|
+
def handle_if
|
97
|
+
key = style == :unless ? :unless : :if
|
98
|
+
|
99
|
+
node_range = extend_elsif_range
|
100
|
+
cond_info = [key, *node_loc_infos(node_range)]
|
101
|
+
|
102
|
+
sub_keys = [:then, :else]
|
103
|
+
if style == :ternary
|
104
|
+
empty_fallback_locs = [nil, nil]
|
105
|
+
else
|
106
|
+
else_loc = loc_hash[:else]
|
107
|
+
|
108
|
+
first_clause_fallback = loc_hash[:begin]
|
109
|
+
if first_clause_fallback
|
110
|
+
first_clause_fallback = first_clause_fallback.wrap_rwhitespace_and_comments.end
|
111
|
+
elsif else_loc
|
112
|
+
first_clause_fallback = else_loc.begin
|
113
|
+
end
|
114
|
+
|
115
|
+
if else_loc
|
116
|
+
second_clause_fallback = else_loc.wrap_rwhitespace_and_comments.end
|
117
|
+
end
|
118
|
+
end_loc = root_if_node.loc_hash[:end]
|
119
|
+
end_loc = end_loc.begin if end_loc
|
120
|
+
|
121
|
+
empty_fallback_locs = [first_clause_fallback || end_loc, second_clause_fallback || end_loc]
|
122
|
+
end
|
123
|
+
# loc can be nil if the clause can't be empty, such as ternary and modifer if/unless
|
124
|
+
|
125
|
+
if key == :unless
|
126
|
+
sub_keys.reverse!
|
127
|
+
empty_fallback_locs.reverse!
|
128
|
+
end
|
129
|
+
|
130
|
+
branches_locs = branches
|
131
|
+
execution_counts = branches_locs.map(&:execution_count)
|
132
|
+
branches_locs[1] = extend_elsif_range(branches_locs[1])
|
133
|
+
|
134
|
+
clauses_infos = infos_for_branches(branches_locs, sub_keys, empty_fallback_locs, execution_counts: execution_counts, node_range: node_range)
|
135
|
+
[cond_info, clauses_infos]
|
136
|
+
end
|
137
|
+
|
138
|
+
def handle_short_circuit
|
139
|
+
cond_info = [operator, *node_loc_infos]
|
140
|
+
sub_keys = [:then, :else]
|
141
|
+
sub_keys.reverse! if node.is_a?(Node::Or)
|
142
|
+
|
143
|
+
[cond_info, infos_for_branches(branches, sub_keys, [nil, nil])]
|
144
|
+
end
|
145
|
+
|
146
|
+
def handle_until_while
|
147
|
+
key = loc_hash[:keyword].source.to_sym
|
148
|
+
base_info = [key, *node_loc_infos]
|
149
|
+
body_node = if node.is_a?(Node::WhilePost) || node.is_a?(Node::UntilPost)
|
150
|
+
if !body.instructions.empty?
|
151
|
+
end_pos = body.instructions.last.expression.end_pos
|
152
|
+
body.instructions.first.expression.with(end_pos: end_pos)
|
153
|
+
else
|
154
|
+
body.loc_hash[:end].begin
|
155
|
+
end
|
156
|
+
elsif body.is_a?(Node::Begin) && !node.body.expressions.empty?
|
157
|
+
end_pos = body.expressions.last.expression.end_pos
|
158
|
+
body.expressions.first.expression.with(end_pos: end_pos)
|
159
|
+
else
|
160
|
+
body
|
161
|
+
end
|
162
|
+
|
163
|
+
[base_info, {[:body, *node_loc_infos(body_node)] => body.execution_count}]
|
164
|
+
end
|
165
|
+
|
166
|
+
protected
|
167
|
+
|
168
|
+
# If the actual else clause (final one) of an if...elsif...end is empty, then Ruby makes the
|
169
|
+
# node reach the `end` in its branch coverage output
|
170
|
+
def extend_elsif_range(possible_elsif = node)
|
171
|
+
return possible_elsif unless possible_elsif.is_a?(Node::If) && possible_elsif.style == :elsif
|
172
|
+
deepest_if = possible_elsif.deepest_elsif_node
|
173
|
+
if deepest_if.false_branch.is_a?(Node::EmptyBody)
|
174
|
+
return possible_elsif.expression.with(end_pos: possible_elsif.root_if_node.loc_hash[:end].begin_pos)
|
175
|
+
end
|
176
|
+
possible_elsif
|
177
|
+
end
|
178
|
+
|
179
|
+
def infos_for_branch(branch, key, empty_fallback_loc, execution_count: nil, node_range: node)
|
180
|
+
if !branch.is_a?(Node::EmptyBody)
|
181
|
+
loc = branch
|
182
|
+
elsif branch.expression
|
183
|
+
# There is clause, but it is empty
|
184
|
+
loc = empty_fallback_loc
|
185
|
+
else
|
186
|
+
# There is no clause
|
187
|
+
loc = node_range
|
188
|
+
end
|
189
|
+
|
190
|
+
execution_count ||= branch.execution_count
|
191
|
+
[[key, *node_loc_infos(loc)], execution_count]
|
192
|
+
end
|
193
|
+
|
194
|
+
def infos_for_branches(branches, keys, empty_fallback_locs, execution_counts: [], node_range: node)
|
195
|
+
branches_infos = branches.map.with_index do |branch, i|
|
196
|
+
infos_for_branch(branch, keys[i], empty_fallback_locs[i], execution_count: execution_counts[i], node_range: node_range)
|
197
|
+
end
|
198
|
+
branches_infos.to_h
|
199
|
+
end
|
200
|
+
|
201
|
+
def node_loc_infos(node_or_range = node)
|
202
|
+
source_range = node_or_range.is_a?(Node) ? node_or_range.expression : node_or_range
|
203
|
+
|
204
|
+
@loc_index += 1
|
205
|
+
[@loc_index, source_range.line, source_range.column, source_range.last_line, source_range.last_column]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
data/lib/deep_cover/auto_run.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require 'pry'
|
3
|
+
require_relative 'core_ext/exec_callbacks'
|
5
4
|
|
6
5
|
module DeepCover
|
7
6
|
module AutoRun
|
8
7
|
class Runner
|
9
8
|
def initialize(covered_path)
|
10
9
|
@covered_path = covered_path
|
10
|
+
@saved = !(DeepCover.respond_to?(:running?) && DeepCover.running?)
|
11
11
|
end
|
12
12
|
|
13
13
|
def run!
|
14
|
-
@coverage = load_coverage
|
15
14
|
after_tests { save }
|
15
|
+
ExecCallbacks.before_exec { save }
|
16
16
|
self
|
17
17
|
end
|
18
18
|
|
@@ -23,22 +23,26 @@ module DeepCover
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
def
|
27
|
-
@
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
def saved?
|
27
|
+
@saved
|
28
|
+
end
|
29
|
+
|
30
|
+
def coverage
|
31
|
+
@coverage ||= if saved?
|
32
|
+
Coverage.load(@covered_path, with_trackers: false)
|
33
|
+
else
|
34
|
+
DeepCover.coverage
|
35
|
+
end
|
33
36
|
end
|
34
37
|
|
35
38
|
def save
|
36
|
-
|
37
|
-
|
39
|
+
require_relative '../deep_cover'
|
40
|
+
coverage.save(@covered_path) unless saved?
|
41
|
+
coverage.save_trackers(@covered_path)
|
38
42
|
end
|
39
43
|
|
40
44
|
def report(**options)
|
41
|
-
|
45
|
+
coverage.report(**options)
|
42
46
|
end
|
43
47
|
|
44
48
|
def after_tests
|
@@ -60,12 +64,8 @@ module DeepCover
|
|
60
64
|
end
|
61
65
|
|
62
66
|
def self.run!(covered_path)
|
63
|
-
@
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.and_report!(**options)
|
68
|
-
@runner.report!(**options)
|
67
|
+
@runners ||= {}
|
68
|
+
@runners[covered_path] ||= Runner.new(covered_path).run!
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|