mutant 0.8.11 → 0.8.12
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 +4 -4
- data/.gitattributes +1 -0
- data/Changelog.md +29 -3
- data/README.md +2 -0
- data/config/flay.yml +1 -1
- data/lib/mutant.rb +6 -0
- data/lib/mutant/ast/meta/send.rb +26 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +1 -0
- data/lib/mutant/env/bootstrap.rb +7 -2
- data/lib/mutant/meta/example/dsl.rb +8 -0
- data/lib/mutant/mutator/node/generic.rb +52 -8
- data/lib/mutant/mutator/node/regexp.rb +0 -11
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +21 -0
- data/lib/mutant/mutator/node/regexp/capture_group.rb +26 -0
- data/lib/mutant/mutator/node/regexp/character_type.rb +29 -0
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +21 -0
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +21 -0
- data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +25 -0
- data/lib/mutant/mutator/node/send.rb +20 -1
- data/lib/mutant/reporter/cli.rb +2 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +6 -1
- data/meta/regexp.rb +8 -30
- data/meta/regexp/character_types.rb +20 -0
- data/meta/regexp/regexp_alternation_meta.rb +11 -0
- data/meta/regexp/regexp_bol_anchor.rb +1 -6
- data/meta/regexp/regexp_bos_anchor.rb +2 -12
- data/meta/regexp/regexp_capture_group.rb +17 -0
- data/meta/regexp/regexp_eol_anchor.rb +8 -0
- data/meta/regexp/regexp_eos_anchor.rb +6 -0
- data/meta/regexp/regexp_eos_ob_eol_anchor.rb +8 -0
- data/meta/regexp/regexp_greedy_zero_or_more.rb +10 -0
- data/meta/regexp/regexp_root_expression.rb +1 -6
- data/meta/send.rb +65 -0
- data/mutant.gemspec +2 -2
- data/spec/integrations.yml +0 -21
- data/spec/support/shared_context.rb +0 -13
- data/spec/support/warnings.yml +1 -1
- data/spec/unit/mutant/actor/mailbox_spec.rb +0 -3
- data/spec/unit/mutant/ast/meta/send/proc_predicate_spec.rb +28 -0
- data/spec/unit/mutant/ast/regexp_spec.rb +8 -3
- data/spec/unit/mutant/cli_spec.rb +0 -1
- data/spec/unit/mutant/context_spec.rb +0 -7
- data/spec/unit/mutant/env_spec.rb +2 -17
- data/spec/unit/mutant/expression_spec.rb +0 -2
- data/spec/unit/mutant/matcher/compiler_spec.rb +0 -2
- data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -2
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +1 -2
- data/spec/unit/mutant/meta/example/dsl_spec.rb +16 -0
- data/spec/unit/mutant/mutation_spec.rb +0 -3
- data/spec/unit/mutant/mutator_spec.rb +0 -2
- data/spec/unit/mutant/parallel/master_spec.rb +0 -3
- data/spec/unit/mutant/parallel/worker_spec.rb +0 -1
- data/spec/unit/mutant/registry_spec.rb +3 -5
- data/spec/unit/mutant/reporter/cli/tput_spec.rb +1 -1
- data/spec/unit/mutant/result/env_spec.rb +0 -5
- data/spec/unit/mutant/result/mutation_spec.rb +1 -13
- data/spec/unit/mutant/runner_spec.rb +3 -16
- data/spec/unit/mutant/selector/expression_spec.rb +0 -1
- data/spec/unit/mutant/subject_spec.rb +1 -6
- metadata +24 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9fccb5b88d832378fa591e769d03f29bd9157ad
|
4
|
+
data.tar.gz: 7a84e4ba5e25a538218b4a4d2efab2be9a7c90e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0590a8d9f4775c4c21b1599a67f2360a8319b5fce2ec4264846c731a9468a09108bccb8ed56bc72ca7ba5087eac13135e004ab02fb4848f490bbe86c2c6e9833
|
7
|
+
data.tar.gz: c2a3e39dbb3ee300d3c526e0aecba9fcf866fef79a4954eb004a928f448f2c67e56655a84df4f0145e9b06f4b14e65e6de85a1ffa8e98dc7c540b8936335f4cc
|
data/.gitattributes
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Changelog.md merge=union
|
data/Changelog.md
CHANGED
@@ -1,10 +1,36 @@
|
|
1
|
-
# v0.8.
|
1
|
+
# v0.8.12 2016-10-17
|
2
|
+
|
3
|
+
* Add mutation from `/foo|bar/` to `/foo/` and `/bar/`
|
4
|
+
* Add mutation from `/$/` to `/\z/`
|
5
|
+
* Add mutation from `/\h/` to `/\H/`
|
6
|
+
* Add mutation from `/\H/` to `/\h/`
|
7
|
+
* Add mutation from `/\Z/` to `/\z/`
|
8
|
+
* Add mutation from `flat_map` to `map`
|
9
|
+
* Add mutation from `/(foo)/` to `/(?:foo)/`
|
10
|
+
* Add mutation from `/a*/` to `/a+/`
|
11
|
+
* Add mutation from `/a*/` to `/a/`
|
12
|
+
* Add mutation from `!!foo` to `foo`
|
13
|
+
* Add mutation from `proc { }` to `lambda { }`
|
14
|
+
|
15
|
+
# v0.8.11 2016-08-01
|
2
16
|
|
3
17
|
* Add support for rspec-3.5
|
4
|
-
* Remove misleading
|
5
|
-
* Remove misleading
|
18
|
+
* Remove misleading `--debug` option
|
19
|
+
* Remove misleading `--expect-coverage` option
|
6
20
|
* Add basic support for regexp mutations (machinery and simple anchor mutations)
|
7
21
|
* Add support for mutating csend (duck tape operator) into regular sends
|
22
|
+
* Add mutation from `foo&.bar` to `foo.bar`
|
23
|
+
* Add mutation from `#to_a` to `#to_set`
|
24
|
+
* Add mutation from `foo.dig(a, b)` to `foo.fetch(a).dig(b)`
|
25
|
+
* Add mutation from `def foo(bar:); end` to `def foo(_bar:); end`
|
26
|
+
* Add mutation from `def foo(bar: baz); end` to `def foo(_bar: baz); end`
|
27
|
+
* Add mutation from `/regex/i` to `/regex/`
|
28
|
+
* Add mutation from `foo[n..-1]` to `foo.drop(n)`
|
29
|
+
* Add mutation from `/^/` to `/\A/`
|
30
|
+
* Add mutation from `#first` to `#last`
|
31
|
+
* Add mutation from `#last` to `#first`
|
32
|
+
* Add mutation from `#sample` to `#first` and `#last`
|
33
|
+
* Remove mutations from `1..n` to `1..(0.0 / 0.0)` and `1..(1.0 / 0.0)`
|
8
34
|
|
9
35
|
# v0.8.10 2016-01-24
|
10
36
|
|
data/README.md
CHANGED
@@ -340,6 +340,7 @@ Blog posts
|
|
340
340
|
|
341
341
|
Sorted by recency:
|
342
342
|
|
343
|
+
* [A deep dive into mutation testing and how the Mutant gem works][troessner]
|
343
344
|
* [How to write better code using mutation testing (November 2015)][blockscore]
|
344
345
|
* [How good are your Ruby tests? Testing your tests with mutant (June 2015)][arkency1]
|
345
346
|
* [Mutation testing and continuous integration (May 2015)][arkency2]
|
@@ -347,6 +348,7 @@ Sorted by recency:
|
|
347
348
|
* [Mutation testing with mutant (April 2014)][sitepoint]
|
348
349
|
* [Mutation testing with mutant (January 2013)][solnic]
|
349
350
|
|
351
|
+
[troessner]: https://troessner.svbtle.com/kill-all-the-mutants-a-deep-dive-into-mutation-testing-and-how-the-mutant-gem-works
|
350
352
|
[blockscore]: https://blog.blockscore.com/how-to-write-better-code-using-mutation-testing/
|
351
353
|
[sitepoint]: http://www.sitepoint.com/mutation-testing-mutant/
|
352
354
|
[arkency1]: http://blog.arkency.com/2015/06/how-good-are-your-ruby-tests-testing-your-tests-with-mutant/
|
data/config/flay.yml
CHANGED
data/lib/mutant.rb
CHANGED
@@ -91,6 +91,12 @@ require 'mutant/mutator/util/symbol'
|
|
91
91
|
require 'mutant/mutator/node'
|
92
92
|
require 'mutant/mutator/node/generic'
|
93
93
|
require 'mutant/mutator/node/regexp'
|
94
|
+
require 'mutant/mutator/node/regexp/alternation_meta'
|
95
|
+
require 'mutant/mutator/node/regexp/capture_group'
|
96
|
+
require 'mutant/mutator/node/regexp/character_type'
|
97
|
+
require 'mutant/mutator/node/regexp/end_of_line_anchor'
|
98
|
+
require 'mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor'
|
99
|
+
require 'mutant/mutator/node/regexp/greedy_zero_or_more'
|
94
100
|
require 'mutant/mutator/node/literal'
|
95
101
|
require 'mutant/mutator/node/literal/boolean'
|
96
102
|
require 'mutant/mutator/node/literal/range'
|
data/lib/mutant/ast/meta/send.rb
CHANGED
@@ -21,6 +21,13 @@ module Mutant
|
|
21
21
|
|
22
22
|
public :arguments
|
23
23
|
|
24
|
+
# Test if node is defining a proc
|
25
|
+
#
|
26
|
+
# @return [Boolean]
|
27
|
+
def proc?
|
28
|
+
naked_proc? || proc_new?
|
29
|
+
end
|
30
|
+
|
24
31
|
# Test if AST node is a valid assignment target
|
25
32
|
#
|
26
33
|
# @return [Boolean]
|
@@ -59,6 +66,25 @@ module Mutant
|
|
59
66
|
Const.new(receiver).possible_top_level?
|
60
67
|
end
|
61
68
|
|
69
|
+
private
|
70
|
+
|
71
|
+
# Test if node is `proc { ... }`
|
72
|
+
#
|
73
|
+
# @return [Boolean]
|
74
|
+
def naked_proc?
|
75
|
+
!receiver && selector.equal?(:proc)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Test if node is `Proc.new { ... }`
|
79
|
+
#
|
80
|
+
# @return [Boolean]
|
81
|
+
def proc_new?
|
82
|
+
receiver &&
|
83
|
+
selector.equal?(:new) &&
|
84
|
+
n_const?(receiver) &&
|
85
|
+
Const.new(receiver).name.equal?(:Proc)
|
86
|
+
end
|
87
|
+
|
62
88
|
end # Send
|
63
89
|
end # Meta
|
64
90
|
end # AST
|
@@ -70,6 +70,7 @@ module Mutant
|
|
70
70
|
[:regexp_script_hiragana_property, [:property, :script_hiragana, '\p{Hiragana}'], ::Regexp::Expression::UnicodeProperty::Script],
|
71
71
|
[:regexp_script_katakana_property, [:property, :script_katakana, '\p{Katakana}'], ::Regexp::Expression::UnicodeProperty::Script],
|
72
72
|
[:regexp_letter_any_property, [:property, :letter_any, '\p{L}'], ::Regexp::Expression::UnicodeProperty::Letter::Any],
|
73
|
+
[:regexp_hex_type, [:type, :hex, '\h'], ::Regexp::Expression::CharacterType::Hex],
|
73
74
|
[:regexp_digit_type, [:type, :digit, '\d'], ::Regexp::Expression::CharacterType::Digit],
|
74
75
|
[:regexp_space_type, [:type, :space, '\s'], ::Regexp::Expression::CharacterType::Space],
|
75
76
|
[:regexp_word_type, [:type, :word, '\w'], ::Regexp::Expression::CharacterType::Word],
|
data/lib/mutant/env/bootstrap.rb
CHANGED
@@ -56,17 +56,22 @@ module Mutant
|
|
56
56
|
Env.new(
|
57
57
|
actor_env: Actor::Env.new(Thread),
|
58
58
|
config: config,
|
59
|
-
integration:
|
59
|
+
integration: integration,
|
60
60
|
matchable_scopes: matchable_scopes,
|
61
61
|
mutations: subjects.flat_map(&:mutations),
|
62
62
|
parser: parser,
|
63
|
-
selector: Selector::Expression.new(
|
63
|
+
selector: Selector::Expression.new(integration),
|
64
64
|
subjects: subjects
|
65
65
|
)
|
66
66
|
end
|
67
67
|
|
68
68
|
private
|
69
69
|
|
70
|
+
# Configured mutant integration
|
71
|
+
#
|
72
|
+
# @return [Mutant::Integration]
|
73
|
+
attr_reader :integration
|
74
|
+
|
70
75
|
# Scope name from scoping object
|
71
76
|
#
|
72
77
|
# @param [Class, Module] scope
|
@@ -75,6 +75,14 @@ module Mutant
|
|
75
75
|
mutation('self')
|
76
76
|
end
|
77
77
|
|
78
|
+
# Add regexp mutations
|
79
|
+
#
|
80
|
+
# @return [undefined]
|
81
|
+
def regexp_mutations
|
82
|
+
mutation('//')
|
83
|
+
mutation('/nomatch\A/')
|
84
|
+
end
|
85
|
+
|
78
86
|
# Helper method to coerce input to node
|
79
87
|
#
|
80
88
|
# @param [String,Parser::AST::Node] input
|
@@ -5,16 +5,60 @@ module Mutant
|
|
5
5
|
# Generic mutator
|
6
6
|
class Generic < self
|
7
7
|
|
8
|
+
unsupported_nodes = %i[
|
9
|
+
ensure
|
10
|
+
redo
|
11
|
+
retry
|
12
|
+
arg_expr
|
13
|
+
blockarg
|
14
|
+
kwrestarg
|
15
|
+
undef
|
16
|
+
module
|
17
|
+
empty
|
18
|
+
alias
|
19
|
+
for
|
20
|
+
xstr
|
21
|
+
back_ref
|
22
|
+
restarg
|
23
|
+
sclass
|
24
|
+
match_with_lvasgn
|
25
|
+
while_post
|
26
|
+
until_post
|
27
|
+
preexe
|
28
|
+
postexe
|
29
|
+
iflipflop
|
30
|
+
eflipflop
|
31
|
+
kwsplat
|
32
|
+
shadowarg
|
33
|
+
rational
|
34
|
+
complex
|
35
|
+
__FILE__
|
36
|
+
__LINE__
|
37
|
+
]
|
38
|
+
|
39
|
+
unsupported_regexp_nodes = AST::Types::REGEXP.to_a - %i[
|
40
|
+
regexp_alternation_meta
|
41
|
+
regexp_bol_anchor
|
42
|
+
regexp_capture_group
|
43
|
+
regexp_digit_type
|
44
|
+
regexp_eol_anchor
|
45
|
+
regexp_eos_ob_eol_anchor
|
46
|
+
regexp_greedy_zero_or_more
|
47
|
+
regexp_hex_type
|
48
|
+
regexp_nondigit_type
|
49
|
+
regexp_nonhex_type
|
50
|
+
regexp_nonspace_type
|
51
|
+
regexp_nonword_boundary_anchor
|
52
|
+
regexp_nonword_type
|
53
|
+
regexp_root_expression
|
54
|
+
regexp_space_type
|
55
|
+
regexp_word_boundary_anchor
|
56
|
+
regexp_word_type
|
57
|
+
]
|
58
|
+
|
8
59
|
# These nodes still need a dedicated mutator,
|
9
60
|
# your contribution is that close!
|
10
|
-
handle(
|
11
|
-
:ensure, :redo, :retry, :arg_expr, :blockarg,
|
12
|
-
:kwrestarg, :undef, :module, :empty,
|
13
|
-
:alias, :for, :xstr, :back_ref, :restarg,
|
14
|
-
:sclass, :match_with_lvasgn, :while_post,
|
15
|
-
:until_post, :preexe, :postexe, :iflipflop, :eflipflop, :kwsplat,
|
16
|
-
:shadowarg, :rational, :complex, :__FILE__, :__LINE__
|
17
|
-
)
|
61
|
+
handle(*(unsupported_nodes + unsupported_regexp_nodes))
|
18
62
|
|
19
63
|
private
|
20
64
|
|
@@ -2,17 +2,6 @@ module Mutant
|
|
2
2
|
class Mutator
|
3
3
|
class Node
|
4
4
|
module Regexp
|
5
|
-
# Generic regexp mutator
|
6
|
-
class Generic < Node
|
7
|
-
handle(*(AST::Types::REGEXP - %i[regexp_root_expression regexp_bol_anchor]))
|
8
|
-
|
9
|
-
# Noop dispatch
|
10
|
-
#
|
11
|
-
# @return [undefined]
|
12
|
-
def dispatch
|
13
|
-
end
|
14
|
-
end # Generic
|
15
|
-
|
16
5
|
# Mutator for root expression regexp wrapper
|
17
6
|
class RootExpression < Node
|
18
7
|
handle(:regexp_root_expression)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Mutator for pipe in `/foo|bar/` regexp
|
6
|
+
class AlternationMeta < Node
|
7
|
+
handle(:regexp_alternation_meta)
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Dispatch mutations
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
def dispatch
|
15
|
+
children.each_index(&method(:delete_child))
|
16
|
+
end
|
17
|
+
end # AlternationMeta
|
18
|
+
end # Regexp
|
19
|
+
end # Node
|
20
|
+
end # Mutator
|
21
|
+
end # Mutant
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Mutator for regexp capture groups, such as `/(foo)/`
|
6
|
+
class CaptureGroup < Node
|
7
|
+
handle(:regexp_capture_group)
|
8
|
+
|
9
|
+
children :group
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# Replace `(captured_group)` with `(?:non_captured_group)`
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
def dispatch
|
17
|
+
return unless group
|
18
|
+
|
19
|
+
emit(s(:regexp_passive_group, group))
|
20
|
+
emit_group_mutations
|
21
|
+
end
|
22
|
+
end # EndOfLineAnchor
|
23
|
+
end # Regexp
|
24
|
+
end # Node
|
25
|
+
end # Mutator
|
26
|
+
end # Mutant
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Character type mutator
|
6
|
+
class CharacterType < Node
|
7
|
+
map = {
|
8
|
+
regexp_digit_type: :regexp_nondigit_type,
|
9
|
+
regexp_hex_type: :regexp_nonhex_type,
|
10
|
+
regexp_space_type: :regexp_nonspace_type,
|
11
|
+
regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
|
12
|
+
regexp_word_type: :regexp_nonword_type
|
13
|
+
}
|
14
|
+
|
15
|
+
MAP = IceNine.deep_freeze(map.merge(map.invert))
|
16
|
+
|
17
|
+
handle(*MAP.keys)
|
18
|
+
|
19
|
+
# Mutate to invert character type
|
20
|
+
#
|
21
|
+
# @return [undefined]
|
22
|
+
def dispatch
|
23
|
+
emit(s(MAP.fetch(node.type)))
|
24
|
+
end
|
25
|
+
end # CharacterType
|
26
|
+
end # Regexp
|
27
|
+
end # Node
|
28
|
+
end # Mutator
|
29
|
+
end # Mutant
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Mutator for end of line anchor `$`
|
6
|
+
class EndOfLineAnchor < Node
|
7
|
+
handle(:regexp_eol_anchor)
|
8
|
+
|
9
|
+
# Emit mutations
|
10
|
+
#
|
11
|
+
# Replace `$` with `\z`
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
def dispatch
|
15
|
+
emit(s(:regexp_eos_anchor))
|
16
|
+
end
|
17
|
+
end # EndOfLineAnchor
|
18
|
+
end # Regexp
|
19
|
+
end # Node
|
20
|
+
end # Mutator
|
21
|
+
end # Mutant
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Mutator for end of line or before end of string anchor `\Z`
|
6
|
+
class EndOfStringOrBeforeEndOfLineAnchor < Node
|
7
|
+
handle(:regexp_eos_ob_eol_anchor)
|
8
|
+
|
9
|
+
# Emit mutations
|
10
|
+
#
|
11
|
+
# Replace `\Z` with `\z`
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
def dispatch
|
15
|
+
emit(s(:regexp_eos_anchor))
|
16
|
+
end
|
17
|
+
end # EndOfStringOrBeforeEndOfLineAnchor
|
18
|
+
end # Regexp
|
19
|
+
end # Node
|
20
|
+
end # Mutator
|
21
|
+
end # Mutant
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
module Regexp
|
5
|
+
# Mutator for greedy zero-or-more quantifier, `*`
|
6
|
+
class GreedyZeroOrMore < Node
|
7
|
+
handle(:regexp_greedy_zero_or_more)
|
8
|
+
|
9
|
+
children :min, :max, :subject
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# Replace `/a*/` with `/a+/`
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
def dispatch
|
17
|
+
emit(s(:regexp_greedy_one_or_more, *children))
|
18
|
+
emit_subject_mutations
|
19
|
+
emit(subject)
|
20
|
+
end
|
21
|
+
end # GreedyZeroOrMore
|
22
|
+
end # Regexp
|
23
|
+
end # Node
|
24
|
+
end # Mutator
|
25
|
+
end # Mutant
|
@@ -18,6 +18,7 @@ module Mutant
|
|
18
18
|
reverse_each: %i[each],
|
19
19
|
reverse_merge: %i[merge],
|
20
20
|
map: %i[each],
|
21
|
+
flat_map: %i[map],
|
21
22
|
sample: %i[first last],
|
22
23
|
pop: %i[last],
|
23
24
|
shift: %i[first],
|
@@ -110,6 +111,8 @@ module Mutant
|
|
110
111
|
emit_const_get_mutation
|
111
112
|
emit_integer_mutation
|
112
113
|
emit_dig_mutation
|
114
|
+
emit_double_negation_mutation
|
115
|
+
emit_lambda_mutation
|
113
116
|
emit_drop_mutation
|
114
117
|
end
|
115
118
|
|
@@ -125,6 +128,23 @@ module Mutant
|
|
125
128
|
.each(&method(:emit_selector))
|
126
129
|
end
|
127
130
|
|
131
|
+
# Emit mutation from `!!foo` to `foo`
|
132
|
+
#
|
133
|
+
# @return [undefined]
|
134
|
+
def emit_double_negation_mutation
|
135
|
+
return unless selector.equal?(:!) && n_send?(receiver)
|
136
|
+
|
137
|
+
negated = AST::Meta::Send.new(meta.receiver)
|
138
|
+
emit(negated.receiver) if negated.selector.equal?(:!)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Emit mutation from proc definition to lambda
|
142
|
+
#
|
143
|
+
# @return [undefined]
|
144
|
+
def emit_lambda_mutation
|
145
|
+
emit(s(:send, nil, :lambda)) if meta.proc?
|
146
|
+
end
|
147
|
+
|
128
148
|
# Emit mutation for `#dig`
|
129
149
|
#
|
130
150
|
# - Mutates `foo.dig(a, b)` to `foo.fetch(a).dig(b)`
|
@@ -232,5 +252,4 @@ module Mutant
|
|
232
252
|
end # Send
|
233
253
|
end # Node
|
234
254
|
end # Mutator
|
235
|
-
|
236
255
|
end # Mutant
|