deep-cover 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|