deep-cover 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
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)