mutant 0.11.7 → 0.11.10

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.
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: ''