mutant 0.11.7 → 0.11.10

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
  SHA256:
3
- metadata.gz: 528f60da9e74733ccadd735e902e4cbb0110c9bda457eb53e9338196ef668f0d
4
- data.tar.gz: 440f31b09c0645f17aa9a97e1b0ee3849afa21aa1f294c230fbc1b8b3ee38e65
3
+ metadata.gz: 163279d053e71f375fc6854b89e1ca0730d7de6a1cf883772097a635067fdc92
4
+ data.tar.gz: c943e8ad5544a90d967ac9c580557a1e41997de4a2363cffe829710f0a71c8ae
5
5
  SHA512:
6
- metadata.gz: bb351a02f90e45871181af56c4e2288373c39aea7f158d10e19562f10a4d5447d2142a1dff49934fef08ec8e59754959aec560e1ebfa970bfa2ed15686f14982
7
- data.tar.gz: e060943a2504bad9a542d3eb6b927e6ca7cf86a79244d1179386f7074c78e4fbfb1a97890d371d79a7298138610b84c1ec75e04a0cf9cbeb146a176b8657c6bd
6
+ metadata.gz: 1a130b60a8e53fb84d6b95897bc2749007df58d114b8201ac409eb40f203ee9f90804df51f49083c345784d420335eaeaa884299e0c1d37634be6d72875b5580
7
+ data.tar.gz: 18845045b045a1692c5574c092f7035560cab6267a8bd2a904266a69919630df59a47e0cc0d6edfc32717c834824b1b8d698da979aa7480359d363c1df9f1c1f
@@ -19,7 +19,7 @@ module Mutant
19
19
  #
20
20
  # @return [Boolean]
21
21
  def used?
22
- !name.to_s.start_with?(UNDERSCORE)
22
+ !name.start_with?(UNDERSCORE)
23
23
  end
24
24
  end # Optarg
25
25
 
@@ -36,7 +36,6 @@ module Mutant
36
36
  class ASTToExpression < Transformer::ASTToExpression
37
37
  include LookupTable
38
38
 
39
- # rubocop:disable Metrics/BlockLength
40
39
  properties = ::Regexp::Syntax
41
40
  .version_class("ruby/#{RUBY_VERSION}")
42
41
  .features.fetch(:property)
@@ -44,14 +43,8 @@ module Mutant
44
43
  property_specifier = "\\p{#{property}}"
45
44
  non_property_specifier = "\\P{#{property}}"
46
45
 
47
- begin
48
- property_regex = /#{property_specifier}/
49
- non_property_regex = /#{non_property_specifier}/
50
- # This is probably a regexp_parser bug, ignoring registration of that property
51
- # See: https://github.com/ammar/regexp_parser/issues/84
52
- rescue RegexpError
53
- next
54
- end
46
+ property_regex = /#{property_specifier}/
47
+ non_property_regex = /#{non_property_specifier}/
55
48
 
56
49
  [
57
50
  [
@@ -73,8 +66,7 @@ module Mutant
73
66
  ::Regexp::Parser.parse(non_property_regex).expressions.first.class
74
67
  ]
75
68
  ]
76
- end.compact
77
- # rubocop:enable Metrics/BlockLength
69
+ end
78
70
 
79
71
  # rubocop:disable Layout/LineLength
80
72
  TABLE = Table.create(
@@ -45,7 +45,7 @@ module Mutant
45
45
  end
46
46
 
47
47
  def metaclass_containing(node)
48
- AST::FindMetaclassContaining.call(ast, node)
48
+ AST::FindMetaclassContaining.call(ast.node, node)
49
49
  end
50
50
 
51
51
  def line?(node)
@@ -99,6 +99,7 @@ module Mutant
99
99
  node = matched_node_path.last || return
100
100
 
101
101
  self.class::SUBJECT_CLASS.new(
102
+ config: Subject::Config.parse(ast.comment_associations.fetch(node, [])),
102
103
  context: context,
103
104
  node: node,
104
105
  visibility: visibility
@@ -106,7 +107,7 @@ module Mutant
106
107
  end
107
108
 
108
109
  def matched_node_path
109
- AST.find_last_path(ast, &method(:match?))
110
+ AST.find_last_path(ast.node, &method(:match?))
110
111
  end
111
112
  memoize :matched_node_path
112
113
 
@@ -85,9 +85,9 @@ module Mutant
85
85
 
86
86
  MESSAGE = <<~'MESSAGE'
87
87
  Caught an exception while accessing a method with
88
- #instance_method that is part of #{public,privat,protected}_instance_methods.
88
+ #instance_method that is part of #{public,private,protected}_instance_methods.
89
89
 
90
- This is a bug in your ruby implementation its stdlib, libaries our your code.
90
+ This is a bug in your ruby implementation, its stdlib, your dependencies, or your code.
91
91
 
92
92
  Mutant will ignore this method:
93
93
 
@@ -26,7 +26,7 @@ module Mutant
26
26
  end
27
27
 
28
28
  def self.allowed_subject?(config, subject)
29
- select_subject?(config, subject) && !ignore_subject?(config, subject)
29
+ select_subject?(config, subject) && !ignore_subject?(config, subject) && !subject.inline_disabled?
30
30
  end
31
31
  private_class_method :allowed_subject?
32
32
 
@@ -24,7 +24,7 @@ module Mutant
24
24
  end
25
25
 
26
26
  def skip?
27
- name.to_s.start_with?(UNDERSCORE)
27
+ name.start_with?(UNDERSCORE)
28
28
  end
29
29
 
30
30
  # Mutator for optional arguments
@@ -16,6 +16,7 @@ module Mutant
16
16
  emit_argument_presence
17
17
  emit_argument_mutations
18
18
  emit_mlhs_expansion
19
+ emit_procarg0_removal
19
20
  end
20
21
 
21
22
  def emit_argument_presence
@@ -75,6 +76,13 @@ module Mutant
75
76
  end
76
77
  end
77
78
 
79
+ def emit_procarg0_removal
80
+ return unless children.one? && n_procarg0?((procarg0 = Mutant::Util.one(children)))
81
+
82
+ arguments = procarg0.children
83
+ emit_type(*arguments) if arguments.count > 1
84
+ end
85
+
78
86
  end # Arguments
79
87
  end # Node
80
88
  end # Mutator
@@ -26,7 +26,9 @@ module Mutant
26
26
 
27
27
  return unless body
28
28
  emit(body) unless body_has_control?
29
- emit_body_mutations
29
+ emit_body_mutations do |node|
30
+ !(n_nil?(node) && unconditional_loop?)
31
+ end
30
32
 
31
33
  mutate_body_receiver
32
34
  end
@@ -6,7 +6,7 @@ module Mutant
6
6
  # Mutator for dynamic literals
7
7
  class DynamicLiteral < self
8
8
 
9
- handle(:dstr, :dsym)
9
+ handle(:dstr, :dsym, :xstr)
10
10
 
11
11
  private
12
12
 
@@ -7,14 +7,10 @@ module Mutant
7
7
 
8
8
  handle :procarg0
9
9
 
10
- children :argument
11
-
12
10
  private
13
11
 
14
12
  def dispatch
15
- name = Mutant::Util.one(argument.children)
16
-
17
- emit_type(s(:arg, :"_#{name}")) unless name.to_s.start_with?('_')
13
+ children.each_index(&method(:mutate_child))
18
14
  end
19
15
  end # ProcargZero
20
16
  end # Node
@@ -8,25 +8,25 @@ module Mutant
8
8
  class NamedGroup < Node
9
9
  handle(:regexp_named_group)
10
10
 
11
- children :name, :group
11
+ children :name
12
12
 
13
13
  private
14
14
 
15
15
  def dispatch
16
- return unless group
16
+ return if remaining_children.empty?
17
17
 
18
- emit_group_mutations
18
+ remaining_children_indices.each(&method(:mutate_child))
19
19
 
20
20
  # Allows unused captures to be kept and named if they are explicitly prefixed with an
21
21
  # underscore, like we allow with unused local variables.
22
22
  return if name_underscored?
23
23
 
24
- emit(s(:regexp_passive_group, group))
24
+ emit(s(:regexp_passive_group, *remaining_children))
25
25
  emit_name_underscore_mutation
26
26
  end
27
27
 
28
28
  def emit_name_underscore_mutation
29
- emit_type("_#{name}", group)
29
+ emit_type("_#{name}", *remaining_children)
30
30
  end
31
31
 
32
32
  def name_underscored?
@@ -4,7 +4,7 @@ module Mutant
4
4
  module Parallel
5
5
  # Driver for parallelized execution
6
6
  class Driver
7
- include Adamantium, Anima.new(
7
+ include Anima.new(
8
8
  :threads,
9
9
  :var_active_jobs,
10
10
  :var_final,
@@ -16,6 +16,11 @@ module Mutant
16
16
 
17
17
  private(*anima.attribute_names)
18
18
 
19
+ def initialize(**attributes)
20
+ @alive = true
21
+ super
22
+ end
23
+
19
24
  # Wait for computation to finish, with timeout
20
25
  #
21
26
  # @param [Float] timeout
@@ -23,11 +28,22 @@ module Mutant
23
28
  # @return [Variable::Result<Sink#status>]
24
29
  # current status
25
30
  def wait_timeout(timeout)
26
- var_final.take_timeout(timeout)
31
+ var_final.take_timeout(timeout) if @alive
27
32
 
28
33
  finalize(status)
29
34
  end
30
35
 
36
+ # Stop parallel computation
37
+ #
38
+ # This will cause all work to be immediately stopped.
39
+ #
40
+ # @return [self]
41
+ def stop
42
+ @alive = false
43
+ threads.each(&:kill)
44
+ self
45
+ end
46
+
31
47
  private
32
48
 
33
49
  def finalize(status)
data/lib/mutant/parser.rb CHANGED
@@ -5,6 +5,13 @@ module Mutant
5
5
  class Parser
6
6
  include Adamantium, Equalizer.new
7
7
 
8
+ class AST
9
+ include Anima.new(
10
+ :node,
11
+ :comment_associations
12
+ )
13
+ end
14
+
8
15
  # Initialize object
9
16
  #
10
17
  # @return [undefined]
@@ -18,7 +25,18 @@ module Mutant
18
25
  #
19
26
  # @return [AST::Node]
20
27
  def call(path)
21
- @cache[path] ||= Unparser.parse(path.read)
28
+ @cache[path] ||= parse(path.read)
29
+ end
30
+
31
+ private
32
+
33
+ def parse(source)
34
+ node, comments = Unparser.parse_with_comments(source)
35
+
36
+ AST.new(
37
+ node: node,
38
+ comment_associations: ::Parser::Source::Comment.associate_by_identity(node, comments)
39
+ )
22
40
  end
23
41
 
24
42
  end # Parser
data/lib/mutant/runner.rb CHANGED
@@ -25,6 +25,10 @@ module Mutant
25
25
  private_class_method :run_mutation_analysis
26
26
 
27
27
  def self.run_driver(reporter, driver)
28
+ Signal.trap('INT') do
29
+ driver.stop
30
+ end
31
+
28
32
  loop do
29
33
  status = driver.wait_timeout(reporter.delay)
30
34
  break status.payload if status.done?
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Subject
5
+ class Config
6
+ include Adamantium, Anima.new(:inline_disable)
7
+
8
+ DEFAULT = new(inline_disable: false)
9
+
10
+ DISABLE_REGEXP = /(\s|^)mutant:disable(?:\s|$)/.freeze
11
+ SYNTAX_REGEXP = /\A(?:#|=begin\n)/.freeze
12
+
13
+ def self.parse(comments)
14
+ new(
15
+ inline_disable: comments.any? { |comment| DISABLE_REGEXP.match?(comment_body(comment)) }
16
+ )
17
+ end
18
+
19
+ def self.comment_body(comment)
20
+ comment.text.sub(SYNTAX_REGEXP, '')
21
+ end
22
+ private_class_method :comment_body
23
+ end # Config
24
+ end # Subject
25
+ end # Mutant
@@ -4,7 +4,7 @@ module Mutant
4
4
  # Subject of a mutation
5
5
  class Subject
6
6
  include AbstractType, Adamantium, Enumerable
7
- include Anima.new(:context, :node)
7
+ include Anima.new(:config, :context, :node)
8
8
 
9
9
  # Mutations for this subject
10
10
  #
@@ -19,6 +19,10 @@ module Mutant
19
19
  end
20
20
  memoize :mutations
21
21
 
22
+ def inline_disabled?
23
+ config.inline_disable
24
+ end
25
+
22
26
  # Source path
23
27
  #
24
28
  # @return [Pathname]
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.7'
5
+ VERSION = '0.11.10'
6
6
  end # Mutant
data/lib/mutant.rb CHANGED
@@ -164,6 +164,7 @@ require 'mutant/loader'
164
164
  require 'mutant/context'
165
165
  require 'mutant/scope'
166
166
  require 'mutant/subject'
167
+ require 'mutant/subject/config'
167
168
  require 'mutant/subject/method'
168
169
  require 'mutant/subject/method/instance'
169
170
  require 'mutant/subject/method/singleton'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.7
4
+ version: 0.11.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-24 00:00:00.000000000 Z
11
+ date: 2022-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -45,6 +45,9 @@ dependencies:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '2.3'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.3.1
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
@@ -52,6 +55,9 @@ dependencies:
52
55
  - - "~>"
53
56
  - !ruby/object:Gem::Version
54
57
  version: '2.3'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.3.1
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: sorbet-runtime
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -347,6 +353,7 @@ files:
347
353
  - lib/mutant/selector/expression.rb
348
354
  - lib/mutant/selector/null.rb
349
355
  - lib/mutant/subject.rb
356
+ - lib/mutant/subject/config.rb
350
357
  - lib/mutant/subject/method.rb
351
358
  - lib/mutant/subject/method/instance.rb
352
359
  - lib/mutant/subject/method/metaclass.rb
@@ -379,7 +386,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
379
386
  - !ruby/object:Gem::Version
380
387
  version: '0'
381
388
  requirements: []
382
- rubygems_version: 3.3.7
389
+ rubygems_version: 3.1.6
383
390
  signing_key:
384
391
  specification_version: 4
385
392
  summary: ''