mutant 0.11.4 → 0.11.7

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.
@@ -7,13 +7,13 @@ module Mutant
7
7
  class Run < self
8
8
  NAME = 'run'
9
9
  SHORT_DESCRIPTION = 'Run code analysis'
10
- SLEEP = 60
11
10
  SUBCOMMANDS = EMPTY_ARRAY
12
11
 
13
12
  UNLICENSED = <<~MESSAGE.lines.freeze
14
- Soft fail, continuing in #{SLEEP} seconds
15
- Next major version will enforce the license
16
- See https://github.com/mbj/mutant#licensing
13
+ You are using mutant unlicensed.
14
+
15
+ See https://github.com/mbj/mutant#licensing to aquire a license.
16
+ Note: Its free for opensource use, which is recommended for trials.
17
17
  MESSAGE
18
18
 
19
19
  NO_TESTS_MESSAGE = <<~'MESSAGE'
@@ -40,7 +40,7 @@ module Mutant
40
40
  private
41
41
 
42
42
  def action
43
- soft_fail(License.call(world))
43
+ License.call(world)
44
44
  .bind { bootstrap }
45
45
  .bind(&method(:validate_tests))
46
46
  .bind(&Runner.public_method(:call))
@@ -62,23 +62,6 @@ module Mutant
62
62
  Either::Left.new('Uncovered mutations detected, exiting nonzero!')
63
63
  end
64
64
  end
65
-
66
- def soft_fail(result)
67
- result.either(
68
- lambda do |message|
69
- stderr = world.stderr
70
- stderr.puts(message)
71
- UNLICENSED.each { |line| stderr.puts(unlicensed(line)) }
72
- world.kernel.sleep(SLEEP)
73
- Either::Right.new(nil)
74
- end,
75
- ->(_subscription) { Either::Right.new(nil) }
76
- )
77
- end
78
-
79
- def unlicensed(message)
80
- "[Mutant-License-Error]: #{message}"
81
- end
82
65
  end # Run
83
66
  end # Environment
84
67
  end # Command
@@ -184,9 +184,9 @@ module Mutant
184
184
  end
185
185
 
186
186
  def format_subcommands
187
- commands = subcommands.map do |subcommand|
187
+ commands = subcommands.to_h do |subcommand|
188
188
  [subcommand.command_name, subcommand.short_description]
189
- end.to_h
189
+ end
190
190
 
191
191
  width = commands.each_key.map(&:length).max
192
192
 
data/lib/mutant/env.rb CHANGED
@@ -68,9 +68,9 @@ module Mutant
68
68
  #
69
69
  # @return Hash{Mutation => Enumerable<Test>}
70
70
  def selections
71
- subjects.map do |subject|
71
+ subjects.to_h do |subject|
72
72
  [subject, selector.call(subject)]
73
- end.to_h
73
+ end
74
74
  end
75
75
  memoize :selections
76
76
 
@@ -142,11 +142,10 @@ module Mutant
142
142
  result = mutation.insert(world.kernel)
143
143
  hooks.run(:mutation_insert_post, mutation)
144
144
 
145
- if result.equal?(Loader::Result::VoidValue.instance)
146
- Result::Test::VoidValue.instance
147
- else
148
- integration.call(tests)
149
- end
145
+ result.either(
146
+ ->(_) { Result::Test::VoidValue.instance },
147
+ ->(_) { integration.call(tests) }
148
+ )
150
149
  end
151
150
  end
152
151
 
@@ -36,7 +36,7 @@ module Mutant
36
36
  fail "Unmatched git remote URL: #{input.inspect}"
37
37
  end
38
38
 
39
- new(match[:host], match[:path])
39
+ new(match[:host], match[:path].downcase)
40
40
  end
41
41
  private_class_method :parse_url
42
42
  end
data/lib/mutant/loader.rb CHANGED
@@ -9,17 +9,8 @@ module Mutant
9
9
 
10
10
  private_constant(*constants(false))
11
11
 
12
- class Result
13
- include Singleton
14
-
15
- # Vale returned on successful load
16
- class Success < self
17
- end # Success
18
-
19
- # Vale returned on MRI detecting void value expressions
20
- class VoidValue < self
21
- end # VoidValue
22
- end # Result
12
+ VOID_VALUE = Either::Left.new(nil)
13
+ SUCCESS = Either::Right.new(nil)
23
14
 
24
15
  # Call loader
25
16
  #
@@ -45,12 +36,12 @@ module Mutant
45
36
  rescue SyntaxError => exception
46
37
  # rubocop:disable Style/GuardClause
47
38
  if VOID_VALUE_REGEXP.match?(exception.message)
48
- Result::VoidValue.instance
39
+ VOID_VALUE
49
40
  else
50
41
  raise
51
42
  end
52
43
  else
53
- Result::Success.instance
44
+ SUCCESS
54
45
  end
55
46
  end # Loader
56
47
  end # Mutant
@@ -25,7 +25,7 @@ module Mutant
25
25
 
26
26
  private_constant(*constants(false))
27
27
 
28
- DEFAULT = new(anima.attribute_names.map { |name| [name, []] }.to_h)
28
+ DEFAULT = new(anima.attribute_names.to_h { |name| [name, []] })
29
29
 
30
30
  expression = Transform::Block.capture(:expression) do |input|
31
31
  Mutant::Config::DEFAULT.expression_parser.call(input)
@@ -74,8 +74,7 @@ module Mutant
74
74
  def merge(other)
75
75
  self.class.new(
76
76
  to_h
77
- .map { |name, value| [name, value + other.public_send(name)] }
78
- .to_h
77
+ .to_h { |name, value| [name, value + other.public_send(name)] }
79
78
  )
80
79
  end
81
80
 
@@ -41,6 +41,16 @@ module Mutant
41
41
  node.children.fetch(NAME_INDEX).equal?(method_name)
42
42
  end
43
43
 
44
+ def visibility
45
+ if scope.private_instance_methods.include?(method_name)
46
+ :private
47
+ elsif scope.protected_instance_methods.include?(method_name)
48
+ :protected
49
+ else
50
+ :public
51
+ end
52
+ end
53
+
44
54
  # Evaluator specialized for memoized instance methods
45
55
  class Memoized < self
46
56
  SUBJECT_CLASS = Subject::Method::Instance::Memoized
@@ -99,16 +99,40 @@ module Mutant
99
99
  node = matched_node_path.last || return
100
100
 
101
101
  self.class::SUBJECT_CLASS.new(
102
- context: context,
103
- node: node
102
+ context: context,
103
+ node: node,
104
+ visibility: visibility
104
105
  )
105
106
  end
106
- memoize :subject
107
107
 
108
108
  def matched_node_path
109
109
  AST.find_last_path(ast, &method(:match?))
110
110
  end
111
111
  memoize :matched_node_path
112
+
113
+ def visibility
114
+ # This can be cleaned up once we are on >ruby-3.0
115
+ # Method#{public,private,protected}? exists there.
116
+ #
117
+ # On Ruby 3.1 this can just be:
118
+ #
119
+ # if target_method.private?
120
+ # :private
121
+ # elsif target_method.protected?
122
+ # :protected
123
+ # else
124
+ # :public
125
+ # end
126
+ #
127
+ # Change to this once 3.0 is EOL.
128
+ if scope.private_methods.include?(method_name)
129
+ :private
130
+ elsif scope.protected_methods.include?(method_name)
131
+ :protected
132
+ else
133
+ :public
134
+ end
135
+ end
112
136
  end # Evaluator
113
137
 
114
138
  private_constant(*constants(false))
@@ -7,7 +7,7 @@ module Mutant
7
7
  include Concord::Public.new(:subject, :node)
8
8
 
9
9
  CODE_DELIMITER = "\0"
10
- CODE_RANGE = (0..4).freeze
10
+ CODE_RANGE = (..4).freeze
11
11
 
12
12
  # Mutation identification code
13
13
  #
@@ -69,7 +69,10 @@ module Mutant
69
69
  kernel: kernel,
70
70
  source: monkeypatch,
71
71
  subject: subject
72
- )
72
+ ).fmap do
73
+ subject.post_insert
74
+ nil
75
+ end
73
76
  end
74
77
 
75
78
  # Rendered mutation diff
@@ -19,17 +19,27 @@ module Mutant
19
19
  end
20
20
 
21
21
  def emit_argument_presence
22
- emit_type unless removed_block_arg?(EMPTY_ARRAY)
22
+ emit_type unless removed_block_arg?(EMPTY_ARRAY) || forward_arg?
23
23
 
24
- Util::Array::Presence.call(children).each do |children|
25
- unless removed_block_arg?(children) || (children.one? && n_mlhs?(children.first))
26
- emit_type(*children)
24
+ children.each_with_index do |removed, index|
25
+ new_arguments = children.dup
26
+ new_arguments.delete_at(index)
27
+ unless n_forward_arg?(removed) || removed_block_arg?(new_arguments) || only_mlhs?(new_arguments)
28
+ emit_type(*new_arguments)
27
29
  end
28
30
  end
29
31
  end
30
32
 
31
- def removed_block_arg?(children)
32
- anonymous_block_arg? && children.none?(&ANONYMOUS_BLOCKARG_PRED)
33
+ def only_mlhs?(new_arguments)
34
+ new_arguments.one? && n_mlhs?(new_arguments.first)
35
+ end
36
+
37
+ def forward_arg?
38
+ children.last && n_forward_arg?(children.last)
39
+ end
40
+
41
+ def removed_block_arg?(new_arguments)
42
+ anonymous_block_arg? && new_arguments.none?(&ANONYMOUS_BLOCKARG_PRED)
33
43
  end
34
44
 
35
45
  def anonymous_block_arg?
@@ -47,7 +57,7 @@ module Mutant
47
57
  end
48
58
 
49
59
  def invalid_argument_replacement?(mutant, index)
50
- n_arg?(mutant) && children[0...index].any?(&method(:n_optarg?))
60
+ n_arg?(mutant) && children[...index].any?(&method(:n_optarg?))
51
61
  end
52
62
 
53
63
  def emit_mlhs_expansion
@@ -7,7 +7,7 @@ module Mutant
7
7
  # Mutator for attribute assignments
8
8
  class AttributeAssignment < self
9
9
 
10
- ATTRIBUTE_RANGE = (0..-2).freeze
10
+ ATTRIBUTE_RANGE = (..-2).freeze
11
11
 
12
12
  private_constant(*constants(false))
13
13
 
@@ -241,7 +241,9 @@ module Mutant
241
241
 
242
242
  argument = Mutant::Util.one(arguments)
243
243
 
244
- emit_propagation(argument) unless n_kwargs?(argument)
244
+ return if n_kwargs?(argument) || n_forwarded_args?(argument)
245
+
246
+ emit_propagation(argument)
245
247
  end
246
248
 
247
249
  def mutate_receiver
@@ -22,7 +22,7 @@ module Mutant
22
22
 
23
23
  def mutate_conditions
24
24
  conditions = children.length - 1
25
- children[0..-2].each_index do |index|
25
+ children[..-2].each_index do |index|
26
26
  delete_child(index) if conditions > 1
27
27
  mutate_child(index)
28
28
  end
@@ -50,7 +50,7 @@ module Mutant
50
50
  Mutant
51
51
  .traverse(->(line) { parse_line(root, line) }, lines)
52
52
  .fmap do |paths|
53
- paths.map { |path| [path.path, path] }.to_h
53
+ paths.to_h { |path| [path.path, path] }
54
54
  end
55
55
  end
56
56
  end
@@ -17,6 +17,11 @@ module Mutant
17
17
  self
18
18
  end
19
19
 
20
+ def post_insert
21
+ scope.__send__(visibility, name)
22
+ self
23
+ end
24
+
20
25
  # Mutator for memoizable memoized instance methods
21
26
  class Memoized < self
22
27
  include AST::Sexp
@@ -17,6 +17,11 @@ module Mutant
17
17
  self
18
18
  end
19
19
 
20
+ def post_insert
21
+ scope.singleton_class.__send__(visibility, name)
22
+ self
23
+ end
24
+
20
25
  end # Singleton
21
26
  end # Method
22
27
  end # Subject
@@ -4,6 +4,7 @@ module Mutant
4
4
  class Subject
5
5
  # Abstract base class for method subjects
6
6
  class Method < self
7
+ include anima.add(:visibility)
7
8
 
8
9
  # Method name
9
10
  #
@@ -33,6 +33,13 @@ module Mutant
33
33
  self
34
34
  end
35
35
 
36
+ # Perform post insert cleanup
37
+ #
38
+ # @return [self]
39
+ def post_insert
40
+ self
41
+ end
42
+
36
43
  # Source line range
37
44
  #
38
45
  # @return [Range<Integer>]
@@ -351,7 +351,7 @@ module Mutant
351
351
  def transform_keys(keys, input)
352
352
  success(
353
353
  keys
354
- .map do |key|
354
+ .to_h do |key|
355
355
  [
356
356
  key.value,
357
357
  coerce_key(key, input).from_right do |error|
@@ -359,7 +359,6 @@ module Mutant
359
359
  end
360
360
  ]
361
361
  end
362
- .to_h
363
362
  )
364
363
  end
365
364
  # rubocop:enable Metrics/MethodLength
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.11.4'
5
+ VERSION = '0.11.7'
6
6
  end # Mutant
@@ -17,10 +17,7 @@ module Mutant
17
17
 
18
18
  include AST::Sexp
19
19
 
20
- # rubocop:disable Lint/InheritException
21
20
  LoadError = Class.new(::LoadError)
22
- # rubocop:enable Lint/InheritException
23
-
24
21
  # Initialize object
25
22
  #
26
23
  # @param [Symbol] namespace
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.4
4
+ version: 0.11.7
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-02-14 00:00:00.000000000 Z
11
+ date: 2022-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -44,20 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.0'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 2.0.3
47
+ version: '2.3'
51
48
  type: :runtime
52
49
  prerelease: false
53
50
  version_requirements: !ruby/object:Gem::Requirement
54
51
  requirements:
55
52
  - - "~>"
56
53
  - !ruby/object:Gem::Version
57
- version: '2.0'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 2.0.3
54
+ version: '2.3'
61
55
  - !ruby/object:Gem::Dependency
62
56
  name: sorbet-runtime
63
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +72,14 @@ dependencies:
78
72
  requirements:
79
73
  - - "~>"
80
74
  - !ruby/object:Gem::Version
81
- version: 0.6.4
75
+ version: 0.6.5
82
76
  type: :runtime
83
77
  prerelease: false
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
- version: 0.6.4
82
+ version: 0.6.5
89
83
  - !ruby/object:Gem::Dependency
90
84
  name: parallel
91
85
  requirement: !ruby/object:Gem::Requirement
@@ -368,7 +362,8 @@ files:
368
362
  homepage: https://github.com/mbj/mutant
369
363
  licenses:
370
364
  - Nonstandard
371
- metadata: {}
365
+ metadata:
366
+ rubygems_mfa_required: 'true'
372
367
  post_install_message:
373
368
  rdoc_options: []
374
369
  require_paths:
@@ -377,14 +372,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
377
372
  requirements:
378
373
  - - ">="
379
374
  - !ruby/object:Gem::Version
380
- version: '2.6'
375
+ version: '2.7'
381
376
  required_rubygems_version: !ruby/object:Gem::Requirement
382
377
  requirements:
383
378
  - - ">="
384
379
  - !ruby/object:Gem::Version
385
380
  version: '0'
386
381
  requirements: []
387
- rubygems_version: 3.3.3
382
+ rubygems_version: 3.3.7
388
383
  signing_key:
389
384
  specification_version: 4
390
385
  summary: ''