deep-cover 0.1.13 → 0.1.14
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/Rakefile +1 -0
- data/bin/test_gems +2 -1
- data/bin/testall +0 -1
- data/lib/deep_cover.rb +2 -0
- data/lib/deep_cover/analyser/base.rb +7 -1
- data/lib/deep_cover/analyser/per_char.rb +1 -1
- data/lib/deep_cover/analyser/per_line.rb +1 -1
- data/lib/deep_cover/cli/debugger.rb +0 -2
- data/lib/deep_cover/cli/deep_cover.rb +2 -1
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +74 -25
- data/lib/deep_cover/coverage.rb +5 -2
- data/lib/deep_cover/covered_code.rb +7 -4
- data/lib/deep_cover/node/base.rb +31 -3
- data/lib/deep_cover/node/mixin/execution_location.rb +4 -0
- data/lib/deep_cover/node/mixin/flow_accounting.rb +5 -0
- data/lib/deep_cover/node/send.rb +11 -2
- data/lib/deep_cover/problem_with_diagnostic.rb +61 -0
- data/lib/deep_cover/tools/number_lines.rb +2 -0
- data/lib/deep_cover/tools/our_coverage.rb +1 -1
- data/lib/deep_cover/tools/truncate_backtrace.rb +30 -0
- data/lib/deep_cover/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6de45ce3979398ef5abb25a8147848ad13fa370
|
4
|
+
data.tar.gz: 74dfa0b7b03271419f0b2c7094e124b447392c46
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a455c059204f7eeb91f57ca3d4453a7a79021ece85e3228b4a312034dcaef7d022f0776dc9179bcb1dc44049971ba5248fcdc94badcacc6ab1c08bbd9da195e
|
7
|
+
data.tar.gz: 8c6ec4f7204c95968a329d1ae3896cf9c0e41c68973883add1beca6d1efdcdba353e09ff11dfa97651488a75e2cb4f6dd7cc70d5f23159b21efaba6e967233e4
|
data/Rakefile
CHANGED
@@ -14,6 +14,7 @@ namespace :dev do
|
|
14
14
|
if RUBY_VERSION >= '2.2.2' && (!defined?(RUBY_ENGINE) || RUBY_ENGINE != 'jruby')
|
15
15
|
commands << 'bundle install --gemfile=spec/full_usage/rails51_project/Gemfile'
|
16
16
|
end
|
17
|
+
commands << 'bundle install --gemfile=spec/cli_fixtures/simple_rails42_app/Gemfile'
|
17
18
|
|
18
19
|
commands.each do |command|
|
19
20
|
puts "Running: #{command}"
|
data/bin/test_gems
CHANGED
@@ -8,7 +8,8 @@ def gem_list
|
|
8
8
|
rspec-support thread_safe rspec-core rspec-expectations rspec-mocks rspec mini_portile
|
9
9
|
multi_json rspec-support rspec-expectations rspec-mocks mail nokogiri rack rspec unf
|
10
10
|
json thread_safe rspec-core json rack-protection sdoc docile faraday multi_xml coderay
|
11
|
-
mime-types net-scp multi_json turbolinks formatador coffee-script rack-test]
|
11
|
+
mime-types net-scp multi_json turbolinks formatador coffee-script rack-test] +
|
12
|
+
%w[devise]
|
12
13
|
# How I got those:
|
13
14
|
require 'gems'
|
14
15
|
Gems.most_downloaded
|
data/bin/testall
CHANGED
data/lib/deep_cover.rb
CHANGED
@@ -33,7 +33,13 @@ module DeepCover
|
|
33
33
|
def each_node(from = covered_code.root, &block)
|
34
34
|
return to_enum(:each_node) unless block_given?
|
35
35
|
children = node_children(from)
|
36
|
-
|
36
|
+
begin
|
37
|
+
yield from, children unless from.is_a?(Node::Root)
|
38
|
+
rescue ProblemWithDiagnostic
|
39
|
+
raise
|
40
|
+
rescue StandardError, SystemStackError => e
|
41
|
+
raise ProblemWithDiagnostic.new(covered_code, from.diagnostic_expression, e)
|
42
|
+
end
|
37
43
|
children.each do |child|
|
38
44
|
each_node(child, &block)
|
39
45
|
end
|
@@ -9,7 +9,7 @@ module DeepCover
|
|
9
9
|
runs = node_runs(node)
|
10
10
|
if runs != nil
|
11
11
|
node.proper_range.each do |pos|
|
12
|
-
bc[buffer.line_for_position(pos)-
|
12
|
+
bc[buffer.line_for_position(pos)-buffer.first_line][buffer.column_for_position(pos)] = runs > 0 ? ' ' : 'x'
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -3,7 +3,7 @@ module DeepCover
|
|
3
3
|
# Returns an array of runs, one per line.
|
4
4
|
def results
|
5
5
|
disallow_partial = !options.fetch(:allow_partial, true)
|
6
|
-
line_hits = Array.new(covered_code.nb_lines)
|
6
|
+
line_hits = Array.new(covered_code.nb_lines + covered_code.lineno - 1)
|
7
7
|
each_node do |node, _children|
|
8
8
|
if (runs = node_runs(node))
|
9
9
|
node.executed_locs.each do |loc|
|
@@ -37,8 +37,9 @@ module DeepCover
|
|
37
37
|
o.banner = "usage: deep-cover [options] [path/to/app/or/gem]"
|
38
38
|
o.separator ''
|
39
39
|
o.string '-o', '--output', 'output folder', default: './coverage'
|
40
|
-
o.string '-c', '--command', 'command to run tests', default: 'rake'
|
40
|
+
o.string '-c', '--command', 'command to run tests', default: 'bundle exec rake'
|
41
41
|
o.bool '--bundle', 'run bundle before the tests', default: true
|
42
|
+
o.bool '--process', 'turn off to only redo the reporting', default: true
|
42
43
|
o.separator 'Coverage options'
|
43
44
|
@ignore_uncovered_map = Analyser.optionally_covered.map do |option|
|
44
45
|
default = Config::DEFAULTS[:ignore_uncovered].include?(option)
|
@@ -8,10 +8,10 @@ module DeepCover
|
|
8
8
|
# matches regular files, .files, ..files, but not '.' or '..'
|
9
9
|
GLOB_ALL_CONTENT = '{,.[^.],..?}*'
|
10
10
|
|
11
|
-
def initialize(
|
11
|
+
def initialize(source_path, command: 'rake', **options)
|
12
12
|
@command = command
|
13
13
|
@options = options
|
14
|
-
@root_path =
|
14
|
+
@root_path = @source_path = Pathname.new(source_path).expand_path
|
15
15
|
unless @root_path.join('Gemfile').exist?
|
16
16
|
# E.g. rails/activesupport
|
17
17
|
@root_path = @root_path.dirname
|
@@ -20,40 +20,85 @@ module DeepCover
|
|
20
20
|
@dest_root = Pathname('~/test_deep_cover').expand_path
|
21
21
|
@dest_root = Pathname.new(Dir.mktmpdir("deep_cover_test")) unless @dest_root.exist?
|
22
22
|
|
23
|
-
|
24
|
-
gem_relative_path = gem_path.relative_path_from(@root_path)
|
23
|
+
gem_relative_path = @source_path.relative_path_from(@root_path)
|
25
24
|
@main_path = @dest_root.join(gem_relative_path)
|
25
|
+
singleton_class.include self.class.const_get(Tools.camelize(style))
|
26
|
+
end
|
27
|
+
|
28
|
+
def clear
|
29
|
+
FileUtils.rm_rf(Dir.glob("#{@dest_root}/#{GLOB_ALL_CONTENT}"))
|
26
30
|
end
|
27
31
|
|
28
32
|
def copy
|
29
33
|
return true if @copied
|
34
|
+
puts "Cloning..."
|
30
35
|
FileUtils.cp_r(Dir.glob("#{@root_path}/#{GLOB_ALL_CONTENT}"), @dest_root)
|
31
36
|
@copied = true
|
32
37
|
end
|
33
38
|
|
34
39
|
def patch_ruby_file(ruby_file)
|
35
|
-
content =
|
40
|
+
content = ruby_file.read
|
36
41
|
# Insert our code after leading comments:
|
37
42
|
content.sub!(/^((#.*\n+)*)/, "#{$1}require 'deep_cover/auto_run';DeepCover::AutoRun.run! '#{@dest_root}';")
|
38
|
-
|
43
|
+
ruby_file.write(content)
|
39
44
|
end
|
40
45
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
46
|
+
def style
|
47
|
+
if @source_path.join('config/environments/test.rb').exist?
|
48
|
+
:rails
|
49
|
+
elsif @source_path.join('lib').exist?
|
50
|
+
:single_gem
|
45
51
|
else # Rails style
|
52
|
+
:gem_collection
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Style specific functionality
|
57
|
+
module Gem
|
58
|
+
def each_main_ruby_files(&block)
|
59
|
+
each_gem_path do |dest_path|
|
60
|
+
main = dest_path.join('lib/*.rb')
|
61
|
+
Pathname.glob(main).select(&:file?).each(&block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def each_dir_to_cover
|
66
|
+
each_gem_path do |dest_path|
|
67
|
+
yield dest_path.join('lib')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module SingleGem
|
73
|
+
include Gem
|
74
|
+
def each_gem_path
|
75
|
+
yield @main_path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module GemCollection
|
80
|
+
include Gem
|
81
|
+
def each_gem_path
|
46
82
|
Pathname.glob(@main_path.join('*/lib')).each{|p| yield p.dirname}
|
47
83
|
end
|
48
84
|
end
|
49
85
|
|
86
|
+
module Rails
|
87
|
+
def each_main_ruby_files
|
88
|
+
yield @main_path.join('config/environments/test.rb')
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_dir_to_cover
|
92
|
+
yield @main_path.join('app')
|
93
|
+
yield @main_path.join('lib')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Back to global functionality
|
50
98
|
def patch_main_ruby_files
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
puts "Patching #{main}"
|
55
|
-
patch_ruby_file(main)
|
56
|
-
end
|
99
|
+
each_main_ruby_files do |main|
|
100
|
+
puts "Patching #{main}"
|
101
|
+
patch_ruby_file(main)
|
57
102
|
end
|
58
103
|
end
|
59
104
|
|
@@ -88,11 +133,12 @@ module DeepCover
|
|
88
133
|
|
89
134
|
def cover
|
90
135
|
coverage = Coverage.new
|
91
|
-
|
92
|
-
|
93
|
-
|
136
|
+
each_dir_to_cover do |to_cover|
|
137
|
+
original = to_cover.sub_ext('_original')
|
138
|
+
FileUtils.cp_r(to_cover, original)
|
139
|
+
Tools.dump_covered_code(original,
|
94
140
|
coverage: coverage, root_path: @dest_root.to_s,
|
95
|
-
dest_path:
|
141
|
+
dest_path: to_cover)
|
96
142
|
end
|
97
143
|
coverage.save(@dest_root.to_s)
|
98
144
|
end
|
@@ -116,11 +162,14 @@ module DeepCover
|
|
116
162
|
end
|
117
163
|
|
118
164
|
def run
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
165
|
+
if @options.fetch(:process, true)
|
166
|
+
clear
|
167
|
+
copy
|
168
|
+
cover
|
169
|
+
patch
|
170
|
+
bundle if @options.fetch(:bundle, true)
|
171
|
+
process
|
172
|
+
end
|
124
173
|
report
|
125
174
|
end
|
126
175
|
end
|
data/lib/deep_cover/coverage.rb
CHANGED
@@ -3,7 +3,6 @@ module DeepCover
|
|
3
3
|
silence_warnings do
|
4
4
|
require 'parser/current'
|
5
5
|
end
|
6
|
-
require 'pry'
|
7
6
|
require_relative 'covered_code'
|
8
7
|
require 'securerandom'
|
9
8
|
|
@@ -133,11 +132,15 @@ module DeepCover
|
|
133
132
|
|
134
133
|
def save_trackers(global)
|
135
134
|
saved?
|
135
|
+
trackers = eval(global)
|
136
|
+
# Some testing involves more than one process, some of which don't run any of our covered code.
|
137
|
+
# Don't save anything if that's the case
|
138
|
+
return if trackers.nil?
|
136
139
|
basename = TRACKER_TEMPLATE % {unique: SecureRandom.urlsafe_base64}
|
137
140
|
dir_path.join(basename).binwrite(Marshal.dump({
|
138
141
|
version: DeepCover::VERSION,
|
139
142
|
global: global,
|
140
|
-
trackers:
|
143
|
+
trackers: trackers,
|
141
144
|
}))
|
142
145
|
end
|
143
146
|
|
@@ -6,12 +6,11 @@ module DeepCover
|
|
6
6
|
@@counter = 0
|
7
7
|
@@globals = Hash.new{|h, global| h[global] = eval("#{global} ||= {}") }
|
8
8
|
|
9
|
-
def initialize(path: nil, source: nil, lineno:
|
9
|
+
def initialize(path: nil, source: nil, lineno: 1, tracker_global: DEFAULT_TRACKER_GLOBAL, local_var: '_temp', name: nil)
|
10
10
|
raise "Must provide either path or source" unless path || source
|
11
11
|
|
12
|
-
@buffer = ::Parser::Source::Buffer.new(path)
|
12
|
+
@buffer = ::Parser::Source::Buffer.new(path, lineno)
|
13
13
|
@buffer.source = source ||= File.read(path)
|
14
|
-
@lineno = lineno
|
15
14
|
@tracker_count = 0
|
16
15
|
@tracker_global = tracker_global
|
17
16
|
@local_var = local_var
|
@@ -23,6 +22,10 @@ module DeepCover
|
|
23
22
|
@buffer.name || "(source: '#{@buffer.source[0..20]}...')"
|
24
23
|
end
|
25
24
|
|
25
|
+
def lineno
|
26
|
+
@buffer.first_line
|
27
|
+
end
|
28
|
+
|
26
29
|
def nb_lines
|
27
30
|
@nb_lines ||= begin
|
28
31
|
lines = buffer.source_lines
|
@@ -37,7 +40,7 @@ module DeepCover
|
|
37
40
|
def execute_code(binding: DeepCover::GLOBAL_BINDING.dup)
|
38
41
|
return if has_executed?
|
39
42
|
global[nb] = Array.new(@tracker_count, 0)
|
40
|
-
eval(@covered_source, binding, @buffer.name || '<raw_code>',
|
43
|
+
eval(@covered_source, binding, @buffer.name || '<raw_code>', lineno)
|
41
44
|
self
|
42
45
|
end
|
43
46
|
|
data/lib/deep_cover/node/base.rb
CHANGED
@@ -30,9 +30,38 @@ module DeepCover
|
|
30
30
|
|
31
31
|
### Public API
|
32
32
|
|
33
|
+
# Search self and descendants for a particular Class or type
|
34
|
+
def find_all(lookup)
|
35
|
+
case lookup
|
36
|
+
when ::Class
|
37
|
+
each_node.grep(lookup)
|
38
|
+
when ::Symbol
|
39
|
+
each_node.find_all{|n| n.type == lookup}
|
40
|
+
when ::String
|
41
|
+
each_node.find_all{|n| n.source == lookup}
|
42
|
+
when ::Regexp
|
43
|
+
each_node.find_all{|n| n.source =~ lookup}
|
44
|
+
else
|
45
|
+
binding.pry
|
46
|
+
raise ::TypeError, "Expected class or symbol, got #{lookup.class}: #{lookup.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
33
50
|
# Shortcut to access children
|
34
51
|
def [](v)
|
35
|
-
|
52
|
+
if v.is_a?(Integer)
|
53
|
+
children.fetch(v)
|
54
|
+
else
|
55
|
+
found = find_all(v)
|
56
|
+
case found.size
|
57
|
+
when 1
|
58
|
+
found.first
|
59
|
+
when 0
|
60
|
+
raise "No children of type #{v}"
|
61
|
+
else
|
62
|
+
raise "Ambiguous lookup #{v}, found #{found}."
|
63
|
+
end
|
64
|
+
end
|
36
65
|
end
|
37
66
|
|
38
67
|
# Shortcut to create a node from source code
|
@@ -106,7 +135,6 @@ module DeepCover
|
|
106
135
|
|
107
136
|
private
|
108
137
|
def diagnose(exception)
|
109
|
-
exp = base_node.loc.expression
|
110
138
|
msg = if self.class == Node
|
111
139
|
"Unknown node type encountered: #{base_node.type}"
|
112
140
|
else
|
@@ -116,7 +144,7 @@ module DeepCover
|
|
116
144
|
'Attempting to continue, but this node will not be handled properly',
|
117
145
|
('Its subnodes will be ignored' if children.empty?),
|
118
146
|
'Source:',
|
119
|
-
|
147
|
+
expression,
|
120
148
|
"Original exception:",
|
121
149
|
exception.inspect,
|
122
150
|
].join("\n")
|
@@ -49,6 +49,10 @@ module DeepCover
|
|
49
49
|
expression.source if expression
|
50
50
|
end
|
51
51
|
|
52
|
+
def diagnostic_expression
|
53
|
+
expression || parent.diagnostic_expression
|
54
|
+
end
|
55
|
+
|
52
56
|
# Returns an array of character numbers (in the original buffer) that
|
53
57
|
# pertain exclusively to this node (and thus not to any children).
|
54
58
|
def proper_range
|
data/lib/deep_cover/node/send.rb
CHANGED
@@ -37,16 +37,25 @@ module DeepCover
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
#
|
40
|
+
# In different circumstances, we need ().
|
41
|
+
# Deal with ambiguous cases where a method is hidden by a local. Ex:
|
41
42
|
# foo 42, 'hello' #=> Works
|
42
43
|
# foo (42), 'hello' #=> Simplification of what DeepCover would generate, still works
|
43
44
|
# foo = 1; foo 42, 'hello' #=> works
|
44
45
|
# foo = 1; foo (42), 'hello' #=> syntax error.
|
45
46
|
# foo = 1; foo((42), 'hello') #=> works
|
47
|
+
# Deal with do/end block. Ex:
|
48
|
+
# x.foo 42, 43 # => ok
|
49
|
+
# x.foo (42), 43 # => ok
|
50
|
+
# x.foo ((42)), 43 # => ok
|
51
|
+
# x.foo 42, 43 do ; end # => ok
|
52
|
+
# x.foo (42), 43 do ; end # => ok
|
53
|
+
# x.foo ((42)), 43 do ; end # => parse error!
|
46
54
|
def need_parentheses?
|
47
55
|
true unless
|
48
56
|
arguments.empty? || # No issue when no arguments
|
49
|
-
|
57
|
+
loc_hash[:selector_end] || # No issue with foo[bar]= and such
|
58
|
+
loc_hash[:operator] || # No issue with foo.bar=
|
50
59
|
loc_hash[:begin] # Ok if has parentheses
|
51
60
|
end
|
52
61
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module DeepCover
|
2
|
+
class ProblemWithDiagnostic < StandardError
|
3
|
+
attr_reader :covered_code, :line_range, :original_exception
|
4
|
+
|
5
|
+
def initialize(covered_code, line_range, original_exception=nil)
|
6
|
+
@covered_code = covered_code
|
7
|
+
if line_range.is_a?(Parser::Source::Range)
|
8
|
+
@line_range = line_range.line..line_range.last_line
|
9
|
+
else
|
10
|
+
@line_range = line_range
|
11
|
+
end
|
12
|
+
@original_exception = original_exception
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
msg = []
|
17
|
+
msg << "You found a problem with DeepCover!"
|
18
|
+
msg << "Please open an issue at https://github.com/deep-cover/deep-cover/issues"
|
19
|
+
msg << "and include the following diagnostic information:"
|
20
|
+
extra = begin
|
21
|
+
diagnostic_information_lines.map{|line| "| #{line}"}
|
22
|
+
rescue ProblemWithDiagnostic
|
23
|
+
["Oh no! We're in deep trouble!!!"]
|
24
|
+
rescue Exception => e
|
25
|
+
["Oh no! Even diagnostics are failing: #{e}\n#{e.backtrace}"]
|
26
|
+
end
|
27
|
+
msg.concat(extra)
|
28
|
+
msg.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
def diagnostic_information_lines
|
32
|
+
lines = []
|
33
|
+
lines << "Source file: #{covered_code.path}"
|
34
|
+
lines << "Line numbers: #{line_range}"
|
35
|
+
lines << "Source lines around location:"
|
36
|
+
lines.concat source_lines.map{|line| " #{line}" }
|
37
|
+
if original_exception
|
38
|
+
lines << "Original exception:"
|
39
|
+
lines << " #{original_exception.class.name}: #{original_exception.message}"
|
40
|
+
backtrace = Tools.truncate_backtrace(original_exception)
|
41
|
+
lines.concat backtrace.map{|line| " #{line}"}
|
42
|
+
end
|
43
|
+
lines
|
44
|
+
end
|
45
|
+
|
46
|
+
def source_lines(nb_context_line: 7)
|
47
|
+
first_index = line_range.begin - nb_context_line - buffer.first_line
|
48
|
+
first_index = 0 if first_index < 0
|
49
|
+
last_index = line_range.end + nb_context_line - buffer.first_line
|
50
|
+
last_index = 0 if last_index < 0
|
51
|
+
|
52
|
+
lines = buffer.source_lines[first_index..last_index]
|
53
|
+
|
54
|
+
Tools.number_lines(lines, lineno: buffer.first_line, bad_linenos: line_range.to_a)
|
55
|
+
end
|
56
|
+
|
57
|
+
def buffer
|
58
|
+
covered_code.buffer
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -7,8 +7,10 @@ module DeepCover
|
|
7
7
|
cur_lineno = lineno + i
|
8
8
|
cur_lineno_s = cur_lineno.to_s.rjust(nb_lineno_digits)
|
9
9
|
if bad_linenos.include?(cur_lineno)
|
10
|
+
cur_lineno_s = "*#{cur_lineno_s}" unless bad_linenos.empty?
|
10
11
|
prefix = Term::ANSIColor.red("#{cur_lineno_s} | ")
|
11
12
|
else
|
13
|
+
cur_lineno_s = " #{cur_lineno_s}" unless bad_linenos.empty?
|
12
14
|
prefix = Term::ANSIColor.white("#{cur_lineno_s} | ")
|
13
15
|
end
|
14
16
|
"#{prefix}#{line}"
|
@@ -3,7 +3,7 @@ module DeepCover
|
|
3
3
|
def our_coverage(source, fn, lineno, **options)
|
4
4
|
covered_code = CoveredCode.new(source:source, path: fn, lineno: lineno)
|
5
5
|
Tools.execute_sample(covered_code)
|
6
|
-
covered_code.line_coverage(options)
|
6
|
+
covered_code.line_coverage(options)[(lineno-1)..-1]
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DeepCover
|
2
|
+
module Tools::TruncateBacktrace
|
3
|
+
def truncate_backtrace(backtrace, extra_context: 10)
|
4
|
+
backtrace = backtrace.backtrace if backtrace.is_a?(Exception)
|
5
|
+
trace_lines = backtrace.uniq
|
6
|
+
|
7
|
+
keep_from_begin = 0
|
8
|
+
keep_from_end = backtrace.size - 1
|
9
|
+
|
10
|
+
trace_lines.each do |line|
|
11
|
+
from_begin = backtrace.index(line)
|
12
|
+
from_end = backtrace.rindex(line)
|
13
|
+
if from_begin <= backtrace.size - 1 - from_end
|
14
|
+
keep_from_begin = [keep_from_begin, from_begin].max
|
15
|
+
else
|
16
|
+
keep_from_end = [keep_from_end, from_end].min
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
keep_from_begin += extra_context
|
21
|
+
keep_from_end -= extra_context
|
22
|
+
|
23
|
+
return backtrace if keep_from_begin + 5 >= keep_from_end
|
24
|
+
|
25
|
+
result = backtrace[0..keep_from_begin]
|
26
|
+
result << "... #{keep_from_end - keep_from_begin - 1} levels..."
|
27
|
+
result.concat backtrace[keep_from_end..-1]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/deep_cover/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep-cover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-André Lafortune
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-11-
|
12
|
+
date: 2017-11-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: parser
|
@@ -288,6 +288,7 @@ files:
|
|
288
288
|
- lib/deep_cover/node/splat.rb
|
289
289
|
- lib/deep_cover/node/variables.rb
|
290
290
|
- lib/deep_cover/parser_ext/range.rb
|
291
|
+
- lib/deep_cover/problem_with_diagnostic.rb
|
291
292
|
- lib/deep_cover/reporter.rb
|
292
293
|
- lib/deep_cover/reporter/istanbul.rb
|
293
294
|
- lib/deep_cover/tools.rb
|
@@ -304,6 +305,7 @@ files:
|
|
304
305
|
- lib/deep_cover/tools/require_relative_dir.rb
|
305
306
|
- lib/deep_cover/tools/silence_warnings.rb
|
306
307
|
- lib/deep_cover/tools/slice.rb
|
308
|
+
- lib/deep_cover/tools/truncate_backtrace.rb
|
307
309
|
- lib/deep_cover/version.rb
|
308
310
|
homepage: http://github.com
|
309
311
|
licenses:
|
@@ -325,7 +327,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
325
327
|
version: '0'
|
326
328
|
requirements: []
|
327
329
|
rubyforge_project:
|
328
|
-
rubygems_version: 2.6.
|
330
|
+
rubygems_version: 2.6.14
|
329
331
|
signing_key:
|
330
332
|
specification_version: 4
|
331
333
|
summary: Write a short summary, because Rubygems requires one.
|