deep-cover 0.6.4 → 0.7.0
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/.deep_cover.rb +5 -0
- data/.gitignore +7 -4
- data/.rubocop.yml +7 -0
- data/CHANGELOG.md +27 -0
- data/Gemfile +5 -1
- data/README.md +47 -53
- data/Rakefile +20 -15
- data/deep_cover.gemspec +2 -3
- data/exe/deep-cover +2 -4
- data/lib/deep_cover/cli.rb +85 -0
- data/lib/deep_cover/cli/commands/clear.rb +10 -0
- data/lib/deep_cover/cli/commands/clone.rb +22 -0
- data/lib/deep_cover/cli/commands/exec.rb +37 -0
- data/lib/deep_cover/cli/commands/gather.rb +36 -0
- data/lib/deep_cover/cli/commands/help.rb +34 -0
- data/lib/deep_cover/cli/commands/merge.rb +10 -0
- data/lib/deep_cover/cli/commands/report.rb +14 -0
- data/lib/deep_cover/cli/commands/run_expression.rb +13 -0
- data/lib/deep_cover/cli/commands/short_help.rb +26 -0
- data/lib/deep_cover/cli/commands/version.rb +15 -0
- data/lib/deep_cover/cli/tools.rb +18 -0
- data/lib/deep_cover/cover_cloned_tree.rb +58 -0
- data/lib/deep_cover/expression_debugger.rb +122 -0
- data/lib/deep_cover/instrumented_clone_reporter.rb +127 -0
- metadata +22 -33
- data/bin/console +0 -14
- data/bin/cov +0 -43
- data/bin/setup +0 -8
- data/bin/test_gems +0 -54
- data/bin/testall +0 -88
- data/future_read_me.md +0 -108
- data/lib/deep_cover/cli/debugger.rb +0 -127
- data/lib/deep_cover/cli/exec.rb +0 -27
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +0 -197
- data/lib/deep_cover/cli/runner.rb +0 -126
- data/lib/deep_cover/dump_covered_code.rb +0 -36
- data/lib/deep_cover_entry.rb +0 -3
data/lib/deep_cover/cli/exec.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
module CLI
|
5
|
-
class Exec
|
6
|
-
class Option
|
7
|
-
def keep_file_descriptors?
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize(argv, **options)
|
12
|
-
@argv = argv
|
13
|
-
@options = options
|
14
|
-
end
|
15
|
-
|
16
|
-
def run
|
17
|
-
require 'yaml'
|
18
|
-
require 'deep_cover/backports'
|
19
|
-
env_var = {'DEEP_COVER' => 't',
|
20
|
-
'DEEP_COVER_OPTIONS' => YAML.dump(@options.slice(*DEFAULTS.keys)),
|
21
|
-
}
|
22
|
-
|
23
|
-
system(env_var, *@argv)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,197 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'tmpdir'
|
4
|
-
|
5
|
-
module DeepCover
|
6
|
-
require 'deep-cover'
|
7
|
-
require_relative '../dump_covered_code'
|
8
|
-
bootstrap
|
9
|
-
|
10
|
-
module CLI
|
11
|
-
class InstrumentedCloneReporter
|
12
|
-
include Tools
|
13
|
-
# matches regular files, .files, ..files, but not '.' or '..'
|
14
|
-
GLOB_ALL_CONTENT = '{,.[^.],..?}*'
|
15
|
-
|
16
|
-
def initialize(source_path, **options)
|
17
|
-
@options = CLI_DEFAULTS.merge(options)
|
18
|
-
@root_path = @source_path = Pathname.new(source_path).expand_path
|
19
|
-
unless @root_path.join('Gemfile').exist?
|
20
|
-
# E.g. rails/activesupport
|
21
|
-
@root_path = @root_path.dirname
|
22
|
-
raise "Can't find Gemfile in #{@root_path}" unless @root_path.join('Gemfile').exist?
|
23
|
-
end
|
24
|
-
path = Pathname('~/test_deep_cover').expand_path
|
25
|
-
if path.exist?
|
26
|
-
@dest_root = path.join(@source_path.basename)
|
27
|
-
@dest_root.mkpath
|
28
|
-
else
|
29
|
-
@dest_root = Pathname.new(Dir.mktmpdir('deep_cover_test'))
|
30
|
-
end
|
31
|
-
|
32
|
-
gem_relative_path = @source_path.relative_path_from(@root_path)
|
33
|
-
@main_path = @dest_root.join(gem_relative_path)
|
34
|
-
singleton_class.include self.class.const_get(Tools.camelize(style))
|
35
|
-
end
|
36
|
-
|
37
|
-
def clear
|
38
|
-
FileUtils.rm_rf(Dir.glob("#{@dest_root}/#{GLOB_ALL_CONTENT}"))
|
39
|
-
end
|
40
|
-
|
41
|
-
def copy
|
42
|
-
return true if @copied
|
43
|
-
puts 'Cloning...'
|
44
|
-
FileUtils.cp_r(Dir.glob("#{@root_path}/#{GLOB_ALL_CONTENT}"), @dest_root)
|
45
|
-
@copied = true
|
46
|
-
end
|
47
|
-
|
48
|
-
def patch_ruby_file(ruby_file)
|
49
|
-
content = ruby_file.read
|
50
|
-
# Insert our code after leading comments:
|
51
|
-
content.sub!(/^(#.*\n+)*/) { |header| "#{header}require 'deep_cover/auto_run';DeepCover::AutoRun.run! '#{@dest_root}';" }
|
52
|
-
ruby_file.write(content)
|
53
|
-
end
|
54
|
-
|
55
|
-
def style
|
56
|
-
if @source_path.join('config/environments/test.rb').exist?
|
57
|
-
:rails
|
58
|
-
elsif @source_path.join('lib').exist?
|
59
|
-
:single_gem
|
60
|
-
else # Rails style
|
61
|
-
:gem_collection
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Style specific functionality
|
66
|
-
module Gem
|
67
|
-
def each_main_ruby_files(&block)
|
68
|
-
each_gem_path do |dest_path|
|
69
|
-
main = dest_path.join('lib/*.rb')
|
70
|
-
Pathname.glob(main).select(&:file?).each(&block)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def each_dir_to_cover
|
75
|
-
each_gem_path do |dest_path|
|
76
|
-
yield dest_path.join('lib')
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
module SingleGem
|
82
|
-
include Gem
|
83
|
-
def each_gem_path
|
84
|
-
yield @main_path
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
module GemCollection
|
89
|
-
include Gem
|
90
|
-
def each_gem_path
|
91
|
-
Pathname.glob(@main_path.join('*/lib')).each { |p| yield p.dirname }
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
module Rails
|
96
|
-
def each_main_ruby_files
|
97
|
-
yield @main_path.join('config/environments/test.rb')
|
98
|
-
end
|
99
|
-
|
100
|
-
def each_dir_to_cover
|
101
|
-
yield @main_path.join('app')
|
102
|
-
yield @main_path.join('lib')
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Back to global functionality
|
107
|
-
def patch_main_ruby_files
|
108
|
-
each_main_ruby_files do |main|
|
109
|
-
puts "Patching #{main}"
|
110
|
-
patch_ruby_file(main)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def patch_gemfile
|
115
|
-
gemfile = @dest_root.join('Gemfile')
|
116
|
-
require 'bundler'
|
117
|
-
deps = Bundler::Definition.build(gemfile, nil, nil).dependencies
|
118
|
-
|
119
|
-
return if deps.find { |e| e.name.start_with? 'deep-cover' }
|
120
|
-
|
121
|
-
content = File.read(gemfile)
|
122
|
-
puts "Patching Gemfile #{gemfile}"
|
123
|
-
File.write(gemfile, [
|
124
|
-
'# This file was modified by DeepCover',
|
125
|
-
content,
|
126
|
-
"gem 'deep-cover', path: '#{File.expand_path(__dir__ + '/../../../')}'",
|
127
|
-
"gem 'deep-cover-core', path: '#{File.expand_path(__dir__ + '/../../../core_gem')}'",
|
128
|
-
'',
|
129
|
-
].join("\n"))
|
130
|
-
end
|
131
|
-
|
132
|
-
def patch_rubocop
|
133
|
-
path = @dest_root.join('.rubocop.yml')
|
134
|
-
return unless path.exist?
|
135
|
-
puts 'Patching .rubocop.yml'
|
136
|
-
config = YAML.load(path.read.gsub(/(?<!\w)lib(?!\w)/, 'lib_original'))
|
137
|
-
((config['AllCops'] ||= {})['Exclude'] ||= []) << 'lib/**/*' << 'app/**/*'
|
138
|
-
path.write("# This file was modified by DeepCover\n" + YAML.dump(config))
|
139
|
-
end
|
140
|
-
|
141
|
-
def patch
|
142
|
-
patch_gemfile
|
143
|
-
patch_rubocop
|
144
|
-
patch_main_ruby_files
|
145
|
-
end
|
146
|
-
|
147
|
-
def cover
|
148
|
-
coverage = Coverage.new(tracker_global: ::DeepCover.config.tracker_global)
|
149
|
-
each_dir_to_cover do |to_cover|
|
150
|
-
FileUtils.cp_r(to_cover, to_cover.sub_ext('_original'))
|
151
|
-
Tools.dump_covered_code(to_cover,
|
152
|
-
coverage: coverage,
|
153
|
-
dest_path: to_cover)
|
154
|
-
end
|
155
|
-
coverage.save(@dest_root.to_s)
|
156
|
-
end
|
157
|
-
|
158
|
-
def process
|
159
|
-
Bundler.with_clean_env do
|
160
|
-
system({'DISABLE_SPRING' => 'true'}, "cd #{@main_path} && #{@options[:command]}")
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def restore
|
165
|
-
each_dir_to_cover do |to_cover|
|
166
|
-
FileUtils.mv(to_cover, to_cover.sub_ext('_instrumented'))
|
167
|
-
FileUtils.mv(to_cover.sub_ext('_original'), to_cover)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def report
|
172
|
-
coverage = Coverage.load @dest_root.to_s
|
173
|
-
puts coverage.report(dir: @dest_root.to_s, **@options)
|
174
|
-
end
|
175
|
-
|
176
|
-
def bundle
|
177
|
-
puts 'Running `bundle install`'
|
178
|
-
Bundler.with_clean_env do
|
179
|
-
`cd #{@dest_root} && bundle`
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def run
|
184
|
-
if @options[:process]
|
185
|
-
clear
|
186
|
-
copy
|
187
|
-
cover
|
188
|
-
patch
|
189
|
-
bundle if @options[:bundle]
|
190
|
-
process
|
191
|
-
restore
|
192
|
-
end
|
193
|
-
report
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
require 'slop'
|
5
|
-
require 'deep-cover'
|
6
|
-
bootstrap
|
7
|
-
|
8
|
-
module CLI
|
9
|
-
module SlopExtension
|
10
|
-
attr_accessor :stopped
|
11
|
-
attr_reader :ignored
|
12
|
-
|
13
|
-
def try_process(*)
|
14
|
-
@ignored ||= 0
|
15
|
-
return if stopped
|
16
|
-
o = super
|
17
|
-
@ignored += 1 unless o
|
18
|
-
o
|
19
|
-
end
|
20
|
-
end
|
21
|
-
::Slop::Parser.prepend SlopExtension
|
22
|
-
|
23
|
-
module Runner
|
24
|
-
extend self
|
25
|
-
|
26
|
-
def show_version
|
27
|
-
require 'deep_cover/version'
|
28
|
-
require 'parser'
|
29
|
-
puts "deep-cover v#{DeepCover::VERSION}; parser v#{Parser::VERSION}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def show_help
|
33
|
-
puts menu
|
34
|
-
end
|
35
|
-
|
36
|
-
class OptionParser < Struct.new(:delegate)
|
37
|
-
def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissing
|
38
|
-
options = args.last
|
39
|
-
if options.is_a?(Hash) && options.has_key?(:default)
|
40
|
-
args[-2] += " [#{options[:default]}]"
|
41
|
-
end
|
42
|
-
delegate.public_send(method, *args, &block)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse
|
47
|
-
Slop.parse do |o|
|
48
|
-
yield OptionParser.new(o)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def menu
|
53
|
-
@menu ||= parse do |o|
|
54
|
-
o.banner = ['usage: deep-cover [options] exec <command ...>',
|
55
|
-
' or deep-cover [options] [path/to/app/or/gem]',
|
56
|
-
].join("\n")
|
57
|
-
o.separator ''
|
58
|
-
o.string '-o', '--output', 'output folder', default: DeepCover.config.output
|
59
|
-
o.string '--reporter', 'reporter', default: DeepCover.config.reporter
|
60
|
-
o.bool '--open', 'open the output coverage', default: CLI_DEFAULTS[:open]
|
61
|
-
|
62
|
-
o.separator 'Coverage options'
|
63
|
-
@ignore_uncovered_map = OPTIONALLY_COVERED.map do |option|
|
64
|
-
default = DeepCover.config.ignore_uncovered.include?(option)
|
65
|
-
o.bool "--ignore-#{dasherize(option)}", '', default: default
|
66
|
-
[:"ignore_#{option}", option]
|
67
|
-
end.to_h
|
68
|
-
|
69
|
-
o.separator "\nWhen not using ’exec’:"
|
70
|
-
o.string '-c', '--command', 'command to run tests', default: CLI_DEFAULTS[:command]
|
71
|
-
o.bool '--bundle', 'run bundle before the tests', default: CLI_DEFAULTS[:bundle]
|
72
|
-
o.bool '--process', 'turn off to only redo the reporting', default: CLI_DEFAULTS[:process]
|
73
|
-
|
74
|
-
o.separator "\nFor testing purposes:"
|
75
|
-
o.bool '--profile', 'use profiler' unless RUBY_PLATFORM == 'java'
|
76
|
-
o.string '-e', '--expression', 'test ruby expression instead of a covering a path'
|
77
|
-
o.bool '-d', '--debug', 'enter debugging after cover'
|
78
|
-
|
79
|
-
o.separator "\nOther available commands:"
|
80
|
-
o.on('--version', 'print the version') do
|
81
|
-
show_version
|
82
|
-
exit
|
83
|
-
end
|
84
|
-
o.boolean('-h', '--help')
|
85
|
-
|
86
|
-
o.boolean('exec', '', help: false) do
|
87
|
-
o.parser.stopped = true if o.parser.ignored == 0
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def convert_options(options)
|
93
|
-
iu = options[:ignore_uncovered] = []
|
94
|
-
@ignore_uncovered_map.each do |cli_option, option|
|
95
|
-
iu << option if options.delete(cli_option)
|
96
|
-
end
|
97
|
-
options[:output] = false if ['false', 'f', ''].include?(options[:output])
|
98
|
-
options
|
99
|
-
end
|
100
|
-
|
101
|
-
def go
|
102
|
-
options = convert_options(menu.to_h)
|
103
|
-
if options[:help]
|
104
|
-
show_help
|
105
|
-
elsif options[:expression]
|
106
|
-
require_relative 'debugger'
|
107
|
-
Debugger.new(options[:expression], **options).show
|
108
|
-
elsif menu.parser.stopped
|
109
|
-
require_relative 'exec'
|
110
|
-
Exec.new(menu.arguments, **options).run
|
111
|
-
else
|
112
|
-
require_relative 'instrumented_clone_reporter'
|
113
|
-
path = menu.arguments.first || '.'
|
114
|
-
InstrumentedCloneReporter.new(path, **options).run
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
# Poor man's dasherize. 'an_example' => 'an-example'
|
121
|
-
def dasherize(string)
|
122
|
-
string.to_s.tr('_', '-')
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
silence_warnings do
|
5
|
-
require 'with_progress'
|
6
|
-
end
|
7
|
-
module Tools::DumpCoveredCode
|
8
|
-
def dump_covered_code(source_path, coverage:, dest_path: Dir.mktmpdir)
|
9
|
-
source_path = File.join(File.expand_path(source_path), '')
|
10
|
-
dest_path = File.join(File.expand_path(dest_path), '')
|
11
|
-
skipped = []
|
12
|
-
file_paths = Dir.glob("#{source_path}**/*.rb").select { |p| File.file?(p) }
|
13
|
-
file_paths.each.with_progress(title: 'Rewriting') do |path|
|
14
|
-
new_path = Pathname(path.gsub(source_path, dest_path))
|
15
|
-
begin
|
16
|
-
covered_code = coverage.covered_code(path)
|
17
|
-
rescue Parser::SyntaxError
|
18
|
-
skipped << path
|
19
|
-
next
|
20
|
-
end
|
21
|
-
new_path.dirname.mkpath
|
22
|
-
new_path.write(covered_code.covered_source)
|
23
|
-
end
|
24
|
-
unless skipped.empty?
|
25
|
-
warn [
|
26
|
-
"#{skipped.size} files could not be instrumented because of syntax errors:",
|
27
|
-
*skipped.first(3),
|
28
|
-
('...' if skipped.size > 3),
|
29
|
-
].compact.join("\n")
|
30
|
-
end
|
31
|
-
dest_path
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
Tools.extend Tools::DumpCoveredCode
|
36
|
-
end
|
data/lib/deep_cover_entry.rb
DELETED