deep-cover 0.1.1 → 0.1.2

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +3 -1
  4. data/Rakefile +1 -1
  5. data/bin/selfcov +1 -1
  6. data/deep_cover.gemspec +2 -1
  7. data/lib/deep_cover/analyser.rb +1 -2
  8. data/lib/deep_cover/analyser/base.rb +20 -6
  9. data/lib/deep_cover/analyser/covered_code_source.rb +0 -12
  10. data/lib/deep_cover/analyser/node.rb +11 -1
  11. data/lib/deep_cover/analyser/optionally_covered.rb +14 -0
  12. data/lib/deep_cover/auto_run.rb +36 -32
  13. data/lib/deep_cover/backports.rb +9 -0
  14. data/lib/deep_cover/base.rb +8 -1
  15. data/lib/deep_cover/cli/debugger.rb +6 -4
  16. data/lib/deep_cover/cli/deep_cover.rb +37 -6
  17. data/lib/deep_cover/cli/instrumented_clone_reporter.rb +50 -32
  18. data/lib/deep_cover/config.rb +16 -7
  19. data/lib/deep_cover/coverage.rb +8 -9
  20. data/lib/deep_cover/covered_code.rb +17 -18
  21. data/lib/deep_cover/node/base.rb +28 -4
  22. data/lib/deep_cover/node/branch.rb +10 -7
  23. data/lib/deep_cover/node/def.rb +2 -2
  24. data/lib/deep_cover/node/empty_body.rb +1 -1
  25. data/lib/deep_cover/node/mixin/can_augment_children.rb +1 -2
  26. data/lib/deep_cover/node/mixin/execution_location.rb +9 -6
  27. data/lib/deep_cover/node/mixin/has_child.rb +16 -17
  28. data/lib/deep_cover/node/mixin/has_tracker.rb +2 -6
  29. data/lib/deep_cover/node/mixin/rewriting.rb +9 -8
  30. data/lib/deep_cover/node/send.rb +57 -48
  31. data/lib/deep_cover/node/{boolean.rb → short_circuit.rb} +0 -0
  32. data/lib/deep_cover/reporter/istanbul.rb +2 -3
  33. data/lib/deep_cover/tools.rb +2 -1
  34. data/lib/deep_cover/tools/dasherize.rb +8 -0
  35. data/lib/deep_cover/tools/dump_covered_code.rb +12 -6
  36. data/lib/deep_cover/tools/format_char_cover.rb +2 -3
  37. data/lib/deep_cover/tools/slice.rb +7 -0
  38. data/lib/deep_cover/version.rb +1 -1
  39. metadata +7 -18
@@ -13,19 +13,20 @@ module DeepCover
13
13
  def rewrite_child(child, name=nil)
14
14
  end
15
15
 
16
+ # Replaces all the '%{local}' or '%{some_tracker}' in rewriting rules
16
17
  def resolve_rewrite(rule, context)
17
- rule ||= '%{node}'
18
+ return if rule == nil
18
19
  sources = context.tracker_sources
19
- rule.split('%{node}').map{|s| s % {local: covered_code.local_var, **sources} }
20
+ rule % {local: covered_code.local_var, node: '%{node}', **sources}
20
21
  end
21
22
 
22
- def rewrite_prefix_suffix
23
- parent_prefix, parent_suffix = resolve_rewrite(parent.rewrite_child(self), parent)
24
- prefix, suffix = resolve_rewrite(rewrite, self)
23
+ # Returns an array of [range, rule], where rule is a string containing '%{node}'
24
+ # Rules must be ordered inner-most first
25
+ def rewriting_rules
25
26
  [
26
- "#{parent_prefix}#{prefix}",
27
- "#{suffix}#{parent_suffix}"
28
- ]
27
+ resolve_rewrite(rewrite, self),
28
+ resolve_rewrite(parent.rewrite_child(self), parent),
29
+ ].compact.map{|rule| [expression, rule]}
29
30
  end
30
31
  end
31
32
  end
@@ -1,75 +1,84 @@
1
1
  require_relative 'literals'
2
+ require_relative 'branch'
2
3
 
3
4
  module DeepCover
4
5
  class Node
5
- class MethodName < Node
6
- has_child name: Symbol
7
-
8
- def initialize(name, parent: raise, **kwargs)
9
- super(parent, **kwargs, parent: parent, base_children: [name])
10
- end
11
-
12
- def loc_hash
13
- # Expression is used in the rewriting
14
- # if selector_end is present, then this won't be needed
15
- {expression: parent.loc_hash[:selector_begin]}
16
- end
17
-
18
- def executable?
19
- false
20
- end
21
- end
22
-
23
6
  class Send < Node
24
7
  check_completion
25
8
  has_child receiver: [Node, nil]
26
- has_child method_name_wrapper: {Symbol => MethodName}, rewrite: :add_opening_parentheses
27
- has_extra_children arguments: Node, rewrite: :add_closing_parentheses
9
+ has_child message: Symbol
10
+ has_extra_children arguments: Node
28
11
  executed_loc_keys :dot, :selector_begin, :selector_end, :operator
29
12
 
30
- def method_name
31
- method_name_wrapper.name
32
- end
33
-
34
13
  def loc_hash
35
- base = super
36
- hash = { expression: base[:expression], begin: base[:begin], end: base[:end], dot: base[:dot]}
37
- selector = base[:selector]
14
+ hash = super.dup
15
+ selector = hash.delete(:selector)
38
16
 
39
- if [:[], :[]=].include?(method_name)
17
+ # Special case for foo[bar]=baz, but not for foo.[]= bar, baz: we split selector into begin and end
18
+ if base_node.location.dot == nil && [:[], :[]=].include?(message)
40
19
  hash[:selector_begin] = selector.resize(1)
41
20
  hash[:selector_end] = Parser::Source::Range.new(selector.source_buffer, selector.end_pos - 1, selector.end_pos)
42
21
  else
43
- hash[:selector_begin] = base[:selector]
22
+ hash.delete(:dot) if type == :safe_send # Hack. API to get a Parser::AST::Send::Map without the dot is crappy.
23
+ hash[:selector_begin] = selector
44
24
  end
45
25
 
46
26
  hash
47
27
  end
48
28
 
29
+ # Rules must be ordered inner-most first
30
+ def rewriting_rules
31
+ rules = super
32
+ if need_parentheses?
33
+ range = arguments.last.expression.with(begin_pos: loc_hash[:selector_begin].end_pos)
34
+ rules.unshift [range, '(%{node})']
35
+ end
36
+ rules
37
+ end
38
+
39
+ private
40
+
49
41
  # Only need to add them to deal with ambiguous cases where a method is hidden by a local. Ex:
50
- # raise TypeError, 'hello' #=> Works
51
- # raise (TypeError), 'hello' #=> Simplification of what DeepCover generates, still works
52
- # raise = 1; raise TypeError, 'hello' #=> works
53
- # raise = 1; raise (TypeError), 'hello' #=> syntax error.
54
- # raise = 1; raise((TypeError), 'hello'0 #=> works
55
- def add_parentheses?
56
- return if arguments.empty?
57
- # No ambiguity if there is a receiver
58
- return if receiver
59
- # Already has parentheses
60
- return if self.loc_hash[:begin]
61
- true
42
+ # foo 42, 'hello' #=> Works
43
+ # foo (42), 'hello' #=> Simplification of what DeepCover would generate, still works
44
+ # foo = 1; foo 42, 'hello' #=> works
45
+ # foo = 1; foo (42), 'hello' #=> syntax error.
46
+ # foo = 1; foo((42), 'hello') #=> works
47
+ def need_parentheses?
48
+ true unless
49
+ arguments.empty? || # No issue when no arguments
50
+ receiver || # No ambiguity if there is a receiver
51
+ loc_hash[:begin] # Ok if has parentheses
62
52
  end
53
+ end
54
+
55
+ class Csend < Node
56
+ include Branch
57
+ has_tracker :conditional
58
+ has_child receiver: Node,
59
+ rewrite: '(%{local}=%{node};%{conditional_tracker} if %{local} != nil;%{local})'
60
+
61
+ has_child actual_send: {safe_send: Send},
62
+ flow_entry_count: :conditional_tracker_hits
63
+
64
+ def initialize(base_node, base_children: base_node.children, **)
65
+ send_without_receiver = base_node.updated(:safe_send, [nil, *base_node.children.drop(1)])
66
+ base_children = [base_children.first, send_without_receiver]
67
+ super
68
+ end
69
+
70
+ executed_loc_keys :dot
71
+
72
+ alias_method :execution_count, :flow_entry_count
63
73
 
64
- def add_opening_parentheses
65
- return unless add_parentheses?
66
- "%{node}("
74
+ def message
75
+ actual_send.message
67
76
  end
68
77
 
69
- def add_closing_parentheses(child)
70
- return unless add_parentheses?
71
- return unless child.index == children.size - 1
72
- "%{node})"
78
+ def branches
79
+ [ actual_send,
80
+ TrivialBranch.new(receiver, actual_send)
81
+ ]
73
82
  end
74
83
  end
75
84
 
@@ -46,12 +46,11 @@ module DeepCover
46
46
 
47
47
  def convert_branch(node, branches = node.branches)
48
48
  # Currently, nyc seems to outputs the same location over and over...
49
- loc = convert_range(node.expression)
50
49
  {
51
- loc: loc,
50
+ loc: convert_range(node.expression),
52
51
  type: node.type,
53
52
  line: node.expression.line,
54
- locations: branches.map{|n| loc}
53
+ locations: branches.map{|n| convert_range(n.expression || node.expression)}
55
54
  }
56
55
  end
57
56
 
@@ -3,8 +3,9 @@ module DeepCover
3
3
 
4
4
  require_relative 'tools/require_relative_dir'
5
5
  extend Tools::RequireRelativeDir
6
- require_relative_dir 'tools'
6
+ require_relative 'tools/silence_warnings'
7
7
  extend Tools::SilenceWarnings
8
+ require_relative_dir 'tools'
8
9
 
9
10
  # The functions defined in the submodules of Tools can be accessed
10
11
  # either by extending the desired module, or all of them by extending
@@ -0,0 +1,8 @@
1
+ module DeepCover
2
+ module Tools::Dasherize
3
+ # Poor man's dasherize. 'an_example' => 'an-example'
4
+ def dasherize(string)
5
+ string.to_s.gsub('_', '-')
6
+ end
7
+ end
8
+ end
@@ -1,20 +1,27 @@
1
- require 'with_progress'
2
-
3
1
  module DeepCover
2
+ silence_warnings do
3
+ require 'with_progress'
4
+ end
4
5
  module Tools::DumpCoveredCode
5
- def dump_covered_code(source_path, dest_path = Dir.mktmpdir)
6
+ def dump_covered_code_and_save(source_path, dest_path: Dir.mktmpdir)
6
7
  coverage = Coverage.new(tracker_global: '$_sc')
8
+ dump_covered_code(source_path, coverage: coverage, dest_path: dest_path)
9
+ coverage.save(dest_path)
10
+ end
11
+
12
+ def dump_covered_code(source_path, coverage: raise, dest_path: Dir.mktmpdir, root_path: source_path)
7
13
  source_path = File.join(File.expand_path(source_path), '')
8
14
  dest_path = File.join(File.expand_path(dest_path), '')
15
+ root_path = Pathname.new(root_path)
9
16
  skipped = []
10
17
  Dir.glob("#{source_path}**/*.rb").each.with_progress(title: 'Rewriting') do |path|
18
+ new_path = Pathname(path.gsub(source_path, dest_path))
11
19
  begin
12
- covered_code = coverage.covered_code(path)
20
+ covered_code = coverage.covered_code(path, name: new_path.relative_path_from(root_path))
13
21
  rescue Parser::SyntaxError
14
22
  skipped << path
15
23
  next
16
24
  end
17
- new_path = Pathname(path.gsub(source_path, dest_path))
18
25
  new_path.dirname.mkpath
19
26
  new_path.write(covered_code.covered_source)
20
27
  end
@@ -25,7 +32,6 @@ module DeepCover
25
32
  ('...' if skipped.size > 3),
26
33
  ].compact.join("\n")
27
34
  end
28
- coverage.save(dest_path)
29
35
  dest_path
30
36
  end
31
37
  end
@@ -2,9 +2,8 @@ module DeepCover
2
2
  module Tools::FormatCharCover
3
3
  COLOR = {'x' => :red, ' ' => :green, '-' => :faint}
4
4
  WHITESPACE_MAP = Hash.new{|_, v| v}.merge!(' ' => '·', "\t" => '→ ')
5
- def format_char_cover(covered_code, show_whitespace: false)
6
- bc = covered_code.char_cover
7
-
5
+ def format_char_cover(covered_code, show_whitespace: false, **options)
6
+ bc = covered_code.char_cover(**options)
8
7
  covered_code.buffer.source_lines.map.with_index do |line, line_index|
9
8
  next line if line.strip =~ /^#[ >]/
10
9
  line.chars.map.with_index do |c, c_index|
@@ -0,0 +1,7 @@
1
+ module DeepCover
2
+ module Tools::Slice
3
+ def slice(hash, *keys)
4
+ keys.each_with_object(Hash.new) { |k, h| h[k] = hash[k] if hash.has_key?(k) }
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module DeepCover
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
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.1
4
+ version: 0.1.2
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-10-27 00:00:00.000000000 Z
12
+ date: 2017-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parser
@@ -81,20 +81,6 @@ dependencies:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
- - !ruby/object:Gem::Dependency
85
- name: ruby-progressbar
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - "<"
89
- - !ruby/object:Gem::Version
90
- version: 1.9.0
91
- type: :runtime
92
- prerelease: false
93
- version_requirements: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "<"
96
- - !ruby/object:Gem::Version
97
- version: 1.9.0
98
84
  - !ruby/object:Gem::Dependency
99
85
  name: with_progress
100
86
  requirement: !ruby/object:Gem::Requirement
@@ -228,6 +214,7 @@ files:
228
214
  - lib/deep_cover/analyser/function.rb
229
215
  - lib/deep_cover/analyser/ignore_uncovered.rb
230
216
  - lib/deep_cover/analyser/node.rb
217
+ - lib/deep_cover/analyser/optionally_covered.rb
231
218
  - lib/deep_cover/analyser/per_char.rb
232
219
  - lib/deep_cover/analyser/per_line.rb
233
220
  - lib/deep_cover/analyser/statement.rb
@@ -254,7 +241,6 @@ files:
254
241
  - lib/deep_cover/node/base.rb
255
242
  - lib/deep_cover/node/begin.rb
256
243
  - lib/deep_cover/node/block.rb
257
- - lib/deep_cover/node/boolean.rb
258
244
  - lib/deep_cover/node/branch.rb
259
245
  - lib/deep_cover/node/case.rb
260
246
  - lib/deep_cover/node/collections.rb
@@ -281,6 +267,7 @@ files:
281
267
  - lib/deep_cover/node/module.rb
282
268
  - lib/deep_cover/node/root.rb
283
269
  - lib/deep_cover/node/send.rb
270
+ - lib/deep_cover/node/short_circuit.rb
284
271
  - lib/deep_cover/node/splat.rb
285
272
  - lib/deep_cover/node/variables.rb
286
273
  - lib/deep_cover/parser_ext/range.rb
@@ -289,6 +276,7 @@ files:
289
276
  - lib/deep_cover/tools.rb
290
277
  - lib/deep_cover/tools/builtin_coverage.rb
291
278
  - lib/deep_cover/tools/camelize.rb
279
+ - lib/deep_cover/tools/dasherize.rb
292
280
  - lib/deep_cover/tools/dump_covered_code.rb
293
281
  - lib/deep_cover/tools/execute_sample.rb
294
282
  - lib/deep_cover/tools/format.rb
@@ -298,6 +286,7 @@ files:
298
286
  - lib/deep_cover/tools/our_coverage.rb
299
287
  - lib/deep_cover/tools/require_relative_dir.rb
300
288
  - lib/deep_cover/tools/silence_warnings.rb
289
+ - lib/deep_cover/tools/slice.rb
301
290
  - lib/deep_cover/version.rb
302
291
  homepage: http://github.com
303
292
  licenses:
@@ -311,7 +300,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
311
300
  requirements:
312
301
  - - ">="
313
302
  - !ruby/object:Gem::Version
314
- version: '0'
303
+ version: 2.0.0
315
304
  required_rubygems_version: !ruby/object:Gem::Requirement
316
305
  requirements:
317
306
  - - ">="