deep-cover 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 23dab9f10f66926115fc7a84107eaaa364ea232f
4
- data.tar.gz: a5e5a3e0d3b39829928acd724702f306282d03b4
3
+ metadata.gz: cd810c9ed86848f16da708afa29617606737f5d5
4
+ data.tar.gz: fa5f6561e9b952e24f43fa7b06eed8c2a21bd0d4
5
5
  SHA512:
6
- metadata.gz: 746c9f0d6ee8bd832e2629d37996050f309bcc7724be618f72da0c3851705b714f6c56b458bc4727bdb5b7fe62f64eda6b99f61e6ca21e306b3ed8f339a526c5
7
- data.tar.gz: 3aa28c66195e1cd61bfeafe38df9caa82e4e5ffd55bf6fdb3b3c4fcee8aa8ac0efb6a369b74c6656954e761e7e5f659aea36d9d25d582049e0d04b92c20a0f4d
6
+ metadata.gz: 4f26c1f20f3268174c55f2b3bfe17dbf42cecf2e70f1456b395006a8d03545e95388cbe0f3fc18b6b38c5c7413b88327f74c2c921fd55ced04771379a01fb6b0
7
+ data.tar.gz: 5b220912488dde079c748c4376c9a94adbfeac5a144f6d27c362eb9ff29fabc28247990354a646aa9f2b6f449d2c4de88f94f8d6dbe86f83181da06bd2389732
data/.gitignore CHANGED
@@ -14,3 +14,4 @@
14
14
  .rspec_status
15
15
  /Gemfile.local
16
16
  /spec/cli_fixtures/covered_trivial_gem/deep_cover/
17
+ /deep_cover
@@ -1,9 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5
4
+
5
+ * Added custom filters
6
+
3
7
  ## 0.4
4
8
 
5
9
  * Added `deep-cover exec`
6
- * Support for # nocov
10
+ * Automatic loading of `.deep-cover.rb`
11
+ * Support for `# nocov`
7
12
 
8
13
  ## 0.3
9
14
 
data/Gemfile CHANGED
@@ -9,5 +9,4 @@ gemspec
9
9
 
10
10
  eval_gemfile 'Gemfile.local' if File.exist?('Gemfile.local')
11
11
 
12
- gem 'parser', git: 'https://github.com/marcandre/parser.git', branch: 'tree_rewriter_release'
13
12
  gem 'ruby-prof', platforms: :mri
data/README.md CHANGED
@@ -145,6 +145,24 @@ The file `.deep-cover.rb` is loaded automatically when requiring `deep-cover` an
145
145
 
146
146
  *Note*: The configuration block is only executed when `deep-cover` is actually started.
147
147
 
148
+ #### Custom filters
149
+
150
+ `deep-cover` comes with a few filters that make it possible to ignore certain uncovered codes.
151
+
152
+ It is easy to add you own filters.
153
+
154
+ For example, if one wants to ignore uncovered calls to `raise` but the code uses `our_custom_raise` instead, the following with work:
155
+
156
+ ```
157
+ DeepCover.configure do
158
+ ignore_uncovered do
159
+ type == :send &&
160
+ receiver == nil &&
161
+ message == :our_custom_raise
162
+ end
163
+ end
164
+ ```
165
+
148
166
  ## Development
149
167
 
150
168
  After checking out the repo, run `bundle` then `rake dev:install` to install dependencies. Then, run `rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  # Main dependency
29
29
  spec.add_runtime_dependency 'parser'
30
+ spec.add_runtime_dependency 'parser_tree_rewriter'
30
31
 
31
32
  # Support
32
33
  spec.add_runtime_dependency 'backports', '>= 3.11.0'
@@ -11,7 +11,7 @@ module DeepCover
11
11
  def initialize(source, ignore_uncovered: [], **options)
12
12
  @cache = {}.compare_by_identity
13
13
  super
14
- @allow_filters = Array(ignore_uncovered).map { |kind| :"is_#{kind}?" }
14
+ @allow_filters = Array(ignore_uncovered).map { |kind| Node.filter_to_method_name(kind) }
15
15
  @nocov_ranges = FlagCommentAssociator.new(covered_code)
16
16
  end
17
17
 
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # We use a few features newer than our target of Ruby 2.1+:
4
+ class Module
5
+ public :define_method
6
+ end
4
7
  require 'pathname'
5
8
  class Pathname
6
9
  def write(*args)
@@ -18,5 +18,5 @@ module DeepCover
18
18
  open: false,
19
19
  }.freeze
20
20
 
21
- OPTIONALLY_COVERED = %i[case_implicit_else default_argument raise trivial_if].freeze
21
+ OPTIONALLY_COVERED = %i[case_implicit_else default_argument raise trivial_if]
22
22
  end
@@ -7,6 +7,21 @@ module DeepCover
7
7
 
8
8
  module CLI
9
9
  end
10
+
11
+ module CLI::SlopExtension
12
+ attr_accessor :stopped
13
+ attr_reader :ignored
14
+
15
+ def try_process(*)
16
+ @ignored ||= 0
17
+ return if stopped
18
+ o = super
19
+ @ignored += 1 unless o
20
+ o
21
+ end
22
+ end
23
+ Slop::Parser.prepend CLI::SlopExtension
24
+
10
25
  module CLI::DeepCover
11
26
  extend self
12
27
 
@@ -53,7 +68,7 @@ module DeepCover
53
68
  [:"ignore_#{option}", option]
54
69
  end.to_h
55
70
 
56
- o.separator '\nWhen not using ’exec’:'
71
+ o.separator "\nWhen not using ’exec’:"
57
72
  o.string '-c', '--command', 'command to run tests', default: CLI_DEFAULTS[:command]
58
73
  o.bool '--bundle', 'run bundle before the tests', default: CLI_DEFAULTS[:bundle]
59
74
  o.bool '--process', 'turn off to only redo the reporting', default: CLI_DEFAULTS[:process]
@@ -69,6 +84,10 @@ module DeepCover
69
84
  exit
70
85
  end
71
86
  o.boolean('-h', '--help')
87
+
88
+ o.boolean('exec', '', help: false) do
89
+ o.parser.stopped = true if o.parser.ignored == 0
90
+ end
72
91
  end
73
92
  end
74
93
 
@@ -83,18 +102,17 @@ module DeepCover
83
102
 
84
103
  def go
85
104
  options = convert_options(menu.to_h)
86
- first, *rest = menu.arguments
87
105
  if options[:help]
88
106
  show_help
89
107
  elsif options[:expression]
90
108
  require_relative 'debugger'
91
109
  CLI::Debugger.new(options[:expression], **options).show
92
- elsif first == 'exec'
110
+ elsif menu.parser.stopped
93
111
  require_relative 'exec'
94
- CLI::Exec.new(rest, **options).run
112
+ CLI::Exec.new(menu.arguments, **options).run
95
113
  else
96
114
  require_relative 'instrumented_clone_reporter'
97
- path = first || '.'
115
+ path = menu.arguments.first || '.'
98
116
  CLI::InstrumentedCloneReporter.new(path, **options).run
99
117
  end
100
118
  end
@@ -12,7 +12,12 @@ module DeepCover
12
12
  end
13
13
  alias_method :to_h, :to_hash
14
14
 
15
- def ignore_uncovered(*keywords)
15
+ def ignore_uncovered(*keywords, &block)
16
+ if block
17
+ raise ArgumentError, "wrong number of arguments (given #{keywords.size}, expected 0..1)" if keywords.size > 1
18
+ keywords << Node.unique_filter if keywords.empty?
19
+ Node.create_filter(keywords.first, &block)
20
+ end
16
21
  if keywords.empty?
17
22
  @options[:ignore_uncovered]
18
23
  else
@@ -22,6 +27,7 @@ module DeepCover
22
27
  end
23
28
 
24
29
  def detect_uncovered(*keywords)
30
+ raise ArgumentError, 'No block is accepted' if block_given?
25
31
  if keywords.empty?
26
32
  OPTIONALLY_COVERED - @options[:ignore_uncovered]
27
33
  else
@@ -2,7 +2,8 @@
2
2
 
3
3
  module DeepCover
4
4
  module Load
5
- AUTOLOAD = %i[analyser autoload_tracker config coverage covered_code custom_requirer
5
+ AUTOLOAD = %i[analyser autoload_tracker auto_run config
6
+ coverage covered_code custom_requirer
6
7
  flag_comment_associator memoize module_override node
7
8
  problem_with_diagnostic reporter
8
9
  ]
@@ -35,6 +36,7 @@ module DeepCover
35
36
  silence_warnings do
36
37
  require 'parser/current'
37
38
  end
39
+ require 'parser_tree_rewriter'
38
40
  require_relative_dir 'parser_ext'
39
41
  @parser_loaded
40
42
  end
@@ -15,6 +15,7 @@ module DeepCover
15
15
  include ExecutionLocation
16
16
  include ChildCanBeEmpty
17
17
  include Filters
18
+ extend Filters::ClassMethods
18
19
 
19
20
  attr_reader :index, :parent, :children, :base_node
20
21
 
@@ -16,7 +16,7 @@ module DeepCover
16
16
  # See https://github.com/jruby/jruby/issues/4804
17
17
  # This is solved in jruby 9.2.0.0, better keep the workaround
18
18
  # for compatibility.
19
- has_child condition: Node, rewrite: '(((%{entry_tracker}) && %{node}))',
19
+ has_child condition: Node, rewrite: '((%{entry_tracker}) && %{node})',
20
20
  flow_entry_count: :entry_tracker_hits
21
21
  executed_loc_keys []
22
22
 
@@ -78,7 +78,7 @@ module DeepCover
78
78
  has_extra_children whens: When
79
79
  has_child else: Node,
80
80
  can_be_empty: -> { base_node.loc.end.begin },
81
- rewrite: -> { "#{'else;' unless has_else?}((%{else_entry_tracker};%{local}=nil;%{node}))" },
81
+ rewrite: -> { "#{'else;' unless has_else?}(%{else_entry_tracker};%{local}=nil;%{node})" },
82
82
  executed_loc_keys: [:else],
83
83
  is_statement: true,
84
84
  flow_entry_count: :else_entry_tracker_hits
@@ -13,7 +13,7 @@ module DeepCover
13
13
  can_be_empty: -> { (base_node.loc.begin || base_node.loc.expression.succ).end },
14
14
  flow_entry_count: :entered_body_tracker_hits,
15
15
  is_statement: true,
16
- rewrite: '((%{entered_body_tracker};%{local}=nil;%{node}))'
16
+ rewrite: '(%{entered_body_tracker};%{local}=nil;%{node})'
17
17
 
18
18
  def is_statement
19
19
  false
@@ -9,7 +9,7 @@ module DeepCover
9
9
  has_child body: Node,
10
10
  can_be_empty: -> { base_node.loc.end.begin },
11
11
  flow_entry_count: :body_tracker_hits,
12
- rewrite: '((%{body_tracker};%{local}=nil;%{node}))'
12
+ rewrite: '(%{body_tracker};%{local}=nil;%{node})'
13
13
  check_completion
14
14
 
15
15
  def execution_count
@@ -3,6 +3,24 @@
3
3
  module DeepCover
4
4
  module Node::Mixin
5
5
  module Filters
6
+ module ClassMethods
7
+ def filter_to_method_name(kind)
8
+ :"is_#{kind}?"
9
+ end
10
+
11
+ def create_filter(name, &block)
12
+ Filters.define_method(filter_to_method_name(name), &block)
13
+ OPTIONALLY_COVERED << name
14
+ end
15
+
16
+ def unique_filter
17
+ (1..Float::INFINITY).each do |i|
18
+ name = :"custom_filter_#{i}"
19
+ return name unless Filters.method_defined?(filter_to_method_name(name))
20
+ end
21
+ end
22
+ end
23
+
6
24
  RAISING_MESSAGES = %i[raise exit].freeze
7
25
  def is_raise?
8
26
  is_a?(Node::Send) && RAISING_MESSAGES.include?(message) && receiver == nil
@@ -9,7 +9,7 @@ module DeepCover
9
9
  has_tracker :conditional
10
10
  has_child lhs: Node
11
11
  has_child conditional: Node, flow_entry_count: :conditional_tracker_hits,
12
- rewrite: '((%{conditional_tracker};%{node}))'
12
+ rewrite: '(%{conditional_tracker};%{node})'
13
13
 
14
14
  def branches
15
15
  [
@@ -34,7 +34,7 @@ module DeepCover
34
34
  # {a: {b: {d: {} } } }]
35
35
  # => {a: {b: {c: {}, d: {} }}}
36
36
  def deep_merge(trees)
37
- trees.inject do |result, h|
37
+ trees.inject({}) do |result, h|
38
38
  result.merge(h) { |k, val, val_b| deep_merge([val, val_b]) }
39
39
  end
40
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeepCover
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  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.4.0
4
+ version: 0.5.0
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: 2018-02-07 00:00:00.000000000 Z
12
+ date: 2018-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parser
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: parser_tree_rewriter
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: backports
30
44
  requirement: !ruby/object:Gem::Requirement