mutant 0.9.13 → 0.9.14

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: 8a634036241e157b66b8778d1645bca99d67cd81fa26042c42e43f868bafa260
4
- data.tar.gz: ee46dcacd412e10634454dbdd5ec52d5a803c71fa8e9db9cc3fcdc35e35a8e5c
3
+ metadata.gz: 3e92dbf6cbb84cf8d3d5354fc5994cb1ad7cb1fb1364b1927aa89abeedcd0cef
4
+ data.tar.gz: 5c49178b6766424d6ded707a100ebad86cf9c5403a53b2c2c750baf69b4d636f
5
5
  SHA512:
6
- metadata.gz: b0d20d48dc5443ba2347c176425ec372ed2d4e2f11e0bea33c59895b9b52d00b4efcdd07e8f9b47eefbd2ebd8f20d610f3ed3a726d9d59bbed1378b2be2fea1f
7
- data.tar.gz: e4ad2f3d626eaae68f390447ad94cdf1338525f010f684f524873cfab6560d25ffb67062f6f2567750c9468670241d5180ba1a8bcc32fe7e42fc16cd3ff2c4ef
6
+ metadata.gz: e786a6ed55abf722515f3b4b9c08200dac35557e48c27430ae5683471ededf67d1fcb17ff4e5f57f1881765d10f3a8b00ef2993f163a1cceb93531d4b75a37e3
7
+ data.tar.gz: 2a5840a2ecc0ca7c9c6156e8c4596b21808aaf8418ecf134fff9ada56a6c20e94b5ece60a0ebf0b321f1ed51ff0e5c92d26069bcb9473f61276973c46780eb5d
@@ -90,8 +90,7 @@ require 'mutant/mutator/node/arguments'
90
90
  require 'mutant/mutator/node/begin'
91
91
  require 'mutant/mutator/node/binary'
92
92
  require 'mutant/mutator/node/const'
93
- require 'mutant/mutator/node/dstr'
94
- require 'mutant/mutator/node/dsym'
93
+ require 'mutant/mutator/node/dynamic_literal'
95
94
  require 'mutant/mutator/node/kwbegin'
96
95
  require 'mutant/mutator/node/named_value/access'
97
96
  require 'mutant/mutator/node/named_value/constant_assignment'
@@ -3,7 +3,19 @@
3
3
  module Mutant
4
4
  module Meta
5
5
  class Example
6
- include Adamantium, Anima.new(:file, :node, :types, :expected)
6
+ include Adamantium
7
+ include Anima.new(
8
+ :expected,
9
+ :file,
10
+ :lvars,
11
+ :node,
12
+ :original_source,
13
+ :types
14
+ )
15
+
16
+ class Expected
17
+ include Anima.new(:original_source, :node)
18
+ end
7
19
 
8
20
  # Verification instance for example
9
21
  #
@@ -13,13 +25,13 @@ module Mutant
13
25
  end
14
26
  memoize :verification
15
27
 
16
- # Normalized source
28
+ # Original source as generated by unparser
17
29
  #
18
30
  # @return [String]
19
- def source
31
+ def original_source_generated
20
32
  Unparser.unparse(node)
21
33
  end
22
- memoize :source
34
+ memoize :original_source_generated
23
35
 
24
36
  # Generated mutations on example source
25
37
  #
@@ -25,10 +25,11 @@ module Mutant
25
25
  #
26
26
  # @return [undefined]
27
27
  def initialize(file, types)
28
+ @expected = []
28
29
  @file = file
30
+ @lvars = []
31
+ @source = nil
29
32
  @types = types
30
- @node = nil
31
- @expected = []
32
33
  end
33
34
 
34
35
  # Example captured by DSL
@@ -38,28 +39,41 @@ module Mutant
38
39
  # @raise [RuntimeError]
39
40
  # in case example cannot be build
40
41
  def example
41
- fail 'source not defined' unless @node
42
+ fail 'source not defined' unless @source
42
43
  Example.new(
43
- file: @file,
44
- node: @node,
45
- types: @types,
46
- expected: @expected
44
+ expected: @expected,
45
+ file: @file,
46
+ lvars: @lvars,
47
+ node: @node,
48
+ original_source: @source,
49
+ types: @types
47
50
  )
48
51
  end
49
52
 
53
+ # Declare a local variable
54
+ #
55
+ # @param [Symbol]
56
+ def declare_lvar(name)
57
+ @lvars << name
58
+ end
59
+
50
60
  private
51
61
 
52
62
  def source(input)
53
- fail 'source already defined' if @node
54
- @node = node(input)
63
+ fail 'source already defined' if @source
64
+
65
+ @source = input
66
+ @node = node(input)
55
67
  end
56
68
 
57
69
  def mutation(input)
58
- node = node(input)
59
- if @expected.include?(node)
70
+ expected = Expected.new(original_source: input, node: node(input))
71
+
72
+ if @expected.include?(expected)
60
73
  fail "Mutation for input: #{input.inspect} is already expected"
61
74
  end
62
- @expected << node
75
+
76
+ @expected << expected
63
77
  end
64
78
 
65
79
  def singleton_mutations
@@ -70,14 +84,17 @@ module Mutant
70
84
  def node(input)
71
85
  case input
72
86
  when String
73
- Unparser::Preprocessor.run(Unparser.parse(input))
74
- when ::Parser::AST::Node
75
- input
87
+ parser.parse(Unparser.buffer(input))
76
88
  else
77
- fail "Cannot coerce to node: #{input.inspect}"
89
+ fail "Unsupported input: #{input.inspect}"
78
90
  end
79
91
  end
80
92
 
93
+ def parser
94
+ Unparser.parser.tap do |parser|
95
+ @lvars.each(&parser.static_env.public_method(:declare))
96
+ end
97
+ end
81
98
  end # DSL
82
99
  end # Example
83
100
  end # Meta
@@ -11,54 +11,96 @@ module Mutant
11
11
  #
12
12
  # @return [Boolean]
13
13
  def success?
14
- [missing, unexpected, no_diffs, invalid_syntax].all?(&:empty?)
14
+ [
15
+ original_verification,
16
+ invalid,
17
+ missing,
18
+ no_diffs,
19
+ unexpected
20
+ ].all?(&:empty?)
15
21
  end
16
22
  memoize :success?
17
23
 
18
- # Error report
19
- #
20
- # @return [String]
21
24
  def error_report
22
- fail 'no error report on successful validation' if success?
23
-
24
- YAML.dump(
25
- 'file' => example.file,
26
- 'original_ast' => example.node.inspect,
27
- 'original_source' => example.source,
28
- 'missing' => format_mutations(missing),
29
- 'unexpected' => format_mutations(unexpected),
30
- 'invalid_syntax' => format_mutations(invalid_syntax),
31
- 'no_diff' => no_diff_report
32
- )
25
+ reports.join("\n")
33
26
  end
34
- memoize :error_report
35
27
 
36
28
  private
37
29
 
30
+ def reports
31
+ reports = [example.file]
32
+ reports.concat(original)
33
+ reports.concat(original_verification)
34
+ reports.concat(make_report('Missing mutations:', missing))
35
+ reports.concat(make_report('Unexpected mutations:', unexpected))
36
+ reports.concat(make_report('No-Diff mutations:', no_diffs))
37
+ reports.concat(invalid)
38
+ end
39
+
40
+ def make_report(label, mutations)
41
+ if mutations.any?
42
+ [label, mutations.map(&method(:report_mutation))]
43
+ else
44
+ []
45
+ end
46
+ end
47
+
48
+ def report_mutation(mutation)
49
+ [
50
+ mutation.node.inspect,
51
+ mutation.source
52
+ ]
53
+ end
54
+
55
+ def original
56
+ [
57
+ 'Original:',
58
+ example.node,
59
+ example.original_source
60
+ ]
61
+ end
62
+
63
+ def original_verification
64
+ validation = Unparser::Validation.from_string(example.original_source)
65
+ if validation.success?
66
+ []
67
+ else
68
+ [
69
+ prefix('[original]', validation.report)
70
+ ]
71
+ end
72
+ end
73
+
74
+ def prefix(prefix, string)
75
+ string.each_line.map do |line|
76
+ "#{prefix} #{line}"
77
+ end.join
78
+ end
79
+
80
+ def invalid
81
+ mutations.each_with_object([]) do |mutation, aggregate|
82
+ validation = Unparser::Validation.from_node(mutation.node)
83
+ aggregate << prefix('[invalid-mutation]', validation.report) unless validation.success?
84
+ end
85
+ end
86
+ memoize :invalid
87
+
38
88
  def unexpected
39
89
  mutations.reject do |mutation|
40
- example.expected.include?(mutation.node)
90
+ example.expected.any? { |expected| expected.node.eql?(mutation.node) }
41
91
  end
42
92
  end
43
93
  memoize :unexpected
44
94
 
45
95
  def missing
46
- (example.expected - mutations.map(&:node)).map do |node|
47
- Mutation::Evil.new(self, node)
96
+ (example.expected.map(&:node) - mutations.map(&:node)).map do |node|
97
+ Mutation::Evil.new(nil, node)
48
98
  end
49
99
  end
50
100
  memoize :missing
51
101
 
52
- def invalid_syntax
53
- mutations.reject do |mutation|
54
- ::Parser::CurrentRuby.parse(mutation.source)
55
- rescue ::Parser::SyntaxError # rubocop:disable Lint/SuppressedException
56
- end
57
- end
58
- memoize :invalid_syntax
59
-
60
102
  def no_diffs
61
- mutations.select { |mutation| mutation.source.eql?(example.source) }
103
+ mutations.select { |mutation| mutation.source.eql?(example.original_source_generated) }
62
104
  end
63
105
  memoize :no_diffs
64
106
 
@@ -75,7 +75,7 @@ module Mutant
75
75
  end
76
76
 
77
77
  def emit_nil
78
- emit(N_NIL) unless left_assignment?
78
+ emit(N_NIL) unless left_op_assignment?
79
79
  end
80
80
 
81
81
  def parent_node
@@ -86,7 +86,7 @@ module Mutant
86
86
  parent_node&.type
87
87
  end
88
88
 
89
- def left_assignment?
89
+ def left_op_assignment?
90
90
  AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
91
91
  end
92
92
 
@@ -3,17 +3,19 @@
3
3
  module Mutant
4
4
  class Mutator
5
5
  class Node
6
+ # Mutator for dynamic literals
7
+ class DynamicLiteral < self
6
8
 
7
- # Dstr mutator
8
- class Dstr < Generic
9
-
10
- handle(:dstr)
9
+ handle(:dstr, :dsym)
11
10
 
12
11
  private
13
12
 
14
13
  def dispatch
15
- super()
16
14
  emit_singletons
15
+
16
+ children.each_index do |index|
17
+ mutate_child(index, &method(:n_begin?))
18
+ end
17
19
  end
18
20
 
19
21
  end # Dstr
@@ -24,7 +24,7 @@ module Mutant
24
24
  end
25
25
 
26
26
  def emit_send_forms
27
- return if left_assignment?
27
+ return if left_op_assignment?
28
28
 
29
29
  SEND_REPLACEMENTS.each do |selector|
30
30
  emit(s(:send, receiver, selector, *indices))
@@ -43,7 +43,7 @@ module Mutant
43
43
 
44
44
  def mutate_indices
45
45
  children_indices(index_range).each do |index|
46
- emit_propagation(children.fetch(index)) unless left_assignment?
46
+ emit_propagation(children.fetch(index)) unless left_op_assignment?
47
47
  delete_child(index)
48
48
  mutate_child(index)
49
49
  end
@@ -77,7 +77,7 @@ module Mutant
77
77
  def dispatch
78
78
  super()
79
79
 
80
- return if left_assignment?
80
+ return if left_op_assignment?
81
81
 
82
82
  emit_index_read
83
83
  emit(children.last)
@@ -89,7 +89,7 @@ module Mutant
89
89
  end
90
90
 
91
91
  def index_range
92
- if left_assignment?
92
+ if left_op_assignment?
93
93
  NO_VALUE_RANGE
94
94
  else
95
95
  REGULAR_RANGE
@@ -15,10 +15,24 @@ module Mutant
15
15
 
16
16
  def dispatch
17
17
  emit_singletons
18
+
19
+ left_mutations
20
+
21
+ emit_right_mutations
22
+ end
23
+
24
+ def left_mutations
18
25
  emit_left_mutations do |node|
19
26
  !n_self?(node)
20
27
  end
21
- emit_right_mutations
28
+
29
+ emit_left_promotion if n_send?(left)
30
+ end
31
+
32
+ def emit_left_promotion
33
+ receiver = left.children.first
34
+
35
+ emit_left(s(:ivasgn, *receiver)) if n_ivar?(receiver)
22
36
  end
23
37
 
24
38
  end # OpAsgn
@@ -159,7 +159,7 @@ module Mutant
159
159
  end
160
160
 
161
161
  def emit_naked_receiver
162
- emit(receiver) if receiver
162
+ emit(receiver) if receiver && !left_op_assignment?
163
163
  end
164
164
 
165
165
  def mutate_arguments
@@ -8,6 +8,7 @@ module Mutant
8
8
  class AttributeAssignment < self
9
9
 
10
10
  ATTRIBUTE_RANGE = (0..-2).freeze
11
+
11
12
  private_constant(*constants(false))
12
13
 
13
14
  private
@@ -42,7 +42,7 @@ module Mutant
42
42
  private
43
43
 
44
44
  def wrap_node(mutant)
45
- s(:begin, mutant, s(:send, nil, :memoize, s(:args, s(:sym, name), *options)))
45
+ s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name), *options))
46
46
  end
47
47
 
48
48
  # The optional AST node for adamantium memoization options
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.9.13'
5
+ VERSION = '0.9.14'
6
6
  end # Mutant
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.9.13
4
+ version: 0.9.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-07 00:00:00.000000000 Z
11
+ date: 2020-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: abstract_type
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 0.4.8
187
+ version: 0.5.2
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: 0.4.8
194
+ version: 0.5.2
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: variable
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -356,8 +356,7 @@ files:
356
356
  - lib/mutant/mutator/node/const.rb
357
357
  - lib/mutant/mutator/node/define.rb
358
358
  - lib/mutant/mutator/node/defined.rb
359
- - lib/mutant/mutator/node/dstr.rb
360
- - lib/mutant/mutator/node/dsym.rb
359
+ - lib/mutant/mutator/node/dynamic_literal.rb
361
360
  - lib/mutant/mutator/node/generic.rb
362
361
  - lib/mutant/mutator/node/if.rb
363
362
  - lib/mutant/mutator/node/index.rb
@@ -468,7 +467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
468
467
  - !ruby/object:Gem::Version
469
468
  version: '0'
470
469
  requirements: []
471
- rubygems_version: 3.1.2
470
+ rubygems_version: 3.1.4
472
471
  signing_key:
473
472
  specification_version: 4
474
473
  summary: ''
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
-
7
- # Dsym mutator
8
- class Dsym < Generic
9
-
10
- handle(:dsym)
11
-
12
- private
13
-
14
- def dispatch
15
- super()
16
- emit_singletons
17
- end
18
-
19
- end # Dsym
20
- end # Node
21
- end # Mutator
22
- end # Mutant