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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +227 -0
  3. data/Gemfile +5 -2
  4. data/Rakefile +9 -6
  5. data/bin/console +3 -3
  6. data/bin/cov +8 -8
  7. data/bin/gemcov +2 -2
  8. data/bin/selfcov +5 -5
  9. data/bin/test_gems +11 -10
  10. data/bin/testall +6 -6
  11. data/deep_cover.gemspec +26 -21
  12. data/exe/deep-cover +1 -0
  13. data/lib/deep-cover.rb +2 -0
  14. data/lib/deep_cover.rb +3 -0
  15. data/lib/deep_cover/analyser.rb +2 -0
  16. data/lib/deep_cover/analyser/base.rb +2 -0
  17. data/lib/deep_cover/analyser/branch.rb +4 -2
  18. data/lib/deep_cover/analyser/covered_code_source.rb +3 -1
  19. data/lib/deep_cover/analyser/function.rb +3 -1
  20. data/lib/deep_cover/analyser/ignore_uncovered.rb +6 -4
  21. data/lib/deep_cover/analyser/node.rb +3 -0
  22. data/lib/deep_cover/analyser/optionally_covered.rb +12 -7
  23. data/lib/deep_cover/analyser/per_char.rb +7 -6
  24. data/lib/deep_cover/analyser/per_line.rb +9 -8
  25. data/lib/deep_cover/analyser/statement.rb +2 -0
  26. data/lib/deep_cover/analyser/subset.rb +4 -1
  27. data/lib/deep_cover/auto_run.rb +3 -0
  28. data/lib/deep_cover/autoload_tracker.rb +6 -3
  29. data/lib/deep_cover/backports.rb +2 -0
  30. data/lib/deep_cover/base.rb +11 -2
  31. data/lib/deep_cover/builtin_takeover.rb +2 -0
  32. data/lib/deep_cover/cli/debugger.rb +55 -30
  33. data/lib/deep_cover/cli/deep_cover.rb +17 -11
  34. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +16 -14
  35. data/lib/deep_cover/config.rb +29 -16
  36. data/lib/deep_cover/core_ext/autoload_overrides.rb +2 -0
  37. data/lib/deep_cover/core_ext/coverage_replacement.rb +2 -0
  38. data/lib/deep_cover/core_ext/load_overrides.rb +5 -6
  39. data/lib/deep_cover/core_ext/require_overrides.rb +6 -7
  40. data/lib/deep_cover/coverage.rb +21 -18
  41. data/lib/deep_cover/covered_code.rb +22 -12
  42. data/lib/deep_cover/custom_requirer.rb +82 -35
  43. data/lib/deep_cover/memoize.rb +48 -0
  44. data/lib/deep_cover/module_override.rb +2 -0
  45. data/lib/deep_cover/node.rb +14 -1
  46. data/lib/deep_cover/node/arguments.rb +2 -0
  47. data/lib/deep_cover/node/assignments.rb +32 -30
  48. data/lib/deep_cover/node/base.rb +30 -29
  49. data/lib/deep_cover/node/begin.rb +3 -1
  50. data/lib/deep_cover/node/block.rb +5 -2
  51. data/lib/deep_cover/node/branch.rb +2 -1
  52. data/lib/deep_cover/node/case.rb +15 -13
  53. data/lib/deep_cover/node/collections.rb +2 -0
  54. data/lib/deep_cover/node/const.rb +2 -0
  55. data/lib/deep_cover/node/def.rb +10 -8
  56. data/lib/deep_cover/node/empty_body.rb +2 -0
  57. data/lib/deep_cover/node/exceptions.rb +3 -1
  58. data/lib/deep_cover/node/if.rb +3 -1
  59. data/lib/deep_cover/node/keywords.rb +4 -2
  60. data/lib/deep_cover/node/literals.rb +2 -0
  61. data/lib/deep_cover/node/loops.rb +5 -3
  62. data/lib/deep_cover/node/mixin/can_augment_children.rb +8 -7
  63. data/lib/deep_cover/node/mixin/check_completion.rb +3 -1
  64. data/lib/deep_cover/node/mixin/child_can_be_empty.rb +4 -2
  65. data/lib/deep_cover/node/mixin/executed_after_children.rb +2 -0
  66. data/lib/deep_cover/node/mixin/execution_location.rb +4 -2
  67. data/lib/deep_cover/node/mixin/flow_accounting.rb +2 -0
  68. data/lib/deep_cover/node/mixin/has_child.rb +22 -18
  69. data/lib/deep_cover/node/mixin/has_child_handler.rb +10 -8
  70. data/lib/deep_cover/node/mixin/has_tracker.rb +4 -2
  71. data/lib/deep_cover/node/mixin/is_statement.rb +3 -1
  72. data/lib/deep_cover/node/mixin/rewriting.rb +5 -3
  73. data/lib/deep_cover/node/mixin/wrapper.rb +2 -0
  74. data/lib/deep_cover/node/module.rb +11 -9
  75. data/lib/deep_cover/node/root.rb +2 -0
  76. data/lib/deep_cover/node/send.rb +4 -2
  77. data/lib/deep_cover/node/short_circuit.rb +4 -2
  78. data/lib/deep_cover/node/splat.rb +2 -0
  79. data/lib/deep_cover/node/variables.rb +2 -0
  80. data/lib/deep_cover/parser_ext/range.rb +3 -1
  81. data/lib/deep_cover/problem_with_diagnostic.rb +11 -9
  82. data/lib/deep_cover/reporter.rb +2 -0
  83. data/lib/deep_cover/reporter/istanbul.rb +28 -24
  84. data/lib/deep_cover/tools.rb +2 -0
  85. data/lib/deep_cover/tools/builtin_coverage.rb +6 -4
  86. data/lib/deep_cover/tools/camelize.rb +3 -1
  87. data/lib/deep_cover/tools/dasherize.rb +3 -1
  88. data/lib/deep_cover/tools/dump_covered_code.rb +7 -6
  89. data/lib/deep_cover/tools/execute_sample.rb +13 -13
  90. data/lib/deep_cover/tools/format.rb +3 -1
  91. data/lib/deep_cover/tools/format_char_cover.rb +4 -2
  92. data/lib/deep_cover/tools/format_generated_code.rb +3 -1
  93. data/lib/deep_cover/tools/number_lines.rb +2 -0
  94. data/lib/deep_cover/tools/our_coverage.rb +5 -3
  95. data/lib/deep_cover/tools/profiling.rb +66 -0
  96. data/lib/deep_cover/tools/require_relative_dir.rb +3 -1
  97. data/lib/deep_cover/tools/silence_warnings.rb +4 -1
  98. data/lib/deep_cover/tools/slice.rb +3 -1
  99. data/lib/deep_cover/tools/truncate_backtrace.rb +2 -0
  100. data/lib/deep_cover/version.rb +3 -1
  101. metadata +47 -30
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node
3
5
  class Begin < Node
@@ -16,7 +18,7 @@ module DeepCover
16
18
  when 'else', '#{'
17
19
  %i[begin end]
18
20
  else
19
- warn "Unknown context for Begin node"
21
+ warn 'Unknown context for Begin node'
20
22
  []
21
23
  end
22
24
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'send'
2
4
  require_relative 'keywords'
3
5
 
@@ -32,8 +34,9 @@ module DeepCover
32
34
  class Block < Node
33
35
  check_completion
34
36
  has_tracker :body
35
- has_child call: { send: SendWithBlock, csend: CsendWithBlock,
36
- zsuper: SuperWithBlock, super: SuperWithBlock }
37
+ has_child call: {send: SendWithBlock, csend: CsendWithBlock,
38
+ zsuper: SuperWithBlock, super: SuperWithBlock,
39
+ }
37
40
  has_child args: Args
38
41
  has_child body: Node,
39
42
  can_be_empty: -> { base_node.loc.end.begin },
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'empty_body'
2
4
 
3
5
  module DeepCover
@@ -26,6 +28,5 @@ module DeepCover
26
28
  @condition.flow_completion_count - @other_branch.flow_entry_count
27
29
  end
28
30
  end
29
-
30
31
  end
31
32
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'branch'
2
4
 
3
5
  module DeepCover
@@ -14,8 +16,8 @@ module DeepCover
14
16
  # See https://github.com/jruby/jruby/issues/4804
15
17
  # This is solved in jruby 9.2.0.0, better keep the workaround
16
18
  # for compatibility.
17
- has_child condition: Node, rewrite: "(((%{entry_tracker}) && %{node}))",
18
- flow_entry_count: :entry_tracker_hits
19
+ has_child condition: Node, rewrite: '(((%{entry_tracker}) && %{node}))',
20
+ flow_entry_count: :entry_tracker_hits
19
21
  executed_loc_keys []
20
22
 
21
23
  def flow_entry_count
@@ -43,18 +45,18 @@ module DeepCover
43
45
 
44
46
  class When < Node
45
47
  has_tracker :body_entry
46
- has_extra_children matches: { splat: WhenSplatCondition, Parser::AST::Node => WhenCondition }
48
+ has_extra_children matches: {splat: WhenSplatCondition, Parser::AST::Node => WhenCondition}
47
49
  has_child body: Node,
48
- can_be_empty: -> {
49
- if (after_then = base_node.loc.begin)
50
- after_then.end
51
- else
52
- base_node.loc.expression.end
53
- end
54
- },
55
- rewrite: ";%{body_entry_tracker};%{local}=nil;%{node}",
56
- is_statement: true,
57
- flow_entry_count: :body_entry_tracker_hits
50
+ can_be_empty: -> {
51
+ if (after_then = base_node.loc.begin)
52
+ after_then.end
53
+ else
54
+ base_node.loc.expression.end
55
+ end
56
+ },
57
+ rewrite: ';%{body_entry_tracker};%{local}=nil;%{node}',
58
+ is_statement: true,
59
+ flow_entry_count: :body_entry_tracker_hits
58
60
 
59
61
  def flow_entry_count
60
62
  matches.first.flow_entry_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'splat'
2
4
 
3
5
  module DeepCover
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node::Const < Node
3
5
  check_completion
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'arguments'
2
4
 
3
5
  module DeepCover
@@ -7,10 +9,10 @@ module DeepCover
7
9
  has_child method_name: Symbol
8
10
  has_child signature: Args
9
11
  has_child body: Node,
10
- rewrite: '%{method_call_tracker};%{local}=nil;%{node}',
11
- can_be_empty: -> { base_node.loc.end.begin },
12
- is_statement: true,
13
- flow_entry_count: :method_call_tracker_hits
12
+ rewrite: '%{method_call_tracker};%{local}=nil;%{node}',
13
+ can_be_empty: -> { base_node.loc.end.begin },
14
+ is_statement: true,
15
+ flow_entry_count: :method_call_tracker_hits
14
16
  executed_loc_keys :keyword, :name
15
17
 
16
18
  def children_nodes_in_flow_order
@@ -25,10 +27,10 @@ module DeepCover
25
27
  has_child method_name: Symbol
26
28
  has_child signature: Args
27
29
  has_child body: Node,
28
- rewrite: '%{method_call_tracker};%{local}=nil;%{node}',
29
- can_be_empty: -> { base_node.loc.end.begin },
30
- is_statement: true,
31
- flow_entry_count: :method_call_tracker_hits
30
+ rewrite: '%{method_call_tracker};%{local}=nil;%{node}',
31
+ can_be_empty: -> { base_node.loc.end.begin },
32
+ is_statement: true,
33
+ flow_entry_count: :method_call_tracker_hits
32
34
  executed_loc_keys :keyword, :name, :operator
33
35
 
34
36
  def children_nodes_in_flow_order
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node::EmptyBody < Node
3
5
  def initialize(base_node, parent: raise, index: 0, position: ChildCanBeEmpty.last_empty_position)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'variables'
2
4
  require_relative 'collections'
3
5
 
@@ -51,7 +53,7 @@ module DeepCover
51
53
  if prev.equal? watched_body
52
54
  prev.flow_entry_count - prev.flow_completion_count
53
55
  else # RESBODIES
54
- if prev.exception
56
+ if prev.exception # rubocop:disable Style/IfInsideElse
55
57
  prev.exception.flow_completion_count - prev.execution_count
56
58
  else
57
59
  prev.flow_entry_count - prev.execution_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'branch'
2
4
 
3
5
  module DeepCover
@@ -19,7 +21,7 @@ module DeepCover
19
21
  executed_loc_keys :keyword, :question
20
22
 
21
23
  def branches
22
- [ true_branch, false_branch ]
24
+ [true_branch, false_branch]
23
25
  end
24
26
 
25
27
  def execution_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'variables'
2
4
  require_relative 'literals'
3
5
 
@@ -31,7 +33,7 @@ module DeepCover
31
33
 
32
34
  class Break < Node
33
35
  has_extra_children arguments: Node
34
- # TODO Anything special needed for the arguments?
36
+ # TODO: Anything special needed for the arguments?
35
37
 
36
38
  def flow_completion_count
37
39
  0
@@ -40,7 +42,7 @@ module DeepCover
40
42
 
41
43
  class Next < Node
42
44
  has_extra_children arguments: Node
43
- # TODO Anything special needed for the arguments?
45
+ # TODO: Anything special needed for the arguments?
44
46
 
45
47
  def flow_completion_count
46
48
  0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'begin'
2
4
  require_relative 'variables'
3
5
  module DeepCover
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  class Node
3
5
  class For < Node
@@ -5,9 +7,9 @@ module DeepCover
5
7
  has_child assignments: [Mlhs, VariableAssignment], flow_entry_count: -> { body.flow_entry_count if body }
6
8
  has_child iterable: [Node], flow_entry_count: -> { flow_entry_count }
7
9
  has_child body: Node,
8
- can_be_empty: -> { base_node.loc.end.begin },
9
- flow_entry_count: :body_tracker_hits,
10
- rewrite: '((%{body_tracker};%{local}=nil;%{node}))'
10
+ can_be_empty: -> { base_node.loc.end.begin },
11
+ flow_entry_count: :body_tracker_hits,
12
+ rewrite: '((%{body_tracker};%{local}=nil;%{node}))'
11
13
  check_completion
12
14
 
13
15
  def execution_count
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module CanAugmentChildren
@@ -10,9 +12,9 @@ module DeepCover
10
12
  # Caution: receiver is not fully constructed since it is also being augmented.
11
13
  # don't call `children`
12
14
  def augment_children(child_base_nodes)
13
- missing = self.class.min_children - child_base_nodes.size
14
- if missing > 0
15
- child_base_nodes = [*child_base_nodes, *Array.new(missing)]
15
+ if child_base_nodes.size < (sz = self.class.min_children)
16
+ child_base_nodes = child_base_nodes.dup
17
+ child_base_nodes[sz..-1] = [] # Fill with nil
16
18
  end
17
19
  child_base_nodes.map.with_index do |child, child_index|
18
20
  child_name = self.class.child_index_to_name(child_index, child_base_nodes.size)
@@ -25,14 +27,13 @@ module DeepCover
25
27
  end
26
28
  private :augment_children
27
29
 
28
- def remap_child(child, name=nil)
30
+ def remap_child(child, name = nil)
29
31
  return unless child.is_a?(Parser::AST::Node)
30
32
  class_name = Tools.camelize(child.type)
31
33
  Node.const_defined?(class_name) ? Node.const_get(class_name) : Node
32
34
  end
33
35
 
34
36
  module ClassMethods
35
-
36
37
  # This handles the following shortcuts:
37
38
  # has_child foo: {type: NodeClass, ...}
38
39
  # same as:
@@ -43,13 +44,13 @@ module DeepCover
43
44
  def has_child(remap: nil, **h)
44
45
  name, types = h.first
45
46
  if types.is_a? Hash
46
- raise "Use either remap or a hash as type but not both" if remap
47
+ raise 'Use either remap or a hash as type but not both' if remap
47
48
  remap = types
48
49
  h[name] = types = []
49
50
  end
50
51
  if remap.is_a? Hash
51
52
  type_map = remap
52
- remap = -> (child) do
53
+ remap = ->(child) do
53
54
  klass = type_map[child.type] if child.respond_to? :type
54
55
  klass ||= type_map[child.class]
55
56
  klass
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'executed_after_children'
2
4
 
3
5
  module DeepCover
4
6
  module Node::Mixin
5
7
  module CheckCompletion
6
- def check_completion(outer:'(%{node})', inner:'(%{node})')
8
+ def check_completion(outer: '(%{node})', inner: '(%{node})')
7
9
  has_tracker :completion
8
10
  include ExecutedAfterChildren
9
11
  alias_method :flow_completion_count, :completion_tracker_hits
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module ChildCanBeEmpty
@@ -8,7 +10,7 @@ module DeepCover
8
10
  end
9
11
  end
10
12
 
11
- def remap_child(child, name=raise)
13
+ def remap_child(child, name = raise)
12
14
  if child == nil
13
15
  if (ChildCanBeEmpty.last_empty_position = child_can_be_empty(child, name))
14
16
  return Node::EmptyBody
@@ -17,7 +19,7 @@ module DeepCover
17
19
  super
18
20
  end
19
21
 
20
- def child_can_be_empty(_child, _name=nil)
22
+ def child_can_be_empty(_child, _name = nil)
21
23
  false
22
24
  end
23
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  # By default, nodes are considered executed if they are entered.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module ExecutionLocation
@@ -30,7 +32,7 @@ module DeepCover
30
32
  if (keys = parent.child_executed_loc_keys(self))
31
33
  h.merge!(Tools.slice(parent.loc_hash, *keys))
32
34
  end
33
- h.reject{|k, v| v.nil? }
35
+ h.reject { |k, v| v.nil? }
34
36
  end
35
37
 
36
38
  def executed_locs
@@ -38,7 +40,7 @@ module DeepCover
38
40
  end
39
41
 
40
42
  def loc_hash
41
- @loc_hash ||= (base_node.respond_to?(:location) ? base_node.location.to_hash : {}).freeze
43
+ base_node.respond_to?(:location) ? base_node.location.to_hash : {}
42
44
  end
43
45
 
44
46
  def expression
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module FlowAccounting
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DeepCover
2
4
  module Node::Mixin
3
5
  module HasChild
4
6
  def self.included(base)
5
7
  base.extend ClassMethods
6
8
  end
7
- CHILDREN = {}
8
- CHILDREN_TYPES = {}
9
+ CHILDREN = {}.freeze
10
+ CHILDREN_TYPES = {}.freeze
9
11
 
10
12
  def initialize(*)
11
13
  super
@@ -20,31 +22,31 @@ module DeepCover
20
22
  end
21
23
 
22
24
  module ClassMethods
23
- def has_child(_rest: false, _refine: false, **h)
25
+ def has_child(rest_: false, refine_: false, **h)
24
26
  raise "Needs exactly one custom named argument, got #{h.size}" if h.size != 1
25
27
  name, types = h.first
26
28
  raise TypeError, "Expect a Symbol for name, got a #{name.class} (#{name.inspect})" unless name.is_a?(Symbol)
27
- update_children_const(name, rest: _rest) unless _refine
28
- define_accessor(name) unless _refine
29
+ update_children_const(name, rest: rest_) unless refine_
30
+ define_accessor(name) unless refine_
29
31
  add_runtime_check(name, types)
30
32
  self
31
33
  end
32
34
 
33
35
  def has_extra_children(**h)
34
- has_child(**h, _rest: true)
36
+ has_child(**h, rest_: true)
35
37
  end
36
38
 
37
39
  def refine_child(child_name = nil, **h)
38
40
  if child_name
39
41
  h = {child_name => self::CHILDREN_TYPES.fetch(child_name), **h}
40
42
  end
41
- has_child(**h, _refine: true)
43
+ has_child(**h, refine_: true)
42
44
  end
43
45
 
44
46
  def child_index_to_name(index, nb_children)
45
47
  self::CHILDREN.each do |name, i|
46
48
  return name if i == index || (i == index - nb_children) ||
47
- (i.is_a?(Range) && i.begin <= index && i.end + nb_children >= index)
49
+ (i.is_a?(Range) && i.begin <= index && i.end + nb_children >= index)
48
50
  end
49
51
  raise IndexError, "index #{index} does not correspond to any child of #{self}"
50
52
  end
@@ -82,7 +84,7 @@ module DeepCover
82
84
  when nil
83
85
  node.nil?
84
86
  when Array
85
- expected.any? {|exp| node_matches_type?(node, exp) }
87
+ expected.any? { |exp| node_matches_type?(node, exp) }
86
88
  when Class
87
89
  node.is_a?(expected)
88
90
  when Symbol
@@ -110,22 +112,24 @@ module DeepCover
110
112
  end
111
113
  end
112
114
  children_map[name] = if rest
113
- raise "Class #{self} can't have extra children '#{name}' because it already has '#{name}' (#{children_map.inspect})" if already_has_rest
114
- children_map.size..-1
115
- elsif already_has_rest
116
- -1
117
- else
118
- children_map.size
119
- end
115
+ if already_has_rest
116
+ raise "Class #{self} can't have extra children '#{name}' because it already has '#{name}' (#{children_map})"
117
+ end
118
+ children_map.size..-1
119
+ elsif already_has_rest
120
+ -1
121
+ else
122
+ children_map.size
123
+ end
120
124
  end
121
125
 
122
126
  def define_accessor(name)
123
127
  warn "child name '#{name}' conflicts with existing method for #{self}" if method_defined? name
124
- class_eval <<-end_eval, __FILE__, __LINE__
128
+ class_eval <<-EVAL, __FILE__, __LINE__ + 1
125
129
  def #{name}
126
130
  children[CHILDREN.fetch(#{name.inspect})]
127
131
  end
128
- end_eval
132
+ EVAL
129
133
  end
130
134
 
131
135
  def add_runtime_check(name, type)