deep-cover 0.6.2 → 0.6.3.pre
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/.gitignore +3 -1
- data/.rspec +2 -1
- data/.rspec_all +2 -1
- data/.rubocop.yml +8 -9
- data/Gemfile +2 -0
- data/Rakefile +32 -6
- data/bin/cov +3 -3
- data/deep_cover.gemspec +3 -16
- data/exe/deep-cover +5 -0
- data/lib/deep_cover/cli/debugger.rb +1 -1
- data/lib/deep_cover/cli/exec.rb +1 -1
- data/lib/deep_cover/cli/instrumented_clone_reporter.rb +5 -3
- data/lib/deep_cover/cli/runner.rb +2 -2
- data/lib/deep_cover/{tools/dump_covered_code.rb → dump_covered_code.rb} +2 -0
- metadata +10 -203
- data/lib/deep-cover.rb +0 -3
- data/lib/deep_cover.rb +0 -22
- data/lib/deep_cover/analyser.rb +0 -23
- data/lib/deep_cover/analyser/base.rb +0 -104
- data/lib/deep_cover/analyser/branch.rb +0 -41
- data/lib/deep_cover/analyser/covered_code_source.rb +0 -21
- data/lib/deep_cover/analyser/function.rb +0 -14
- data/lib/deep_cover/analyser/node.rb +0 -54
- data/lib/deep_cover/analyser/per_char.rb +0 -38
- data/lib/deep_cover/analyser/per_line.rb +0 -41
- data/lib/deep_cover/analyser/ruby25_like_branch.rb +0 -211
- data/lib/deep_cover/analyser/statement.rb +0 -33
- data/lib/deep_cover/analyser/stats.rb +0 -54
- data/lib/deep_cover/analyser/subset.rb +0 -27
- data/lib/deep_cover/auto_run.rb +0 -71
- data/lib/deep_cover/autoload_tracker.rb +0 -215
- data/lib/deep_cover/backports.rb +0 -22
- data/lib/deep_cover/base.rb +0 -117
- data/lib/deep_cover/basics.rb +0 -22
- data/lib/deep_cover/builtin_takeover.rb +0 -10
- data/lib/deep_cover/config.rb +0 -104
- data/lib/deep_cover/config_setter.rb +0 -33
- data/lib/deep_cover/core_ext/autoload_overrides.rb +0 -112
- data/lib/deep_cover/core_ext/coverage_replacement.rb +0 -61
- data/lib/deep_cover/core_ext/exec_callbacks.rb +0 -27
- data/lib/deep_cover/core_ext/instruction_sequence_load_iseq.rb +0 -32
- data/lib/deep_cover/core_ext/load_overrides.rb +0 -19
- data/lib/deep_cover/core_ext/require_overrides.rb +0 -28
- data/lib/deep_cover/coverage.rb +0 -125
- data/lib/deep_cover/coverage/analysis.rb +0 -42
- data/lib/deep_cover/coverage/persistence.rb +0 -84
- data/lib/deep_cover/covered_code.rb +0 -145
- data/lib/deep_cover/custom_requirer.rb +0 -187
- data/lib/deep_cover/flag_comment_associator.rb +0 -68
- data/lib/deep_cover/load.rb +0 -66
- data/lib/deep_cover/memoize.rb +0 -48
- data/lib/deep_cover/module_override.rb +0 -39
- data/lib/deep_cover/node.rb +0 -23
- data/lib/deep_cover/node/arguments.rb +0 -51
- data/lib/deep_cover/node/assignments.rb +0 -273
- data/lib/deep_cover/node/base.rb +0 -155
- data/lib/deep_cover/node/begin.rb +0 -27
- data/lib/deep_cover/node/block.rb +0 -61
- data/lib/deep_cover/node/branch.rb +0 -32
- data/lib/deep_cover/node/case.rb +0 -113
- data/lib/deep_cover/node/collections.rb +0 -31
- data/lib/deep_cover/node/const.rb +0 -12
- data/lib/deep_cover/node/def.rb +0 -40
- data/lib/deep_cover/node/empty_body.rb +0 -32
- data/lib/deep_cover/node/exceptions.rb +0 -79
- data/lib/deep_cover/node/if.rb +0 -73
- data/lib/deep_cover/node/keywords.rb +0 -86
- data/lib/deep_cover/node/literals.rb +0 -100
- data/lib/deep_cover/node/loops.rb +0 -74
- data/lib/deep_cover/node/mixin/can_augment_children.rb +0 -65
- data/lib/deep_cover/node/mixin/check_completion.rb +0 -18
- data/lib/deep_cover/node/mixin/child_can_be_empty.rb +0 -27
- data/lib/deep_cover/node/mixin/executed_after_children.rb +0 -15
- data/lib/deep_cover/node/mixin/execution_location.rb +0 -66
- data/lib/deep_cover/node/mixin/filters.rb +0 -47
- data/lib/deep_cover/node/mixin/flow_accounting.rb +0 -71
- data/lib/deep_cover/node/mixin/has_child.rb +0 -145
- data/lib/deep_cover/node/mixin/has_child_handler.rb +0 -75
- data/lib/deep_cover/node/mixin/has_tracker.rb +0 -46
- data/lib/deep_cover/node/mixin/is_statement.rb +0 -20
- data/lib/deep_cover/node/mixin/rewriting.rb +0 -35
- data/lib/deep_cover/node/mixin/wrapper.rb +0 -15
- data/lib/deep_cover/node/module.rb +0 -66
- data/lib/deep_cover/node/root.rb +0 -20
- data/lib/deep_cover/node/send.rb +0 -161
- data/lib/deep_cover/node/short_circuit.rb +0 -42
- data/lib/deep_cover/node/splat.rb +0 -15
- data/lib/deep_cover/node/variables.rb +0 -16
- data/lib/deep_cover/parser_ext/range.rb +0 -21
- data/lib/deep_cover/problem_with_diagnostic.rb +0 -63
- data/lib/deep_cover/reporter.rb +0 -10
- data/lib/deep_cover/reporter/base.rb +0 -68
- data/lib/deep_cover/reporter/html.rb +0 -15
- data/lib/deep_cover/reporter/html/base.rb +0 -14
- data/lib/deep_cover/reporter/html/index.rb +0 -59
- data/lib/deep_cover/reporter/html/site.rb +0 -70
- data/lib/deep_cover/reporter/html/source.rb +0 -136
- data/lib/deep_cover/reporter/html/template/assets/32px.png +0 -0
- data/lib/deep_cover/reporter/html/template/assets/40px.png +0 -0
- data/lib/deep_cover/reporter/html/template/assets/deep_cover.css.sass +0 -336
- data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.js +0 -4
- data/lib/deep_cover/reporter/html/template/assets/jquery-3.2.1.min.map +0 -1
- data/lib/deep_cover/reporter/html/template/assets/jstree.css +0 -1108
- data/lib/deep_cover/reporter/html/template/assets/jstree.js +0 -8424
- data/lib/deep_cover/reporter/html/template/assets/jstreetable.js +0 -1069
- data/lib/deep_cover/reporter/html/template/assets/throbber.gif +0 -0
- data/lib/deep_cover/reporter/html/template/index.html.erb +0 -75
- data/lib/deep_cover/reporter/html/template/source.html.erb +0 -35
- data/lib/deep_cover/reporter/istanbul.rb +0 -184
- data/lib/deep_cover/reporter/text.rb +0 -58
- data/lib/deep_cover/reporter/tree/util.rb +0 -86
- data/lib/deep_cover/tools.rb +0 -22
- data/lib/deep_cover/tools/blank.rb +0 -25
- data/lib/deep_cover/tools/builtin_coverage.rb +0 -55
- data/lib/deep_cover/tools/camelize.rb +0 -13
- data/lib/deep_cover/tools/content_tag.rb +0 -11
- data/lib/deep_cover/tools/covered.rb +0 -9
- data/lib/deep_cover/tools/execute_sample.rb +0 -34
- data/lib/deep_cover/tools/format.rb +0 -18
- data/lib/deep_cover/tools/format_char_cover.rb +0 -19
- data/lib/deep_cover/tools/format_generated_code.rb +0 -27
- data/lib/deep_cover/tools/indent_string.rb +0 -26
- data/lib/deep_cover/tools/merge.rb +0 -16
- data/lib/deep_cover/tools/number_lines.rb +0 -22
- data/lib/deep_cover/tools/our_coverage.rb +0 -11
- data/lib/deep_cover/tools/profiling.rb +0 -68
- data/lib/deep_cover/tools/render_template.rb +0 -13
- data/lib/deep_cover/tools/require_relative_dir.rb +0 -12
- data/lib/deep_cover/tools/scan_match_datas.rb +0 -10
- data/lib/deep_cover/tools/silence_warnings.rb +0 -18
- data/lib/deep_cover/tools/slice.rb +0 -9
- data/lib/deep_cover/tools/strip_heredoc.rb +0 -18
- data/lib/deep_cover/tools/truncate_backtrace.rb +0 -32
- data/lib/deep_cover/tracker_bucket.rb +0 -50
- data/lib/deep_cover/tracker_hits_per_path.rb +0 -35
- data/lib/deep_cover/tracker_storage.rb +0 -76
- data/lib/deep_cover/tracker_storage_per_path.rb +0 -34
- data/lib/deep_cover/version.rb +0 -5
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'branch'
|
4
|
-
|
5
|
-
module DeepCover
|
6
|
-
class Node
|
7
|
-
class ShortCircuit < Node
|
8
|
-
include Branch
|
9
|
-
has_tracker :conditional
|
10
|
-
has_child lhs: Node
|
11
|
-
has_child conditional: Node, flow_entry_count: :conditional_tracker_hits,
|
12
|
-
rewrite: '(%{conditional_tracker};%{node})'
|
13
|
-
|
14
|
-
def branches
|
15
|
-
[
|
16
|
-
conditional,
|
17
|
-
TrivialBranch.new(condition: lhs, other_branch: conditional),
|
18
|
-
]
|
19
|
-
end
|
20
|
-
|
21
|
-
def branches_summary(of_branches = branches)
|
22
|
-
of_branches.map do |jump|
|
23
|
-
if jump == conditional
|
24
|
-
'right-hand side'
|
25
|
-
else
|
26
|
-
"#{type == :and ? 'falsy' : 'truthy'} shortcut"
|
27
|
-
end
|
28
|
-
end.join(' and ')
|
29
|
-
end
|
30
|
-
|
31
|
-
def operator
|
32
|
-
loc_hash[:operator].source.to_sym
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class And < ShortCircuit
|
37
|
-
end
|
38
|
-
|
39
|
-
class Or < ShortCircuit
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
class Node
|
5
|
-
class Splat < Node
|
6
|
-
check_completion inner: '[%{node}]', outer: '*%{node}'
|
7
|
-
has_child receiver: Node
|
8
|
-
end
|
9
|
-
|
10
|
-
class Kwsplat < Node
|
11
|
-
check_completion inner: '{%{node}}', outer: '**%{node}'
|
12
|
-
has_child receiver: Node
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
class Node
|
5
|
-
class Variable < Node
|
6
|
-
has_child var_name: Symbol
|
7
|
-
end
|
8
|
-
Ivar = Lvar = Cvar = Gvar = BackRef = Variable
|
9
|
-
|
10
|
-
# $1
|
11
|
-
class NthRef < Node
|
12
|
-
has_child n: Integer
|
13
|
-
# TODO
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Parser::Source::Range
|
4
|
-
def succ
|
5
|
-
adjust(begin_pos: +1, end_pos: +1)
|
6
|
-
end
|
7
|
-
|
8
|
-
def wrap_rwhitespace(whitespaces: /\A\s+/)
|
9
|
-
whitespace = @source_buffer.slice(end_pos..-1)[whitespaces] || ''
|
10
|
-
adjust(end_pos: whitespace.size)
|
11
|
-
end
|
12
|
-
|
13
|
-
def wrap_rwhitespace_and_comments(whitespaces: /\A\s+/)
|
14
|
-
current = wrap_rwhitespace(whitespaces: whitespaces)
|
15
|
-
while @source_buffer.slice(current.end_pos) == '#'
|
16
|
-
comment = @source_buffer.slice(current.end_pos..-1)[/\A[^\n]+/] || ''
|
17
|
-
current = current.adjust(end_pos: comment.size).wrap_rwhitespace(whitespaces: whitespaces)
|
18
|
-
end
|
19
|
-
current
|
20
|
-
end
|
21
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
class ProblemWithDiagnostic < StandardError
|
5
|
-
attr_reader :covered_code, :line_range, :original_exception
|
6
|
-
|
7
|
-
def initialize(covered_code, line_range, original_exception = nil)
|
8
|
-
@covered_code = covered_code
|
9
|
-
if line_range.respond_to? :last_line
|
10
|
-
@line_range = line_range.line..line_range.last_line
|
11
|
-
else
|
12
|
-
@line_range = line_range
|
13
|
-
end
|
14
|
-
@original_exception = original_exception
|
15
|
-
end
|
16
|
-
|
17
|
-
def message
|
18
|
-
msg = []
|
19
|
-
msg << 'You found a problem with DeepCover!'
|
20
|
-
msg << 'Please open an issue at https://github.com/deep-cover/deep-cover/issues'
|
21
|
-
msg << 'and include the following diagnostic information:'
|
22
|
-
extra = begin
|
23
|
-
diagnostic_information_lines.map { |line| "| #{line}" }
|
24
|
-
rescue ProblemWithDiagnostic
|
25
|
-
["Oh no! We're in deep trouble!!!"]
|
26
|
-
rescue Exception => e
|
27
|
-
["Oh no! Even diagnostics are failing: #{e}\n#{e.backtrace}"]
|
28
|
-
end
|
29
|
-
msg.concat(extra)
|
30
|
-
msg.join("\n")
|
31
|
-
end
|
32
|
-
|
33
|
-
def diagnostic_information_lines
|
34
|
-
lines = []
|
35
|
-
lines << "Source file: #{covered_code.path}"
|
36
|
-
lines << "Line numbers: #{line_range}"
|
37
|
-
lines << 'Source lines around location:'
|
38
|
-
lines.concat(source_lines.map { |line| " #{line}" })
|
39
|
-
if original_exception
|
40
|
-
lines << 'Original exception:'
|
41
|
-
lines << " #{original_exception.class}: #{original_exception.message}"
|
42
|
-
backtrace = Tools.truncate_backtrace(original_exception)
|
43
|
-
lines.concat(backtrace.map { |line| " #{line}" })
|
44
|
-
end
|
45
|
-
lines
|
46
|
-
end
|
47
|
-
|
48
|
-
def source_lines(nb_context_line: 7)
|
49
|
-
first_index = line_range.begin - nb_context_line - buffer.first_line
|
50
|
-
first_index = 0 if first_index < 0
|
51
|
-
last_index = line_range.end + nb_context_line - buffer.first_line
|
52
|
-
last_index = 0 if last_index < 0
|
53
|
-
|
54
|
-
lines = buffer.source_lines[first_index..last_index]
|
55
|
-
|
56
|
-
Tools.number_lines(lines, lineno: buffer.first_line, bad_linenos: line_range.to_a)
|
57
|
-
end
|
58
|
-
|
59
|
-
def buffer
|
60
|
-
covered_code.buffer
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/deep_cover/reporter.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
module Reporter
|
5
|
-
require_relative 'tree/util'
|
6
|
-
|
7
|
-
class Base
|
8
|
-
include Memoize
|
9
|
-
memoize :map, :tree, :root_path
|
10
|
-
|
11
|
-
attr_reader :options
|
12
|
-
|
13
|
-
def initialize(coverage, **options)
|
14
|
-
@coverage = coverage
|
15
|
-
@options = options
|
16
|
-
end
|
17
|
-
|
18
|
-
def analysis
|
19
|
-
@analysis ||= Coverage::Analysis.new(@coverage.covered_codes, **options)
|
20
|
-
end
|
21
|
-
|
22
|
-
def each(&block)
|
23
|
-
return to_enum :each unless block_given?
|
24
|
-
@coverage.each do |covered_code|
|
25
|
-
yield relative_path(covered_code.path), covered_code
|
26
|
-
end
|
27
|
-
self
|
28
|
-
end
|
29
|
-
|
30
|
-
# Same as populate, but also yields data, which is either the analysis data (for leaves)
|
31
|
-
# of the sum of the children (for subtrees)
|
32
|
-
def populate_stats
|
33
|
-
return to_enum(__method__) unless block_given?
|
34
|
-
Tree::Util.populate_from_map(
|
35
|
-
tree: tree,
|
36
|
-
map: map,
|
37
|
-
merge: ->(child_data) { Tools.merge(*child_data, :+) }
|
38
|
-
) do |full_path, partial_path, data, children|
|
39
|
-
yield relative_path(full_path), relative_path(partial_path), data, children
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def relative_path(path)
|
46
|
-
path = path.to_s
|
47
|
-
path = path.slice(root_path.length + 1..-1) if path.start_with?(root_path)
|
48
|
-
path
|
49
|
-
end
|
50
|
-
|
51
|
-
def root_path
|
52
|
-
return '' if tree.size > 1
|
53
|
-
path = tree.first.first
|
54
|
-
root = File.dirname(path)
|
55
|
-
root = File.dirname(root) if File.basename(path) == 'dir'
|
56
|
-
root
|
57
|
-
end
|
58
|
-
|
59
|
-
def map
|
60
|
-
analysis.stat_map.transform_keys(&:path).transform_keys(&:to_s)
|
61
|
-
end
|
62
|
-
|
63
|
-
def tree
|
64
|
-
Tree::Util.paths_to_tree(map.keys)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
Reporter::HTML = Module.new
|
5
|
-
|
6
|
-
require_relative_dir 'html'
|
7
|
-
|
8
|
-
module Reporter::HTML
|
9
|
-
class << self
|
10
|
-
def report(coverage, **options)
|
11
|
-
Site.save(coverage, **options)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
module Reporter::HTML::Base
|
5
|
-
include Tools::ContentTag
|
6
|
-
def setup
|
7
|
-
DeepCover::DEFAULTS.keys.map do |setting|
|
8
|
-
value = options[setting]
|
9
|
-
value = value.join(', ') if value.respond_to? :join
|
10
|
-
content_tag :span, value, class: setting
|
11
|
-
end.join
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
require_relative 'base'
|
5
|
-
|
6
|
-
module Reporter
|
7
|
-
class HTML::Index < Struct.new(:base)
|
8
|
-
include HTML::Base
|
9
|
-
extend Forwardable
|
10
|
-
def_delegators :base, :analysis, :options, :populate_stats
|
11
|
-
|
12
|
-
def stats_to_data
|
13
|
-
populate_stats do |full_path, partial_path, data, children|
|
14
|
-
data = transform_data(data)
|
15
|
-
if children.empty?
|
16
|
-
{
|
17
|
-
text: %{<a href="#{full_path}.html">#{partial_path}</a>},
|
18
|
-
data: data,
|
19
|
-
}
|
20
|
-
else
|
21
|
-
{
|
22
|
-
text: partial_path,
|
23
|
-
data: data,
|
24
|
-
children: children,
|
25
|
-
state: {opened: true},
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def columns
|
32
|
-
_covered_code, analyser_map = analysis.analyser_map.first
|
33
|
-
analyser_map ||= []
|
34
|
-
columns = analyser_map.flat_map do |type, analyser|
|
35
|
-
[{
|
36
|
-
value: type,
|
37
|
-
header: analyser.class.human_name,
|
38
|
-
}, {
|
39
|
-
value: :"#{type}_percent",
|
40
|
-
header: '%',
|
41
|
-
},
|
42
|
-
]
|
43
|
-
end
|
44
|
-
columns.unshift(width: 400, header: 'Path')
|
45
|
-
columns
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
# {per_char: Stat, ...} => {per_char: {ignored: ...}, per_char_percent: 55.55, ...}
|
51
|
-
def transform_data(data)
|
52
|
-
Tools.merge(
|
53
|
-
data.transform_values(&:to_h),
|
54
|
-
*data.map { |type, stat| {:"#{type}_percent" => stat.percent_covered} }
|
55
|
-
)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
require 'sass'
|
5
|
-
require_relative 'base'
|
6
|
-
require_relative 'index'
|
7
|
-
require_relative 'source'
|
8
|
-
|
9
|
-
module Reporter::HTML
|
10
|
-
class Site < Reporter::Base
|
11
|
-
include Memoize
|
12
|
-
memoize :analysis
|
13
|
-
|
14
|
-
def path
|
15
|
-
Pathname(options[:output])
|
16
|
-
end
|
17
|
-
|
18
|
-
def save
|
19
|
-
clear
|
20
|
-
save_assets
|
21
|
-
save_index
|
22
|
-
save_pages
|
23
|
-
end
|
24
|
-
|
25
|
-
def clear
|
26
|
-
path.mkpath
|
27
|
-
path.rmtree
|
28
|
-
path.mkpath
|
29
|
-
end
|
30
|
-
|
31
|
-
def compile_stylesheet(source, dest)
|
32
|
-
css = Sass::Engine.for_file(source, style: :expanded).to_css
|
33
|
-
File.write(dest, css)
|
34
|
-
end
|
35
|
-
|
36
|
-
def render_index
|
37
|
-
Tools.render_template(:index, Index.new(self))
|
38
|
-
end
|
39
|
-
|
40
|
-
def save_index
|
41
|
-
path.join('index.html').write(render_index)
|
42
|
-
end
|
43
|
-
|
44
|
-
def save_assets
|
45
|
-
require 'fileutils'
|
46
|
-
src = "#{__dir__}/template/assets"
|
47
|
-
dest = path.join('assets')
|
48
|
-
FileUtils.cp_r(src, dest)
|
49
|
-
compile_stylesheet "#{src}/deep_cover.css.sass", dest.join('deep_cover.css')
|
50
|
-
dest.join('deep_cover.css.sass').delete
|
51
|
-
end
|
52
|
-
|
53
|
-
def render_source(partial_path, covered_code)
|
54
|
-
Tools.render_template(:source, Source.new(analysis.analyser_map.fetch(covered_code), partial_path))
|
55
|
-
end
|
56
|
-
|
57
|
-
def save_pages
|
58
|
-
each do |partial_path, covered_code|
|
59
|
-
dest = path.join("#{partial_path}.html")
|
60
|
-
dest.dirname.mkpath
|
61
|
-
dest.write(render_source(partial_path, covered_code))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.save(coverage, output:, **options)
|
66
|
-
Site.new(coverage, output: output, **options).save
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,136 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module DeepCover
|
4
|
-
module Reporter
|
5
|
-
require_relative 'base'
|
6
|
-
|
7
|
-
class HTML::Source < Struct.new(:analyser_map, :partial_path)
|
8
|
-
include Tools::Covered
|
9
|
-
|
10
|
-
def initialize(analyser_map, partial_path)
|
11
|
-
raise ArgumentError unless analyser_map.values.all? { |a| a.is_a?(Analyser) }
|
12
|
-
super
|
13
|
-
end
|
14
|
-
|
15
|
-
include HTML::Base
|
16
|
-
|
17
|
-
def format_source
|
18
|
-
lines = convert_source.split("\n")
|
19
|
-
lines.map { |line| content_tag(:td, line) }
|
20
|
-
rows = lines.map.with_index do |line, i|
|
21
|
-
nb = content_tag(:td, i + 1, id: "L#{i + 1}", class: :nb)
|
22
|
-
content_tag(:tr, nb + content_tag(:td, line))
|
23
|
-
end
|
24
|
-
content_tag(:table, rows.join, class: :source)
|
25
|
-
end
|
26
|
-
|
27
|
-
def convert_source
|
28
|
-
@rewriter = Parser::Source::TreeRewriter.new(covered_code.buffer)
|
29
|
-
insert_node_tags
|
30
|
-
insert_branch_tags
|
31
|
-
html_escape
|
32
|
-
@rewriter.process
|
33
|
-
end
|
34
|
-
|
35
|
-
def root_path
|
36
|
-
Pathname('.').relative_path_from(Pathname(partial_path).dirname)
|
37
|
-
end
|
38
|
-
|
39
|
-
def stats
|
40
|
-
cells = analyser_map.map do |type, analyser|
|
41
|
-
data = analyser.stats
|
42
|
-
f = ->(kind) { content_tag(:span, data.public_send(kind), class: kind, title: kind) }
|
43
|
-
[content_tag(:th, analyser.class.human_name, class: type),
|
44
|
-
content_tag(:td, "#{f[:executed]} #{f[:ignored] if data.ignored > 0} / #{f[:potentially_executable]}", class: type),
|
45
|
-
]
|
46
|
-
end
|
47
|
-
rows = cells.transpose.map { |line| content_tag(:tr, line.join) }
|
48
|
-
content_tag(:table, rows.join)
|
49
|
-
end
|
50
|
-
|
51
|
-
def analyser
|
52
|
-
analyser_map[:per_char]
|
53
|
-
end
|
54
|
-
|
55
|
-
def covered_code
|
56
|
-
analyser.covered_code
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
RUNS_CLASS = Hash.new('run').merge!(0 => 'not-run', nil => 'ignored')
|
62
|
-
RUNS_TITLE = Hash.new { |k, runs| "#{runs}x" }.merge!(0 => 'never run', nil => 'ignored')
|
63
|
-
|
64
|
-
def node_span(node, kind)
|
65
|
-
runs = analyser.node_runs(node)
|
66
|
-
%{<span class="node-#{node.type} kind-#{kind} #{RUNS_CLASS[runs]}" title="#{RUNS_TITLE[runs]}">}
|
67
|
-
end
|
68
|
-
|
69
|
-
def insert_node_tags
|
70
|
-
analyser.each_node do |node|
|
71
|
-
h = node.executed_loc_hash
|
72
|
-
h.each do |kind, range|
|
73
|
-
wrap(range, node_span(node, kind), '</span>')
|
74
|
-
end
|
75
|
-
exp = node.expression
|
76
|
-
if (exp.nil? || exp.empty?) && !analyser.node_covered?(node) && !node.parent.is_a?(Node::Branch) # Not executed empty bodies must show!
|
77
|
-
replace(exp, icon(:empty, 'empty node never run'))
|
78
|
-
wrap(exp, node_span(node, :empty))
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
ICONS = {
|
84
|
-
fork: 'code-fork',
|
85
|
-
empty: 'code',
|
86
|
-
}.freeze
|
87
|
-
def icon(type, title)
|
88
|
-
%{<i class="#{type}-icon fa fa-#{ICONS[type]}" aria-hidden="true" title="#{title}"></i>}
|
89
|
-
end
|
90
|
-
|
91
|
-
def fork_span(node, kind, id, title: nil, klass: nil)
|
92
|
-
runs = analyser_map[:branch].node_runs(node)
|
93
|
-
title ||= RUNS_TITLE[runs]
|
94
|
-
%{<span class="fork fork-#{kind} fork-#{RUNS_CLASS[runs]} #{klass}" data-fork-id="#{id}">#{icon(:fork, title)}}
|
95
|
-
end
|
96
|
-
|
97
|
-
def insert_branch_tags
|
98
|
-
analyser_map[:branch].each_node.with_index do |node, id|
|
99
|
-
node.branches.each do |branch|
|
100
|
-
exp = branch.expression
|
101
|
-
wrap(exp, fork_span(branch, :branch, id), '</span>') if exp
|
102
|
-
end
|
103
|
-
runs = analyser_map[:branch].node_runs(node)
|
104
|
-
if !covered?(runs) && analyser.node_covered?(node)
|
105
|
-
jumps_missing = node.branches.reject { |jump| analyser.node_covered?(jump) }
|
106
|
-
title = "#{node.branches_summary(jumps_missing)} not covered"
|
107
|
-
klass = 'fork-with-uncovered-branches'
|
108
|
-
end
|
109
|
-
wrap(node.expression, fork_span(node, :whole, id, title: title, klass: klass))
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def replace(range, with)
|
114
|
-
@rewriter.replace(range, with)
|
115
|
-
end
|
116
|
-
|
117
|
-
def wrap(range, before, after = '</span>')
|
118
|
-
line = @rewriter.source_buffer.line_range(range.first_line)
|
119
|
-
pinned = range.with(end_pos: [range, line].map(&:end_pos).min)
|
120
|
-
@rewriter.wrap(pinned, before, after)
|
121
|
-
end
|
122
|
-
|
123
|
-
def html_escape
|
124
|
-
buffer = analyser.covered_code.buffer
|
125
|
-
source = buffer.source
|
126
|
-
{'<' => '<', '>' => '>', '&' => '&'}.each do |char, escaped|
|
127
|
-
source.scan(char) do
|
128
|
-
m = Regexp.last_match
|
129
|
-
range = Parser::Source::Range.new(buffer, m.begin(0), m.end(0))
|
130
|
-
@rewriter.replace(range, escaped)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|