mutant 0.8.10 → 0.8.11
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/.rubocop.yml +1 -4
- data/Changelog.md +8 -0
- data/README.md +112 -43
- data/Rakefile +2 -16
- data/circle.yml +1 -1
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/reek.yml +3 -4
- data/config/rubocop.yml +53 -16
- data/lib/mutant.rb +27 -6
- data/lib/mutant/ast/meta/const.rb +2 -0
- data/lib/mutant/ast/meta/optarg.rb +2 -0
- data/lib/mutant/ast/meta/resbody.rb +2 -0
- data/lib/mutant/ast/meta/restarg.rb +2 -0
- data/lib/mutant/ast/meta/send.rb +4 -0
- data/lib/mutant/ast/meta/symbol.rb +2 -0
- data/lib/mutant/ast/named_children.rb +14 -4
- data/lib/mutant/ast/nodes.rb +3 -1
- data/lib/mutant/ast/regexp.rb +53 -0
- data/lib/mutant/ast/regexp/transformer.rb +185 -0
- data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
- data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
- data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
- data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
- data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
- data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
- data/lib/mutant/ast/types.rb +92 -5
- data/lib/mutant/cli.rb +2 -14
- data/lib/mutant/color.rb +1 -1
- data/lib/mutant/config.rb +1 -3
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/expression/namespace.rb +2 -2
- data/lib/mutant/expression/parser.rb +1 -1
- data/lib/mutant/integration.rb +10 -28
- data/lib/mutant/isolation.rb +9 -60
- data/lib/mutant/isolation/fork.rb +72 -0
- data/lib/mutant/isolation/none.rb +25 -0
- data/lib/mutant/matcher/config.rb +2 -0
- data/lib/mutant/matcher/method/singleton.rb +5 -4
- data/lib/mutant/meta.rb +11 -4
- data/lib/mutant/meta/example.rb +2 -116
- data/lib/mutant/meta/example/dsl.rb +22 -19
- data/lib/mutant/meta/example/verification.rb +86 -0
- data/lib/mutant/mutator.rb +22 -49
- data/lib/mutant/mutator/node.rb +15 -19
- data/lib/mutant/mutator/node/and_asgn.rb +1 -1
- data/lib/mutant/mutator/node/argument.rb +10 -5
- data/lib/mutant/mutator/node/arguments.rb +5 -9
- data/lib/mutant/mutator/node/begin.rb +4 -17
- data/lib/mutant/mutator/node/block.rb +1 -1
- data/lib/mutant/mutator/node/break.rb +1 -1
- data/lib/mutant/mutator/node/class.rb +21 -0
- data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
- data/lib/mutant/mutator/node/define.rb +1 -1
- data/lib/mutant/mutator/node/defined.rb +1 -1
- data/lib/mutant/mutator/node/dstr.rb +1 -1
- data/lib/mutant/mutator/node/dsym.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +3 -3
- data/lib/mutant/mutator/node/kwbegin.rb +1 -1
- data/lib/mutant/mutator/node/literal.rb +9 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
- data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
- data/lib/mutant/mutator/node/literal/float.rb +4 -6
- data/lib/mutant/mutator/node/literal/hash.rb +1 -1
- data/lib/mutant/mutator/node/literal/nil.rb +1 -1
- data/lib/mutant/mutator/node/literal/range.rb +2 -19
- data/lib/mutant/mutator/node/literal/regex.rb +43 -3
- data/lib/mutant/mutator/node/literal/string.rb +1 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
- data/lib/mutant/mutator/node/masgn.rb +1 -1
- data/lib/mutant/mutator/node/match_current_line.rb +1 -1
- data/lib/mutant/mutator/node/mlhs.rb +2 -3
- data/lib/mutant/mutator/node/named_value/access.rb +2 -2
- data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
- data/lib/mutant/mutator/node/next.rb +1 -1
- data/lib/mutant/mutator/node/nthref.rb +1 -1
- data/lib/mutant/mutator/node/or_asgn.rb +1 -1
- data/lib/mutant/mutator/node/regexp.rb +44 -0
- data/lib/mutant/mutator/node/regopt.rb +31 -0
- data/lib/mutant/mutator/node/resbody.rb +1 -1
- data/lib/mutant/mutator/node/rescue.rb +1 -3
- data/lib/mutant/mutator/node/return.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +43 -3
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
- data/lib/mutant/mutator/node/send/conditional.rb +23 -0
- data/lib/mutant/mutator/node/send/index.rb +1 -1
- data/lib/mutant/mutator/node/splat.rb +1 -1
- data/lib/mutant/mutator/node/when.rb +1 -1
- data/lib/mutant/mutator/node/yield.rb +1 -1
- data/lib/mutant/mutator/util.rb +0 -30
- data/lib/mutant/mutator/util/array.rb +4 -16
- data/lib/mutant/parallel.rb +1 -1
- data/lib/mutant/parallel/worker.rb +1 -1
- data/lib/mutant/registry.rb +44 -0
- data/lib/mutant/reporter/cli/format.rb +2 -0
- data/lib/mutant/reporter/cli/printer.rb +2 -2
- data/lib/mutant/reporter/cli/printer/config.rb +0 -1
- data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
- data/lib/mutant/reporter/cli/tput.rb +1 -1
- data/lib/mutant/reporter/sequence.rb +3 -0
- data/lib/mutant/require_highjack.rb +6 -2
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/subject.rb +5 -5
- data/lib/mutant/subject/method/instance.rb +1 -2
- data/lib/mutant/util.rb +18 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +5 -3
- data/meta/and.rb +1 -1
- data/meta/and_asgn.rb +1 -1
- data/meta/array.rb +2 -2
- data/meta/begin.rb +2 -2
- data/meta/block.rb +7 -7
- data/meta/block_pass.rb +1 -1
- data/meta/blockarg.rb +1 -1
- data/meta/break.rb +1 -1
- data/meta/case.rb +2 -2
- data/meta/casgn.rb +11 -2
- data/meta/cbase.rb +1 -1
- data/meta/class.rb +10 -0
- data/meta/const.rb +9 -1
- data/meta/csend.rb +8 -0
- data/meta/cvar.rb +1 -1
- data/meta/cvasgn.rb +1 -1
- data/meta/date.rb +4 -4
- data/meta/def.rb +14 -14
- data/meta/defined.rb +1 -1
- data/meta/dstr.rb +1 -1
- data/meta/dsym.rb +1 -1
- data/meta/ensure.rb +1 -1
- data/meta/false.rb +1 -1
- data/meta/float.rb +3 -3
- data/meta/gvar.rb +1 -1
- data/meta/gvasgn.rb +1 -1
- data/meta/hash.rb +1 -1
- data/meta/if.rb +17 -3
- data/meta/int.rb +1 -1
- data/meta/ivar.rb +1 -1
- data/meta/ivasgn.rb +14 -1
- data/meta/kwarg.rb +8 -0
- data/meta/kwbegin.rb +1 -1
- data/meta/kwoptarg.rb +11 -0
- data/meta/lvar.rb +1 -1
- data/meta/lvasgn.rb +1 -1
- data/meta/masgn.rb +1 -1
- data/meta/match_current_line.rb +2 -2
- data/meta/next.rb +1 -1
- data/meta/nil.rb +1 -1
- data/meta/nthref.rb +5 -5
- data/meta/op_assgn.rb +1 -1
- data/meta/or.rb +1 -1
- data/meta/or_asgn.rb +5 -5
- data/meta/range.rb +2 -8
- data/meta/redo.rb +1 -1
- data/meta/regexp.rb +106 -0
- data/meta/regexp/regexp_bol_anchor.rb +13 -0
- data/meta/regexp/regexp_bos_anchor.rb +26 -0
- data/meta/regexp/regexp_root_expression.rb +13 -0
- data/meta/regopt.rb +8 -0
- data/meta/rescue.rb +49 -4
- data/meta/restarg.rb +6 -9
- data/meta/return.rb +2 -2
- data/meta/self.rb +1 -1
- data/meta/send.rb +228 -55
- data/meta/str.rb +1 -1
- data/meta/super.rb +3 -3
- data/meta/{symbol.rb → sym.rb} +1 -1
- data/meta/true.rb +1 -1
- data/meta/until.rb +1 -1
- data/meta/while.rb +2 -2
- data/meta/yield.rb +1 -1
- data/mutant-rspec.gemspec +2 -2
- data/mutant.gemspec +6 -5
- data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
- data/spec/integrations.yml +93 -24
- data/spec/spec_helper.rb +12 -7
- data/spec/support/compress_helper.rb +1 -1
- data/spec/support/corpus.rb +115 -50
- data/spec/support/fake_actor.rb +5 -5
- data/spec/support/file_system.rb +1 -1
- data/spec/support/ice_nine_config.rb +3 -3
- data/spec/support/ruby_vm.rb +11 -12
- data/spec/support/shared_context.rb +22 -13
- data/spec/support/test_app.rb +1 -1
- data/spec/support/warning.rb +64 -0
- data/spec/support/warnings.yml +4 -0
- data/spec/support/xspec.rb +177 -0
- data/spec/unit/mutant/actor/env_spec.rb +2 -2
- data/spec/unit/mutant/actor/sender_spec.rb +1 -1
- data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
- data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
- data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
- data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
- data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
- data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
- data/spec/unit/mutant/cli_spec.rb +7 -45
- data/spec/unit/mutant/context_spec.rb +4 -7
- data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
- data/spec/unit/mutant/env_spec.rb +13 -16
- data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
- data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
- data/spec/unit/mutant/integration_spec.rb +14 -0
- data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
- data/spec/unit/mutant/isolation/none_spec.rb +16 -0
- data/spec/unit/mutant/loader_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
- data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
- data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
- data/spec/unit/mutant/meta/example_spec.rb +32 -0
- data/spec/unit/mutant/mutator/node_spec.rb +37 -4
- data/spec/unit/mutant/mutator_spec.rb +21 -0
- data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
- data/spec/unit/mutant/parallel/master_spec.rb +13 -13
- data/spec/unit/mutant/registry_spec.rb +47 -0
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
- data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
- data/spec/unit/mutant/repository/diff_spec.rb +6 -6
- data/spec/unit/mutant/require_highjack_spec.rb +38 -14
- data/spec/unit/mutant/result/env_spec.rb +1 -4
- data/spec/unit/mutant/runner_spec.rb +1 -1
- data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
- data/spec/unit/mutant/subject_spec.rb +3 -3
- data/spec/unit/mutant/util/one_spec.rb +20 -0
- data/spec/unit/mutant/zombifier_spec.rb +18 -18
- data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
- metadata +94 -24
- data/TODO +0 -21
- data/lib/mutant/mutator/node/blockarg.rb +0 -13
- data/lib/mutant/mutator/node/restarg.rb +0 -13
- data/lib/mutant/mutator/registry.rb +0 -49
- data/meta/boolean.rb +0 -13
- data/meta/regex.rb +0 -19
- data/spec/unit/mutant/isolation_spec.rb +0 -104
- data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -8,7 +8,7 @@ module Mutant
|
|
8
8
|
handle(:regexp)
|
9
9
|
|
10
10
|
# No input can ever be matched with this
|
11
|
-
NULL_REGEXP_SOURCE = '
|
11
|
+
NULL_REGEXP_SOURCE = 'nomatch\A'.freeze
|
12
12
|
|
13
13
|
private
|
14
14
|
|
@@ -19,11 +19,12 @@ module Mutant
|
|
19
19
|
children.last
|
20
20
|
end
|
21
21
|
|
22
|
-
# Emit
|
22
|
+
# Emit mutations
|
23
23
|
#
|
24
24
|
# @return [undefined]
|
25
25
|
def dispatch
|
26
|
-
|
26
|
+
mutate_body
|
27
|
+
emit_singletons unless parent_node
|
27
28
|
children.each_with_index do |child, index|
|
28
29
|
mutate_child(index) unless n_str?(child)
|
29
30
|
end
|
@@ -31,6 +32,45 @@ module Mutant
|
|
31
32
|
emit_type(s(:str, NULL_REGEXP_SOURCE), options)
|
32
33
|
end
|
33
34
|
|
35
|
+
# Mutate regexp body
|
36
|
+
#
|
37
|
+
# @note will only mutate parts of regexp body if the
|
38
|
+
# body is composed of only strings. Regular expressions
|
39
|
+
# with interpolation are skipped
|
40
|
+
#
|
41
|
+
# @return [undefined]
|
42
|
+
def mutate_body
|
43
|
+
return unless body.all?(&method(:n_str?))
|
44
|
+
return unless AST::Regexp.supported?(body_expression)
|
45
|
+
|
46
|
+
Mutator.mutate(body_ast).each do |mutation|
|
47
|
+
source = AST::Regexp.to_expression(mutation).to_s
|
48
|
+
emit_type(s(:str, source), options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# AST representation of regexp body
|
53
|
+
#
|
54
|
+
# @return [Parser::AST::Node]
|
55
|
+
def body_ast
|
56
|
+
AST::Regexp.to_ast(body_expression)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Expression representation of regexp body
|
60
|
+
#
|
61
|
+
# @return [Regexp::Expression]
|
62
|
+
def body_expression
|
63
|
+
AST::Regexp.parse(body.map(&:children).join)
|
64
|
+
end
|
65
|
+
memoize :body_expression
|
66
|
+
|
67
|
+
# Children of regexp node which compose regular expression source
|
68
|
+
#
|
69
|
+
# @return [Array<Parser::AST::Node>]
|
70
|
+
def body
|
71
|
+
children.slice(0...-1)
|
72
|
+
end
|
73
|
+
|
34
74
|
end # Regex
|
35
75
|
end # Literal
|
36
76
|
end # Node
|
@@ -13,14 +13,12 @@ module Mutant
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
# Emit
|
16
|
+
# Emit mutations
|
17
17
|
#
|
18
18
|
# @return [undefined]
|
19
19
|
def dispatch
|
20
20
|
emit_singletons
|
21
|
-
|
22
|
-
emit_type(value)
|
23
|
-
end
|
21
|
+
Util::Symbol.call(value).each(&method(:emit_type))
|
24
22
|
end
|
25
23
|
|
26
24
|
end # Symbol
|
@@ -33,7 +33,7 @@ module Mutant
|
|
33
33
|
super()
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
private
|
37
37
|
|
38
38
|
# Emit instance variable as attribute send
|
39
39
|
#
|
@@ -48,7 +48,7 @@ module Mutant
|
|
48
48
|
def attribute_name
|
49
49
|
name.slice(NAME_RANGE).to_sym
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end # Ivar
|
52
52
|
|
53
53
|
end # Access
|
54
54
|
end # NamedValue
|
@@ -12,12 +12,13 @@ module Mutant
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
#
|
15
|
+
# Emit mutations
|
16
16
|
#
|
17
17
|
# @return [undefined]
|
18
18
|
def dispatch
|
19
19
|
mutate_name
|
20
|
-
|
20
|
+
return unless value # op asgn
|
21
|
+
emit_value_mutations
|
21
22
|
emit_remove_const
|
22
23
|
end
|
23
24
|
|
@@ -32,7 +33,7 @@ module Mutant
|
|
32
33
|
#
|
33
34
|
# @return [undefined]
|
34
35
|
def mutate_name
|
35
|
-
|
36
|
+
Util::Symbol.call(name).each do |name|
|
36
37
|
emit_name(name.upcase)
|
37
38
|
end
|
38
39
|
end
|
@@ -16,20 +16,20 @@ module Mutant
|
|
16
16
|
}
|
17
17
|
|
18
18
|
MAP = IceNine.deep_freeze(
|
19
|
-
Hash[map.map { |type, prefix| [type, [prefix, /^#{Regexp.escape(prefix)}/]] }]
|
19
|
+
Hash[map.map { |type, prefix| [type, [prefix, /^#{::Regexp.escape(prefix)}/]] }]
|
20
20
|
)
|
21
21
|
|
22
22
|
handle(*MAP.keys)
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
#
|
26
|
+
# Emit mutations
|
27
27
|
#
|
28
28
|
# @return [undefined]
|
29
29
|
def dispatch
|
30
30
|
emit_singletons
|
31
31
|
mutate_name
|
32
|
-
emit_value_mutations if value #
|
32
|
+
emit_value_mutations if value # op asgn!
|
33
33
|
end
|
34
34
|
|
35
35
|
# Emit name mutations
|
@@ -38,7 +38,7 @@ module Mutant
|
|
38
38
|
def mutate_name
|
39
39
|
prefix, regexp = MAP.fetch(node.type)
|
40
40
|
stripped = name.to_s.sub(regexp, EMPTY_STRING)
|
41
|
-
|
41
|
+
Util::Symbol.call(stripped).each do |name|
|
42
42
|
emit_name(:"#{prefix}#{name}")
|
43
43
|
end
|
44
44
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
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
|
+
# Mutator for root expression regexp wrapper
|
17
|
+
class RootExpression < Node
|
18
|
+
handle(:regexp_root_expression)
|
19
|
+
|
20
|
+
# Emit mutations for children of root node
|
21
|
+
#
|
22
|
+
# @return [undefined]
|
23
|
+
def dispatch
|
24
|
+
children.each_index(&method(:mutate_child))
|
25
|
+
end
|
26
|
+
end # RootExpression
|
27
|
+
|
28
|
+
# Mutator for beginning of line anchor `^`
|
29
|
+
class BeginningOfLineAnchor < Node
|
30
|
+
handle(:regexp_bol_anchor)
|
31
|
+
|
32
|
+
# Emit mutations
|
33
|
+
#
|
34
|
+
# Replace `^` with `\A`
|
35
|
+
#
|
36
|
+
# @return [undefined]
|
37
|
+
def dispatch
|
38
|
+
emit(s(:regexp_bos_anchor))
|
39
|
+
end
|
40
|
+
end # BeginningOfLineAnchor
|
41
|
+
end # Regexp
|
42
|
+
end # Node
|
43
|
+
end # Mutator
|
44
|
+
end # Mutant
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
|
5
|
+
# Regular expression options mutation
|
6
|
+
class Regopt < self
|
7
|
+
|
8
|
+
MUTATED_FLAGS = IceNine.deep_freeze(%i[i])
|
9
|
+
|
10
|
+
handle(:regopt)
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# Emit mutations
|
15
|
+
#
|
16
|
+
# @return [undefined]
|
17
|
+
def dispatch
|
18
|
+
emit_type(*mutated_flags)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Altered flags array excluding case insensitive flag
|
22
|
+
#
|
23
|
+
# @return [Array<Symbol>]
|
24
|
+
def mutated_flags
|
25
|
+
(children - MUTATED_FLAGS)
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Regopt
|
29
|
+
end # Node
|
30
|
+
end # Mutator
|
31
|
+
end # Mutant
|
@@ -24,7 +24,7 @@ module Mutant
|
|
24
24
|
# @return [undefined]
|
25
25
|
def mutate_captures
|
26
26
|
return unless captures
|
27
|
-
Util::Array::Element.
|
27
|
+
Util::Array::Element.call(captures.children).each do |matchers|
|
28
28
|
next if matchers.any?(&method(:n_nil?))
|
29
29
|
emit_captures(s(:array, *matchers))
|
30
30
|
end
|
@@ -28,10 +28,8 @@ module Mutant
|
|
28
28
|
# @return [undefined]
|
29
29
|
def mutate_rescue_bodies
|
30
30
|
children_indices(RESCUE_INDICES).each do |index|
|
31
|
-
rescue_body = children.at(index)
|
32
|
-
next unless rescue_body
|
33
31
|
mutate_child(index)
|
34
|
-
resbody_body = AST::Meta::Resbody.new(
|
32
|
+
resbody_body = AST::Meta::Resbody.new(children.fetch(index)).body
|
35
33
|
emit_concat(resbody_body) if resbody_body
|
36
34
|
end
|
37
35
|
end
|
@@ -18,13 +18,19 @@ module Mutant
|
|
18
18
|
reverse_each: %i[each],
|
19
19
|
reverse_merge: %i[merge],
|
20
20
|
map: %i[each],
|
21
|
+
sample: %i[first last],
|
22
|
+
pop: %i[last],
|
23
|
+
shift: %i[first],
|
24
|
+
first: %i[last],
|
25
|
+
last: %i[first],
|
21
26
|
send: %i[public_send __send__],
|
22
27
|
__send__: %i[public_send],
|
28
|
+
method: %i[public_method],
|
23
29
|
gsub: %i[sub],
|
24
30
|
eql?: %i[equal?],
|
25
31
|
to_s: %i[to_str],
|
26
32
|
to_i: %i[to_int],
|
27
|
-
to_a: %i[to_ary],
|
33
|
+
to_a: %i[to_ary to_set],
|
28
34
|
to_h: %i[to_hash],
|
29
35
|
at: %i[fetch key?],
|
30
36
|
fetch: %i[key?],
|
@@ -45,7 +51,7 @@ module Mutant
|
|
45
51
|
|
46
52
|
private
|
47
53
|
|
48
|
-
#
|
54
|
+
# Emit mutations
|
49
55
|
#
|
50
56
|
# @return [undefined]
|
51
57
|
def dispatch
|
@@ -82,6 +88,7 @@ module Mutant
|
|
82
88
|
#
|
83
89
|
# @return [Enumerable<Parser::AST::Node>]
|
84
90
|
alias_method :arguments, :remaining_children
|
91
|
+
private :arguments
|
85
92
|
|
86
93
|
# Perform normal, non special case dispatch
|
87
94
|
#
|
@@ -102,6 +109,8 @@ module Mutant
|
|
102
109
|
def emit_selector_specific_mutations
|
103
110
|
emit_const_get_mutation
|
104
111
|
emit_integer_mutation
|
112
|
+
emit_dig_mutation
|
113
|
+
emit_drop_mutation
|
105
114
|
end
|
106
115
|
|
107
116
|
# Emit selector mutations specific to top level constants
|
@@ -116,6 +125,37 @@ module Mutant
|
|
116
125
|
.each(&method(:emit_selector))
|
117
126
|
end
|
118
127
|
|
128
|
+
# Emit mutation for `#dig`
|
129
|
+
#
|
130
|
+
# - Mutates `foo.dig(a, b)` to `foo.fetch(a).dig(b)`
|
131
|
+
# - Mutates `foo.dig(a)` to `foo.fetch(a)`
|
132
|
+
#
|
133
|
+
# @return [undefined]
|
134
|
+
def emit_dig_mutation
|
135
|
+
return if !selector.equal?(:dig) || arguments.none?
|
136
|
+
|
137
|
+
head, *tail = arguments
|
138
|
+
|
139
|
+
fetch_mutation = s(:send, receiver, :fetch, head)
|
140
|
+
|
141
|
+
return emit(fetch_mutation) if tail.empty?
|
142
|
+
|
143
|
+
emit(s(:send, fetch_mutation, :dig, *tail))
|
144
|
+
end
|
145
|
+
|
146
|
+
# Emit mutation `foo[n..-1]` -> `foo.drop(n)`
|
147
|
+
#
|
148
|
+
# @return [undefined]
|
149
|
+
def emit_drop_mutation
|
150
|
+
return if !selector.equal?(:[]) || !arguments.one? || !n_irange?(arguments.first)
|
151
|
+
|
152
|
+
start, ending = *arguments.first
|
153
|
+
|
154
|
+
return unless ending.eql?(s(:int, -1))
|
155
|
+
|
156
|
+
emit(s(:send, receiver, :drop, start))
|
157
|
+
end
|
158
|
+
|
119
159
|
# Emit mutation from `to_i` to `Integer(...)`
|
120
160
|
#
|
121
161
|
# @return [undefined]
|
@@ -145,7 +185,7 @@ module Mutant
|
|
145
185
|
#
|
146
186
|
# @return [undefined]
|
147
187
|
def emit_naked_receiver
|
148
|
-
emit(receiver) if receiver
|
188
|
+
emit(receiver) if receiver
|
149
189
|
end
|
150
190
|
|
151
191
|
# Mutate arguments
|
@@ -5,6 +5,9 @@ module Mutant
|
|
5
5
|
# Mutator for attribute assignments
|
6
6
|
class AttributeAssignment < self
|
7
7
|
|
8
|
+
ATTRIBUTE_RANGE = (0..-2).freeze
|
9
|
+
private_constant(*constants(false))
|
10
|
+
|
8
11
|
private
|
9
12
|
|
10
13
|
# Emit mutations
|
@@ -28,7 +31,7 @@ module Mutant
|
|
28
31
|
#
|
29
32
|
# @return [undefined]
|
30
33
|
def emit_attribute_read
|
31
|
-
emit_type(receiver, selector
|
34
|
+
emit_type(receiver, selector[ATTRIBUTE_RANGE].to_sym)
|
32
35
|
end
|
33
36
|
|
34
37
|
end # AttributeAssignment
|