deep-cover 0.1.14 → 0.1.15
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/.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
|