deep-cover 0.1.1 → 0.1.2

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