mutant 0.8.11 → 0.8.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|