deep-cover 0.1.14 → 0.1.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +227 -0
- data/Gemfile +5 -2
- data/Rakefile +9 -6
- data/bin/console +3 -3
- data/bin/cov +8 -8
- data/bin/gemcov +2 -2
- data/bin/selfcov +5 -5
- data/bin/test_gems +11 -10
- data/bin/testall +6 -6
- data/deep_cover.gemspec +26 -21
- data/exe/deep-cover +1 -0
- data/lib/deep-cover.rb +2 -0
- data/lib/deep_cover.rb +3 -0
- data/lib/deep_cover/analyser.rb +2 -0
- data/lib/deep_cover/analyser/base.rb +2 -0
- data/lib/deep_cover/analyser/branch.rb +4 -2
- data/lib/deep_cover/analyser/covered_code_source.rb +3 -1
- data/lib/deep_cover/analyser/function.rb +3 -1
- data/lib/deep_cover/analyser/ignore_uncovered.rb +6 -4
- data/lib/deep_cover/analyser/node.rb +3 -0
- data/lib/deep_cover/analyser/optionally_covered.rb +12 -7
- data/lib/deep_cover/analyser/per_char.rb +7 -6
- data/lib/deep_cover/analyser/per_line.rb +9 -8
- data/lib/deep_cover/analyser/statement.rb +2 -0
- data/lib/deep_cover/analyser/subset.rb +4 -1
- data/lib/deep_cover/auto_run.rb +3 -0
- data/lib/deep_cover/autoload_tracker.rb +6 -3
- data/lib/deep_cover/backports.rb +2 -0
- data/lib/deep_cover/base.rb +11 -2
- data/lib/deep_cover/builtin_takeover.rb +2 -0
- data/lib/deep_cover/cli/debugger.rb +55 -30
- data/lib/deep_cover/cli/deep_cover.rb +17 -11
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +16 -14
- data/lib/deep_cover/config.rb +29 -16
- data/lib/deep_cover/core_ext/autoload_overrides.rb +2 -0
- data/lib/deep_cover/core_ext/coverage_replacement.rb +2 -0
- data/lib/deep_cover/core_ext/load_overrides.rb +5 -6
- data/lib/deep_cover/core_ext/require_overrides.rb +6 -7
- data/lib/deep_cover/coverage.rb +21 -18
- data/lib/deep_cover/covered_code.rb +22 -12
- data/lib/deep_cover/custom_requirer.rb +82 -35
- data/lib/deep_cover/memoize.rb +48 -0
- data/lib/deep_cover/module_override.rb +2 -0
- data/lib/deep_cover/node.rb +14 -1
- data/lib/deep_cover/node/arguments.rb +2 -0
- data/lib/deep_cover/node/assignments.rb +32 -30
- data/lib/deep_cover/node/base.rb +30 -29
- data/lib/deep_cover/node/begin.rb +3 -1
- data/lib/deep_cover/node/block.rb +5 -2
- data/lib/deep_cover/node/branch.rb +2 -1
- data/lib/deep_cover/node/case.rb +15 -13
- data/lib/deep_cover/node/collections.rb +2 -0
- data/lib/deep_cover/node/const.rb +2 -0
- data/lib/deep_cover/node/def.rb +10 -8
- data/lib/deep_cover/node/empty_body.rb +2 -0
- data/lib/deep_cover/node/exceptions.rb +3 -1
- data/lib/deep_cover/node/if.rb +3 -1
- data/lib/deep_cover/node/keywords.rb +4 -2
- data/lib/deep_cover/node/literals.rb +2 -0
- data/lib/deep_cover/node/loops.rb +5 -3
- data/lib/deep_cover/node/mixin/can_augment_children.rb +8 -7
- data/lib/deep_cover/node/mixin/check_completion.rb +3 -1
- data/lib/deep_cover/node/mixin/child_can_be_empty.rb +4 -2
- data/lib/deep_cover/node/mixin/executed_after_children.rb +2 -0
- data/lib/deep_cover/node/mixin/execution_location.rb +4 -2
- data/lib/deep_cover/node/mixin/flow_accounting.rb +2 -0
- data/lib/deep_cover/node/mixin/has_child.rb +22 -18
- data/lib/deep_cover/node/mixin/has_child_handler.rb +10 -8
- data/lib/deep_cover/node/mixin/has_tracker.rb +4 -2
- data/lib/deep_cover/node/mixin/is_statement.rb +3 -1
- data/lib/deep_cover/node/mixin/rewriting.rb +5 -3
- data/lib/deep_cover/node/mixin/wrapper.rb +2 -0
- data/lib/deep_cover/node/module.rb +11 -9
- data/lib/deep_cover/node/root.rb +2 -0
- data/lib/deep_cover/node/send.rb +4 -2
- data/lib/deep_cover/node/short_circuit.rb +4 -2
- data/lib/deep_cover/node/splat.rb +2 -0
- data/lib/deep_cover/node/variables.rb +2 -0
- data/lib/deep_cover/parser_ext/range.rb +3 -1
- data/lib/deep_cover/problem_with_diagnostic.rb +11 -9
- data/lib/deep_cover/reporter.rb +2 -0
- data/lib/deep_cover/reporter/istanbul.rb +28 -24
- data/lib/deep_cover/tools.rb +2 -0
- data/lib/deep_cover/tools/builtin_coverage.rb +6 -4
- data/lib/deep_cover/tools/camelize.rb +3 -1
- data/lib/deep_cover/tools/dasherize.rb +3 -1
- data/lib/deep_cover/tools/dump_covered_code.rb +7 -6
- data/lib/deep_cover/tools/execute_sample.rb +13 -13
- data/lib/deep_cover/tools/format.rb +3 -1
- data/lib/deep_cover/tools/format_char_cover.rb +4 -2
- data/lib/deep_cover/tools/format_generated_code.rb +3 -1
- data/lib/deep_cover/tools/number_lines.rb +2 -0
- data/lib/deep_cover/tools/our_coverage.rb +5 -3
- data/lib/deep_cover/tools/profiling.rb +66 -0
- data/lib/deep_cover/tools/require_relative_dir.rb +3 -1
- data/lib/deep_cover/tools/silence_warnings.rb +4 -1
- data/lib/deep_cover/tools/slice.rb +3 -1
- data/lib/deep_cover/tools/truncate_backtrace.rb +2 -0
- data/lib/deep_cover/version.rb +3 -1
- metadata +47 -30
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DeepCover
|
2
4
|
require 'bundler/setup'
|
3
5
|
require 'slop'
|
@@ -9,7 +11,7 @@ module DeepCover
|
|
9
11
|
extend self
|
10
12
|
|
11
13
|
def show_version
|
12
|
-
puts "deep-cover v#{DeepCover::VERSION}; parser v#{Parser::
|
14
|
+
puts "deep-cover v#{::DeepCover::VERSION}; parser v#{::Parser::VERSION}"
|
13
15
|
end
|
14
16
|
|
15
17
|
def show_help
|
@@ -17,7 +19,7 @@ module DeepCover
|
|
17
19
|
end
|
18
20
|
|
19
21
|
class Parser < Struct.new(:delegate)
|
20
|
-
def method_missing(method, *args, &block)
|
22
|
+
def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissing
|
21
23
|
options = args.last
|
22
24
|
if options.is_a?(Hash) && options.has_key?(:default)
|
23
25
|
args[-2] += " [#{options[:default]}]"
|
@@ -34,7 +36,7 @@ module DeepCover
|
|
34
36
|
|
35
37
|
def menu
|
36
38
|
@menu ||= parse do |o|
|
37
|
-
o.banner =
|
39
|
+
o.banner = 'usage: deep-cover [options] [path/to/app/or/gem]'
|
38
40
|
o.separator ''
|
39
41
|
o.string '-o', '--output', 'output folder', default: './coverage'
|
40
42
|
o.string '-c', '--command', 'command to run tests', default: 'bundle exec rake'
|
@@ -43,18 +45,20 @@ module DeepCover
|
|
43
45
|
o.separator 'Coverage options'
|
44
46
|
@ignore_uncovered_map = Analyser.optionally_covered.map do |option|
|
45
47
|
default = Config::DEFAULTS[:ignore_uncovered].include?(option)
|
46
|
-
o.bool "--ignore-#{Tools.dasherize(option)}",
|
48
|
+
o.bool "--ignore-#{Tools.dasherize(option)}", '', default: default
|
47
49
|
[:"ignore_#{option}", option]
|
48
50
|
end.to_h
|
49
|
-
o.separator
|
50
|
-
o.
|
51
|
+
o.separator "\nFor testing purposes:"
|
52
|
+
o.bool '--profile', 'use profiler' unless RUBY_PLATFORM == 'java'
|
51
53
|
o.string '-e', '--expression', 'test ruby expression instead of a covering a path'
|
52
54
|
o.bool '-d', '--debug', 'enter debugging after cover'
|
53
55
|
|
54
|
-
o.separator
|
55
|
-
o.
|
56
|
-
|
57
|
-
|
56
|
+
o.separator "\nOther available commands:"
|
57
|
+
o.on('--version', 'print the version') do
|
58
|
+
show_version
|
59
|
+
exit
|
60
|
+
end
|
61
|
+
o.boolean('-h', '--help')
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
@@ -68,7 +72,9 @@ module DeepCover
|
|
68
72
|
|
69
73
|
def go
|
70
74
|
options = convert_options(menu.to_h)
|
71
|
-
if options[:
|
75
|
+
if options[:help]
|
76
|
+
show_help
|
77
|
+
elsif options[:expression]
|
72
78
|
Debugger.new(options[:expression], **options).show
|
73
79
|
elsif (path = menu.arguments.first)
|
74
80
|
InstrumentedCloneReporter.new(path, **options).run
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
require 'tmpdir'
|
3
5
|
|
@@ -18,7 +20,7 @@ module DeepCover
|
|
18
20
|
raise "Can't find Gemfile" unless @root_path.join('Gemfile').exist?
|
19
21
|
end
|
20
22
|
@dest_root = Pathname('~/test_deep_cover').expand_path
|
21
|
-
@dest_root = Pathname.new(Dir.mktmpdir(
|
23
|
+
@dest_root = Pathname.new(Dir.mktmpdir('deep_cover_test')) unless @dest_root.exist?
|
22
24
|
|
23
25
|
gem_relative_path = @source_path.relative_path_from(@root_path)
|
24
26
|
@main_path = @dest_root.join(gem_relative_path)
|
@@ -31,7 +33,7 @@ module DeepCover
|
|
31
33
|
|
32
34
|
def copy
|
33
35
|
return true if @copied
|
34
|
-
puts
|
36
|
+
puts 'Cloning...'
|
35
37
|
FileUtils.cp_r(Dir.glob("#{@root_path}/#{GLOB_ALL_CONTENT}"), @dest_root)
|
36
38
|
@copied = true
|
37
39
|
end
|
@@ -39,7 +41,7 @@ module DeepCover
|
|
39
41
|
def patch_ruby_file(ruby_file)
|
40
42
|
content = ruby_file.read
|
41
43
|
# Insert our code after leading comments:
|
42
|
-
content.sub!(/^(
|
44
|
+
content.sub!(/^(#.*\n+)*/) { |header| "#{header}require 'deep_cover/auto_run';DeepCover::AutoRun.run! '#{@dest_root}';" }
|
43
45
|
ruby_file.write(content)
|
44
46
|
end
|
45
47
|
|
@@ -79,7 +81,7 @@ module DeepCover
|
|
79
81
|
module GemCollection
|
80
82
|
include Gem
|
81
83
|
def each_gem_path
|
82
|
-
Pathname.glob(@main_path.join('*/lib')).each{|p| yield p.dirname}
|
84
|
+
Pathname.glob(@main_path.join('*/lib')).each { |p| yield p.dirname }
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
@@ -108,19 +110,19 @@ module DeepCover
|
|
108
110
|
unless content =~ /gem 'deep-cover'/
|
109
111
|
puts "Patching Gemfile #{gemfile}"
|
110
112
|
File.write(gemfile, [
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
'# This file was modified by DeepCover',
|
114
|
+
content,
|
115
|
+
"gem 'deep-cover', path: '#{File.expand_path(__dir__ + '/../../../')}'",
|
116
|
+
'',
|
117
|
+
].join("\n"))
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
119
121
|
def patch_rubocop
|
120
122
|
path = @dest_root.join('.rubocop.yml')
|
121
123
|
return unless path.exist?
|
122
|
-
puts
|
123
|
-
config = YAML.
|
124
|
+
puts 'Patching .rubocop.yml'
|
125
|
+
config = YAML.safe_load(path.read.gsub(/(?<!\w)lib(?!\w)/, 'lib_original'))
|
124
126
|
((config['AllCops'] ||= {})['Exclude'] ||= []) << 'lib/**/*' << 'app/**/*'
|
125
127
|
path.write("# This file was modified by DeepCover\n" + YAML.dump(config))
|
126
128
|
end
|
@@ -137,8 +139,8 @@ module DeepCover
|
|
137
139
|
original = to_cover.sub_ext('_original')
|
138
140
|
FileUtils.cp_r(to_cover, original)
|
139
141
|
Tools.dump_covered_code(original,
|
140
|
-
|
141
|
-
|
142
|
+
coverage: coverage, root_path: @dest_root.to_s,
|
143
|
+
dest_path: to_cover)
|
142
144
|
end
|
143
145
|
coverage.save(@dest_root.to_s)
|
144
146
|
end
|
@@ -155,7 +157,7 @@ module DeepCover
|
|
155
157
|
end
|
156
158
|
|
157
159
|
def bundle
|
158
|
-
puts
|
160
|
+
puts 'Running `bundle install`'
|
159
161
|
Bundler.with_clean_env do
|
160
162
|
`cd #{@dest_root} && bundle`
|
161
163
|
end
|
data/lib/deep_cover/config.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DeepCover
|
2
4
|
class Config
|
3
5
|
DEFAULTS = {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
ignore_uncovered: [],
|
7
|
+
paths: %w[./app ./lib],
|
8
|
+
allow_partial: false,
|
9
|
+
}.freeze
|
8
10
|
|
9
|
-
def initialize(**options)
|
11
|
+
def initialize(notify = nil, **options)
|
12
|
+
@notify = notify
|
10
13
|
@options = copy(DEFAULTS.merge(options))
|
11
14
|
end
|
12
15
|
|
@@ -17,38 +20,48 @@ module DeepCover
|
|
17
20
|
|
18
21
|
def ignore_uncovered(*keywords)
|
19
22
|
check_uncovered(keywords)
|
20
|
-
@options[:ignore_uncovered]
|
21
|
-
self
|
23
|
+
change(:ignore_uncovered, @options[:ignore_uncovered] | keywords)
|
22
24
|
end
|
23
25
|
|
24
26
|
def detect_uncovered(*keywords)
|
25
27
|
check_uncovered(keywords)
|
26
|
-
@options[:ignore_uncovered]
|
27
|
-
self
|
28
|
+
change(:ignore_uncovered, @options[:ignore_uncovered] - keywords)
|
28
29
|
end
|
29
30
|
|
30
|
-
def paths(paths)
|
31
|
-
|
32
|
-
|
31
|
+
def paths(paths = nil)
|
32
|
+
if paths
|
33
|
+
change(:paths, Array(paths).dup.freeze)
|
34
|
+
else
|
35
|
+
@options[:paths]
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
private
|
40
|
+
|
36
41
|
def check_uncovered(keywords)
|
37
42
|
unknown = keywords - Analyser.optionally_covered
|
38
43
|
raise ArgumentError, "unknown options: #{unknown.join(', ')}" unless unknown.empty?
|
39
44
|
end
|
40
45
|
|
46
|
+
def change(option, value)
|
47
|
+
if @options[option] != value
|
48
|
+
@options[option] = value
|
49
|
+
@notify.config_changed(option) if @notify.respond_to? :config_changed
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
41
54
|
def copy(h)
|
42
|
-
h.dup.transform_values(&:dup)
|
55
|
+
h.dup.transform_values(&:dup).transform_values(&:freeze)
|
43
56
|
end
|
44
57
|
|
45
58
|
module Setter
|
46
|
-
def config
|
47
|
-
@config ||= Config.new
|
59
|
+
def config(notify = self)
|
60
|
+
@config ||= Config.new(notify)
|
48
61
|
end
|
49
62
|
|
50
63
|
def configure(&block)
|
51
|
-
raise
|
64
|
+
raise 'Must provide a block' unless block
|
52
65
|
case block.arity
|
53
66
|
when 0
|
54
67
|
config.instance_eval(&block)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# These are the monkeypatches to replace the default #load in order
|
2
4
|
# to instrument the code before it gets run.
|
3
5
|
# For now, this is not used, and may never be. The tracking and reporting for things can might be
|
@@ -8,12 +10,9 @@ module DeepCover
|
|
8
10
|
def load(path, wrap = false)
|
9
11
|
return load_without_deep_cover(path, wrap) if wrap
|
10
12
|
|
11
|
-
result = DeepCover.custom_requirer.load(path)
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
result
|
16
|
-
end
|
13
|
+
result = catch(:use_fallback) { DeepCover.custom_requirer.load(path) }
|
14
|
+
result = load_without_deep_cover(path) if result.is_a? Symbol
|
15
|
+
result
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# These are the monkeypatches to replace the default #require and
|
2
4
|
# #require_relative in order to instrument the code before it gets run.
|
3
5
|
# Kernel.require and Kernel#require must both have their version because
|
@@ -7,17 +9,14 @@
|
|
7
9
|
module DeepCover
|
8
10
|
module RequireOverride
|
9
11
|
def require(path)
|
10
|
-
result = DeepCover.custom_requirer.require(path)
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
result
|
15
|
-
end
|
12
|
+
result = catch(:use_fallback) { DeepCover.custom_requirer.require(path) }
|
13
|
+
result = require_without_deep_cover(path) if result.is_a? Symbol
|
14
|
+
result
|
16
15
|
end
|
17
16
|
|
18
17
|
def require_relative(path)
|
19
18
|
base = caller(1..1).first[/[^:]+/]
|
20
|
-
raise LoadError,
|
19
|
+
raise LoadError, 'cannot infer basepath' unless base
|
21
20
|
base = File.dirname(base)
|
22
21
|
|
23
22
|
require(File.absolute_path(path, base))
|
data/lib/deep_cover/coverage.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DeepCover
|
2
4
|
require 'parser'
|
3
5
|
silence_warnings do
|
@@ -34,7 +36,7 @@ module DeepCover
|
|
34
36
|
|
35
37
|
def each
|
36
38
|
return to_enum unless block_given?
|
37
|
-
@covered_codes.
|
39
|
+
@covered_codes.each_value { |covered_code| yield covered_code }
|
38
40
|
self
|
39
41
|
end
|
40
42
|
|
@@ -45,7 +47,7 @@ module DeepCover
|
|
45
47
|
end.inject(:merge)
|
46
48
|
end
|
47
49
|
|
48
|
-
def output_istanbul(dir: '.', name:
|
50
|
+
def output_istanbul(dir: '.', name: '.nyc_output', **options)
|
49
51
|
path = Pathname.new(dir).expand_path.join(name)
|
50
52
|
path.mkpath
|
51
53
|
path.each_child(&:delete)
|
@@ -82,7 +84,7 @@ module DeepCover
|
|
82
84
|
if Reporter::Istanbul.available?
|
83
85
|
report_istanbul(**options)
|
84
86
|
else
|
85
|
-
warn
|
87
|
+
warn 'nyc not available. Please install `nyc` using `yarn global add nyc` or `npm i nyc -g`'
|
86
88
|
basic_report
|
87
89
|
end
|
88
90
|
end
|
@@ -110,6 +112,7 @@ module DeepCover
|
|
110
112
|
end
|
111
113
|
|
112
114
|
class Persistence
|
115
|
+
# rubocop:disable Security/MarshalLoad
|
113
116
|
BASENAME = 'coverage.dc'
|
114
117
|
TRACKER_TEMPLATE = 'trackers%{unique}.dct'
|
115
118
|
|
@@ -132,16 +135,16 @@ module DeepCover
|
|
132
135
|
|
133
136
|
def save_trackers(global)
|
134
137
|
saved?
|
135
|
-
trackers = eval(global)
|
138
|
+
trackers = eval(global) # rubocop:disable Security/Eval
|
136
139
|
# Some testing involves more than one process, some of which don't run any of our covered code.
|
137
140
|
# Don't save anything if that's the case
|
138
141
|
return if trackers.nil?
|
139
|
-
basename = TRACKER_TEMPLATE
|
140
|
-
dir_path.join(basename).binwrite(Marshal.dump(
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
142
|
+
basename = format(TRACKER_TEMPLATE, unique: SecureRandom.urlsafe_base64)
|
143
|
+
dir_path.join(basename).binwrite(Marshal.dump(
|
144
|
+
version: DeepCover::VERSION,
|
145
|
+
global: global,
|
146
|
+
trackers: trackers,
|
147
|
+
))
|
145
148
|
end
|
146
149
|
|
147
150
|
def saved?
|
@@ -156,10 +159,10 @@ module DeepCover
|
|
156
159
|
end
|
157
160
|
|
158
161
|
def save_coverage(coverage)
|
159
|
-
dir_path.join(BASENAME).binwrite(Marshal.dump(
|
160
|
-
|
161
|
-
|
162
|
-
|
162
|
+
dir_path.join(BASENAME).binwrite(Marshal.dump(
|
163
|
+
version: DeepCover::VERSION,
|
164
|
+
coverage: coverage,
|
165
|
+
))
|
163
166
|
end
|
164
167
|
|
165
168
|
def load_coverage
|
@@ -173,22 +176,22 @@ module DeepCover
|
|
173
176
|
tracker_files.each do |full_path|
|
174
177
|
Marshal.load(full_path.binread).tap do |version: raise, global: raise, trackers: raise|
|
175
178
|
raise "dump version mismatch: #{version}, currently #{DeepCover::VERSION}" unless version == DeepCover::VERSION
|
176
|
-
merge_trackers(eval("#{global} ||= {}"), trackers)
|
179
|
+
merge_trackers(eval("#{global} ||= {}"), trackers) # rubocop:disable Security/Eval
|
177
180
|
end
|
178
181
|
end
|
179
182
|
end
|
180
183
|
|
181
184
|
def merge_trackers(hash, to_merge)
|
182
185
|
hash.merge!(to_merge) do |_key, current, to_add|
|
183
|
-
unless current.
|
186
|
+
unless current.empty? || current.size == to_add.size
|
184
187
|
warn "Merging trackers of different sizes: #{current.size} vs #{to_add.size}"
|
185
188
|
end
|
186
|
-
to_add.zip(current).map{|a, b| a+b}
|
189
|
+
to_add.zip(current).map { |a, b| a + b }
|
187
190
|
end
|
188
191
|
end
|
189
192
|
|
190
193
|
def tracker_files
|
191
|
-
basename = TRACKER_TEMPLATE
|
194
|
+
basename = format(TRACKER_TEMPLATE, unique: '*')
|
192
195
|
Pathname.glob(dir_path.join(basename))
|
193
196
|
end
|
194
197
|
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DeepCover
|
2
4
|
class CoveredCode
|
3
5
|
DEFAULT_TRACKER_GLOBAL = '$_cov'
|
4
6
|
|
5
7
|
attr_accessor :covered_source, :buffer, :tracker_global, :local_var, :name
|
6
8
|
@@counter = 0
|
7
|
-
@@globals = Hash.new{|h, global| h[global] = eval("#{global} ||= {}") }
|
9
|
+
@@globals = Hash.new { |h, global| h[global] = eval("#{global} ||= {}") } # rubocop:disable Security/Eval
|
8
10
|
|
9
11
|
def initialize(path: nil, source: nil, lineno: 1, tracker_global: DEFAULT_TRACKER_GLOBAL, local_var: '_temp', name: nil)
|
10
|
-
raise
|
12
|
+
raise 'Must provide either path or source' unless path || source
|
11
13
|
|
12
14
|
@buffer = ::Parser::Source::Buffer.new(path, lineno)
|
13
15
|
@buffer.source = source ||= File.read(path)
|
@@ -27,20 +29,18 @@ module DeepCover
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def nb_lines
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
lines.size - (lines.last.empty? ? 1 : 0)
|
36
|
-
end
|
32
|
+
lines = buffer.source_lines
|
33
|
+
if lines.empty?
|
34
|
+
0
|
35
|
+
else
|
36
|
+
lines.size - (lines.last.empty? ? 1 : 0)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
def execute_code(binding: DeepCover::GLOBAL_BINDING.dup)
|
41
41
|
return if has_executed?
|
42
42
|
global[nb] = Array.new(@tracker_count, 0)
|
43
|
-
eval(@covered_source, binding, @buffer.name || '<raw_code>', lineno)
|
43
|
+
eval(@covered_source, binding, @buffer.name || '<raw_code>', lineno) # rubocop:disable Security/Eval
|
44
44
|
self
|
45
45
|
end
|
46
46
|
|
@@ -71,7 +71,7 @@ module DeepCover
|
|
71
71
|
# Returns a range of tracker ids
|
72
72
|
def allocate_trackers(nb_needed)
|
73
73
|
prev = @tracker_count
|
74
|
-
@tracker_count += nb_needed
|
74
|
+
@tracker_count += nb_needed if nb_needed > 0 # Avoid error if frozen and called with 0.
|
75
75
|
prev...@tracker_count
|
76
76
|
end
|
77
77
|
|
@@ -109,7 +109,7 @@ module DeepCover
|
|
109
109
|
prefix, _node, suffix = rule.partition('%{node}')
|
110
110
|
unless prefix.empty?
|
111
111
|
prefix = yield prefix, node, range.begin, :prefix if block_given?
|
112
|
-
rewriter.insert_before_multi range, prefix
|
112
|
+
rewriter.insert_before_multi range, prefix
|
113
113
|
end
|
114
114
|
unless suffix.empty?
|
115
115
|
suffix = yield suffix, node, range.end, :suffix if block_given?
|
@@ -124,7 +124,17 @@ module DeepCover
|
|
124
124
|
global[nb] != nil
|
125
125
|
end
|
126
126
|
|
127
|
+
def freeze
|
128
|
+
unless frozen? # Guard against reentrance
|
129
|
+
must_have_executed
|
130
|
+
super
|
131
|
+
root.each_node(&:freeze)
|
132
|
+
end
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
127
136
|
protected
|
137
|
+
|
128
138
|
def global
|
129
139
|
@@globals[tracker_global]
|
130
140
|
end
|