deep-cover 0.1.1

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +8 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +127 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/cov +43 -0
  12. data/bin/gemcov +8 -0
  13. data/bin/selfcov +21 -0
  14. data/bin/setup +8 -0
  15. data/bin/testall +88 -0
  16. data/deep_cover.gemspec +44 -0
  17. data/exe/deep-cover +6 -0
  18. data/future_read_me.md +108 -0
  19. data/lib/deep-cover.rb +1 -0
  20. data/lib/deep_cover.rb +11 -0
  21. data/lib/deep_cover/analyser.rb +24 -0
  22. data/lib/deep_cover/analyser/base.rb +51 -0
  23. data/lib/deep_cover/analyser/branch.rb +20 -0
  24. data/lib/deep_cover/analyser/covered_code_source.rb +31 -0
  25. data/lib/deep_cover/analyser/function.rb +12 -0
  26. data/lib/deep_cover/analyser/ignore_uncovered.rb +19 -0
  27. data/lib/deep_cover/analyser/node.rb +11 -0
  28. data/lib/deep_cover/analyser/per_char.rb +20 -0
  29. data/lib/deep_cover/analyser/per_line.rb +23 -0
  30. data/lib/deep_cover/analyser/statement.rb +31 -0
  31. data/lib/deep_cover/analyser/subset.rb +24 -0
  32. data/lib/deep_cover/auto_run.rb +49 -0
  33. data/lib/deep_cover/autoload_tracker.rb +75 -0
  34. data/lib/deep_cover/backports.rb +9 -0
  35. data/lib/deep_cover/base.rb +55 -0
  36. data/lib/deep_cover/builtin_takeover.rb +2 -0
  37. data/lib/deep_cover/cli/debugger.rb +93 -0
  38. data/lib/deep_cover/cli/deep_cover.rb +49 -0
  39. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +105 -0
  40. data/lib/deep_cover/config.rb +52 -0
  41. data/lib/deep_cover/core_ext/autoload_overrides.rb +40 -0
  42. data/lib/deep_cover/core_ext/coverage_replacement.rb +26 -0
  43. data/lib/deep_cover/core_ext/load_overrides.rb +24 -0
  44. data/lib/deep_cover/core_ext/require_overrides.rb +36 -0
  45. data/lib/deep_cover/coverage.rb +198 -0
  46. data/lib/deep_cover/covered_code.rb +138 -0
  47. data/lib/deep_cover/custom_requirer.rb +93 -0
  48. data/lib/deep_cover/node.rb +8 -0
  49. data/lib/deep_cover/node/arguments.rb +50 -0
  50. data/lib/deep_cover/node/assignments.rb +250 -0
  51. data/lib/deep_cover/node/base.rb +99 -0
  52. data/lib/deep_cover/node/begin.rb +25 -0
  53. data/lib/deep_cover/node/block.rb +53 -0
  54. data/lib/deep_cover/node/boolean.rb +22 -0
  55. data/lib/deep_cover/node/branch.rb +28 -0
  56. data/lib/deep_cover/node/case.rb +94 -0
  57. data/lib/deep_cover/node/collections.rb +21 -0
  58. data/lib/deep_cover/node/const.rb +10 -0
  59. data/lib/deep_cover/node/def.rb +38 -0
  60. data/lib/deep_cover/node/empty_body.rb +21 -0
  61. data/lib/deep_cover/node/exceptions.rb +74 -0
  62. data/lib/deep_cover/node/if.rb +36 -0
  63. data/lib/deep_cover/node/keywords.rb +84 -0
  64. data/lib/deep_cover/node/literals.rb +77 -0
  65. data/lib/deep_cover/node/loops.rb +72 -0
  66. data/lib/deep_cover/node/mixin/can_augment_children.rb +65 -0
  67. data/lib/deep_cover/node/mixin/check_completion.rb +16 -0
  68. data/lib/deep_cover/node/mixin/child_can_be_empty.rb +25 -0
  69. data/lib/deep_cover/node/mixin/executed_after_children.rb +13 -0
  70. data/lib/deep_cover/node/mixin/execution_location.rb +56 -0
  71. data/lib/deep_cover/node/mixin/flow_accounting.rb +63 -0
  72. data/lib/deep_cover/node/mixin/has_child.rb +138 -0
  73. data/lib/deep_cover/node/mixin/has_child_handler.rb +73 -0
  74. data/lib/deep_cover/node/mixin/has_tracker.rb +44 -0
  75. data/lib/deep_cover/node/mixin/is_statement.rb +18 -0
  76. data/lib/deep_cover/node/mixin/rewriting.rb +32 -0
  77. data/lib/deep_cover/node/mixin/wrapper.rb +13 -0
  78. data/lib/deep_cover/node/module.rb +64 -0
  79. data/lib/deep_cover/node/root.rb +18 -0
  80. data/lib/deep_cover/node/send.rb +83 -0
  81. data/lib/deep_cover/node/splat.rb +13 -0
  82. data/lib/deep_cover/node/variables.rb +14 -0
  83. data/lib/deep_cover/parser_ext/range.rb +40 -0
  84. data/lib/deep_cover/reporter.rb +6 -0
  85. data/lib/deep_cover/reporter/istanbul.rb +151 -0
  86. data/lib/deep_cover/tools.rb +18 -0
  87. data/lib/deep_cover/tools/builtin_coverage.rb +50 -0
  88. data/lib/deep_cover/tools/camelize.rb +8 -0
  89. data/lib/deep_cover/tools/dump_covered_code.rb +32 -0
  90. data/lib/deep_cover/tools/execute_sample.rb +23 -0
  91. data/lib/deep_cover/tools/format.rb +16 -0
  92. data/lib/deep_cover/tools/format_char_cover.rb +18 -0
  93. data/lib/deep_cover/tools/format_generated_code.rb +25 -0
  94. data/lib/deep_cover/tools/number_lines.rb +18 -0
  95. data/lib/deep_cover/tools/our_coverage.rb +9 -0
  96. data/lib/deep_cover/tools/require_relative_dir.rb +10 -0
  97. data/lib/deep_cover/tools/silence_warnings.rb +15 -0
  98. data/lib/deep_cover/version.rb +3 -0
  99. metadata +326 -0
@@ -0,0 +1,25 @@
1
+ module DeepCover
2
+ class Node
3
+ class Begin < Node
4
+ has_extra_children expressions: Node,
5
+ is_statement: true
6
+
7
+ def is_statement
8
+ false
9
+ end
10
+
11
+ def executed_loc_keys
12
+ # Begin is a generic grouping used in different contexts.
13
+ case loc_hash[:begin] && loc_hash[:begin].source
14
+ when nil, '(', 'begin'
15
+ []
16
+ when 'else', '#{'
17
+ %i[begin end]
18
+ else
19
+ warn "Unknown context for Begin node"
20
+ []
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'send'
2
+ require_relative 'keywords'
3
+
4
+ module DeepCover
5
+ class Node
6
+ module WithBlock
7
+ def flow_completion_count
8
+ parent.flow_completion_count
9
+ end
10
+
11
+ def execution_count
12
+ last = children_nodes.last
13
+ return last.flow_completion_count if last
14
+ super
15
+ end
16
+ end
17
+
18
+ class SendWithBlock < Node
19
+ include WithBlock
20
+ has_child receiver: [Node, nil]
21
+ has_child method_name: Symbol
22
+ has_extra_children arguments: Node
23
+ end
24
+
25
+ class SuperWithBlock < Node
26
+ include WithBlock
27
+ has_extra_children arguments: Node
28
+ end
29
+
30
+ class Block < Node
31
+ check_completion
32
+ has_tracker :body
33
+ has_child call: {send: SendWithBlock, zsuper: SuperWithBlock, super: SuperWithBlock}
34
+ has_child args: Args
35
+ has_child body: Node,
36
+ can_be_empty: -> { base_node.loc.begin.end },
37
+ rewrite: '%{body_tracker};%{local}=nil;%{node}',
38
+ flow_entry_count: :body_tracker_hits,
39
+ is_statement: true
40
+ executed_loc_keys # none
41
+
42
+ def children_nodes_in_flow_order
43
+ [call, args] # Similarly to a def, the body is actually not part of the flow of this node...
44
+ end
45
+ end
46
+
47
+ # &foo
48
+ class BlockPass < Node
49
+ has_child block: Node
50
+ # TODO
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'branch'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class ShortCircuit < Node
6
+ include Branch
7
+ has_tracker :conditional
8
+ has_child first: Node
9
+ has_child conditional: Node, flow_entry_count: :conditional_tracker_hits,
10
+ rewrite: '((%{conditional_tracker};%{node}))'
11
+
12
+ def branches
13
+ [
14
+ conditional,
15
+ TrivialBranch.new(first, conditional)
16
+ ]
17
+ end
18
+ end
19
+
20
+ And = Or = ShortCircuit
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module DeepCover
2
+ class Node
3
+ module Branch
4
+ def flow_completion_count
5
+ branches.map(&:flow_completion_count).inject(0, :+)
6
+ end
7
+
8
+ # Define in sublasses:
9
+ def branches
10
+ raise NotImplementedError
11
+ end
12
+
13
+ # Also define flow_entry_count
14
+ end
15
+
16
+ class TrivialBranch < Struct.new(:condition, :other_branch)
17
+ def flow_entry_count
18
+ condition.flow_completion_count - other_branch.flow_entry_count
19
+ end
20
+ alias_method :flow_completion_count, :flow_entry_count
21
+ alias_method :execution_count, :flow_entry_count
22
+ def executable?
23
+ true
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,94 @@
1
+ require_relative 'branch'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class WhenCondition < Node
6
+ include Wrapper
7
+ has_tracker :entry
8
+ # Using && instead of ; solves a weird bug in jruby 9.1.7.0 and 9.1.9.0 (probably before too).
9
+ # The following will only print 'test' once
10
+ # class EqEqEq; def ===(other); puts 'test'; end; end
11
+ # eqeqeq = EqEqEq.new
12
+ # case 1; when eqeqeq; end
13
+ # case 1; when (3;eqeqeq); end
14
+ # See https://github.com/jruby/jruby/issues/4804
15
+ # This is solved in jruby 9.2.0.0, better keep the workaround
16
+ # for compatibility.
17
+ has_child condition: Node, rewrite: "(((%{entry_tracker}) && %{node}))",
18
+ flow_entry_count: :entry_tracker_hits
19
+ executed_loc_keys []
20
+
21
+ def flow_entry_count
22
+ entry_tracker_hits
23
+ end
24
+
25
+ def flow_completion_count
26
+ condition.flow_completion_count
27
+ end
28
+
29
+ def loc_hash
30
+ condition.loc_hash
31
+ end
32
+ end
33
+
34
+ class WhenSplatCondition < Node
35
+ has_tracker :entry
36
+ check_completion inner: '(%{entry_tracker};[%{node}])', outer: '*%{node}'
37
+ has_child receiver: Node
38
+
39
+ def flow_entry_count
40
+ entry_tracker_hits
41
+ end
42
+ end
43
+
44
+ class When < Node
45
+ has_tracker :body_entry
46
+ has_extra_children matches: { splat: WhenSplatCondition, Parser::AST::Node => WhenCondition }
47
+ has_child body: Node,
48
+ can_be_empty: -> { base_node.loc.expression.succ },
49
+ rewrite: ";%{body_entry_tracker};%{local}=nil;%{node}",
50
+ is_statement: true,
51
+ flow_entry_count: :body_entry_tracker_hits
52
+
53
+ def flow_entry_count
54
+ matches.first.flow_entry_count
55
+ end
56
+
57
+ def execution_count
58
+ matches.first.flow_completion_count
59
+ end
60
+
61
+ def flow_completion_count
62
+ body.flow_completion_count + next_sibling.flow_entry_count
63
+ end
64
+ end
65
+
66
+ class Case < Node
67
+ include Branch
68
+ has_tracker :else_entry
69
+ has_child evaluate: [Node, nil]
70
+ has_extra_children whens: When
71
+ has_child else: Node,
72
+ can_be_empty: -> { base_node.loc.end.begin },
73
+ rewrite: -> { "#{'else;' unless has_else?}((%{else_entry_tracker};%{local}=nil;%{node}))" },
74
+ executed_loc_keys: [:else],
75
+ is_statement: true,
76
+ flow_entry_count: :else_entry_tracker_hits
77
+
78
+ executed_loc_keys :begin, :keyword
79
+
80
+ def branches
81
+ whens.map(&:body) << self.else
82
+ end
83
+
84
+ def execution_count
85
+ return evaluate.flow_completion_count if evaluate
86
+ flow_entry_count
87
+ end
88
+
89
+ def has_else?
90
+ !!base_node.loc.to_hash[:else]
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'splat'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class Array < Node
6
+ has_extra_children elements: Node
7
+ executed_loc_keys :begin, :end
8
+ end
9
+
10
+ class Pair < Node
11
+ has_child key: Node
12
+ has_child value: Node
13
+ executed_loc_keys :operator
14
+ end
15
+
16
+ class Hash < Node
17
+ has_extra_children elements: [Pair, Kwsplat]
18
+ executed_loc_keys :begin, :end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module DeepCover
2
+ class Node::Const < Node
3
+ check_completion
4
+ has_child scope: [Node, nil]
5
+ has_child const_name: Symbol
6
+ end
7
+
8
+ class Node::Cbase < Node
9
+ end
10
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'arguments'
2
+
3
+ module DeepCover
4
+ class Node::Def < Node
5
+ check_completion
6
+ has_tracker :method_call
7
+ has_child method_name: Symbol
8
+ has_child signature: Args
9
+ 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
14
+ executed_loc_keys :keyword, :name
15
+
16
+ def children_nodes_in_flow_order
17
+ []
18
+ end
19
+ end
20
+
21
+ class Node::Defs < Node
22
+ check_completion
23
+ has_tracker :method_call
24
+ has_child singleton: Node, rewrite: '(%{node})'
25
+ has_child method_name: Symbol
26
+ has_child signature: Args
27
+ 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
32
+ executed_loc_keys :keyword, :name, :operator
33
+
34
+ def children_nodes_in_flow_order
35
+ [singleton]
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module DeepCover
2
+ class Node::EmptyBody < Node
3
+ def initialize(base_node, parent: raise, index: 0, position: ChildCanBeEmpty.last_empty_position)
4
+ @position = position
5
+ @position = parent.expression.begin if @position == true # Some random position... don't rewrite!
6
+ super(base_node, parent: parent, index: index, base_children: [])
7
+ end
8
+
9
+ def type
10
+ :EmptyBody
11
+ end
12
+
13
+ def loc_hash
14
+ {expression: @position}
15
+ end
16
+
17
+ def is_statement
18
+ false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'variables'
2
+ require_relative 'collections'
3
+
4
+ module DeepCover
5
+ class Node
6
+ class Resbody < Node
7
+ has_tracker :entered_body
8
+ has_child exception: [Node::Array, nil]
9
+ has_child assignment: [Lvasgn, nil], flow_entry_count: :entered_body_tracker_hits
10
+ has_child body: Node,
11
+ can_be_empty: -> { base_node.loc.expression.succ },
12
+ flow_entry_count: :entered_body_tracker_hits,
13
+ is_statement: true,
14
+ rewrite: '((%{entered_body_tracker};%{local}=nil;%{node}))'
15
+
16
+ def is_statement
17
+ false
18
+ end
19
+
20
+ def execution_count
21
+ entered_body_tracker_hits
22
+ end
23
+ end
24
+
25
+ class Rescue < Node
26
+ has_child watched_body: Node,
27
+ can_be_empty: -> { base_node.loc.expression.begin },
28
+ is_statement: true
29
+ has_extra_children resbodies: Resbody
30
+ has_child else: Node,
31
+ can_be_empty: -> { base_node.loc.expression.succ },
32
+ flow_entry_count: :execution_count,
33
+ is_statement: true
34
+ executed_loc_keys :else
35
+
36
+ def is_statement
37
+ false
38
+ end
39
+
40
+ def flow_completion_count
41
+ resbodies.map(&:flow_completion_count).inject(0, :+) + self.else.flow_completion_count
42
+ end
43
+
44
+ def execution_count
45
+ watched_body.flow_completion_count
46
+ end
47
+
48
+ def resbodies_flow_entry_count(child)
49
+ prev = child.previous_sibling
50
+
51
+ if prev.equal? watched_body
52
+ prev.flow_entry_count - prev.flow_completion_count
53
+ else # RESBODIES
54
+ # TODO is this okay?
55
+ prev.exception.flow_completion_count - prev.execution_count
56
+ end
57
+ end
58
+ end
59
+
60
+ class Ensure < Node
61
+ has_child body: Node,
62
+ can_be_empty: -> { base_node.loc.expression.begin },
63
+ is_statement: true
64
+ has_child ensure: Node,
65
+ can_be_empty: -> { base_node.loc.expression.succ },
66
+ is_statement: true,
67
+ flow_entry_count: -> { body.flow_entry_count }
68
+
69
+ def flow_completion_count
70
+ body.flow_completion_count
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,36 @@
1
+ require_relative 'branch'
2
+
3
+ module DeepCover
4
+ class Node
5
+ class If < Node
6
+ include Branch
7
+ has_tracker :truthy
8
+ has_child condition: Node, rewrite: '((%{node}) && %{truthy_tracker})'
9
+ has_child true_branch: Node,
10
+ can_be_empty: true,
11
+ executed_loc_keys: -> { :else if style == :unless },
12
+ flow_entry_count: :truthy_tracker_hits,
13
+ is_statement: true
14
+ has_child false_branch: Node,
15
+ can_be_empty: true,
16
+ executed_loc_keys: -> { [:else, :colon] if style != :unless },
17
+ flow_entry_count: -> { condition.flow_completion_count - truthy_tracker_hits },
18
+ is_statement: true
19
+ executed_loc_keys :keyword, :question
20
+
21
+ def branches
22
+ [ true_branch, false_branch ]
23
+ end
24
+
25
+ def execution_count
26
+ condition.flow_completion_count
27
+ end
28
+
29
+ # returns on of %i[ternary if unless elsif]
30
+ def style
31
+ keyword = loc_hash[:keyword]
32
+ keyword ? keyword.source.to_sym : :ternary
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,84 @@
1
+ require_relative 'variables'
2
+ require_relative 'literals'
3
+
4
+ module DeepCover
5
+ class Node
6
+ class Kwbegin < Node
7
+ has_extra_children instructions: Node,
8
+ is_statement: true
9
+
10
+ def is_statement
11
+ false
12
+ end
13
+ end
14
+
15
+ class Return < Node
16
+ has_extra_children values: Node
17
+ # TODO
18
+ end
19
+
20
+ class Super < Node
21
+ check_completion
22
+ has_extra_children arguments: Node
23
+ # TODO
24
+ end
25
+ Zsuper = Super # Zsuper is super with no parenthesis (same arguments as caller)
26
+
27
+ class Yield < Node
28
+ has_extra_children arguments: Node
29
+ # TODO
30
+ end
31
+
32
+ class Break < Node
33
+ has_extra_children arguments: Node
34
+ # TODO Anything special needed for the arguments?
35
+
36
+ def flow_completion_count
37
+ 0
38
+ end
39
+ end
40
+
41
+ class Next < Node
42
+ has_extra_children arguments: Node
43
+ # TODO Anything special needed for the arguments?
44
+
45
+ def flow_completion_count
46
+ 0
47
+ end
48
+ end
49
+
50
+ class Alias < Node
51
+ check_completion
52
+ has_child alias: [Sym, Dsym, Gvar, BackRef]
53
+ has_child original: [Sym, Dsym, Gvar, BackRef]
54
+ # TODO: test
55
+ end
56
+
57
+ class NeverEvaluated < Node
58
+ has_extra_children whatever: [:any], remap: {Parser::AST::Node => NeverEvaluated}
59
+
60
+ def executable?
61
+ false
62
+ end
63
+ end
64
+
65
+ class Defined < Node
66
+ has_child code: {Parser::AST::Node => NeverEvaluated}
67
+ # TODO: test
68
+ end
69
+
70
+ class Undef < Node
71
+ check_completion
72
+ has_extra_children arguments: [Sym, Dsym]
73
+ # TODO: test
74
+ end
75
+
76
+ class Return < Node
77
+ include ExecutedAfterChildren
78
+
79
+ def flow_completion_count
80
+ 0
81
+ end
82
+ end
83
+ end
84
+ end