mutant 0.11.16 → 0.11.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mutant +55 -46
  3. data/lib/mutant/bootstrap.rb +66 -35
  4. data/lib/mutant/cli/command/environment/run.rb +1 -1
  5. data/lib/mutant/cli/command/environment.rb +2 -2
  6. data/lib/mutant/cli/command.rb +24 -11
  7. data/lib/mutant/env.rb +9 -0
  8. data/lib/mutant/mutator/node/literal/regex.rb +8 -8
  9. data/lib/mutant/mutator/node/send.rb +27 -17
  10. data/lib/mutant/mutator/regexp.rb +211 -0
  11. data/lib/mutant/parallel/driver.rb +1 -0
  12. data/lib/mutant/parallel/worker.rb +5 -1
  13. data/lib/mutant/runner.rb +8 -6
  14. data/lib/mutant/segment/recorder.rb +124 -0
  15. data/lib/mutant/segment.rb +25 -0
  16. data/lib/mutant/version.rb +1 -1
  17. data/lib/mutant/world.rb +5 -0
  18. data/lib/mutant.rb +288 -228
  19. metadata +12 -33
  20. data/lib/mutant/ast/regexp/transformer/direct.rb +0 -145
  21. data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -50
  22. data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -68
  23. data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -92
  24. data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -56
  25. data/lib/mutant/ast/regexp/transformer/root.rb +0 -28
  26. data/lib/mutant/ast/regexp/transformer/text.rb +0 -58
  27. data/lib/mutant/ast/regexp/transformer.rb +0 -152
  28. data/lib/mutant/ast/regexp.rb +0 -54
  29. data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -20
  30. data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +0 -20
  31. data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -23
  32. data/lib/mutant/mutator/node/regexp/character_type.rb +0 -31
  33. data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -20
  34. data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -20
  35. data/lib/mutant/mutator/node/regexp/named_group.rb +0 -39
  36. data/lib/mutant/mutator/node/regexp/zero_or_more.rb +0 -34
  37. data/lib/mutant/mutator/node/regexp.rb +0 -20
@@ -1,152 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class AST
5
- module Regexp
6
- # Regexp bijective mapper
7
- #
8
- # Transforms parsed regular expression representation from
9
- # `Regexp::Expression` instances (provided by `regexp_parser`) into
10
- # equivalent representations using `Parser::AST::Node`
11
- class Transformer
12
- include AbstractType
13
-
14
- REGISTRY = Registry.new(
15
- ->(type) { fail "No regexp transformer registered for: #{type}" }
16
- )
17
-
18
- # Lookup transformer class for regular expression node type
19
- #
20
- # @param type [Symbol]
21
- #
22
- # @return [Class<Transformer>]
23
- def self.lookup(type)
24
- REGISTRY.lookup(type)
25
- end
26
-
27
- def self.register(type)
28
- REGISTRY.register(type, self)
29
- end
30
- private_class_method :register
31
-
32
- # Transform expression
33
- #
34
- # @param expression [Regexp::Expression]
35
- #
36
- # @return [Parser::AST::Node]
37
- def self.to_ast(expression)
38
- self::ExpressionToAST.call(expression)
39
- end
40
-
41
- # Transform node
42
- #
43
- # @param node [Parser::AST::Node]
44
- #
45
- # @return [Regexp::Expression]
46
- def self.to_expression(node)
47
- self::ASTToExpression.call(node)
48
- end
49
-
50
- # Abstract expression transformer
51
- class ExpressionToAST
52
- PREFIX = :regexp
53
-
54
- include Concord.new(:expression), Procto, AST::Sexp, AbstractType, Adamantium
55
-
56
- private
57
-
58
- def ast(*children)
59
- s(type, *children)
60
- end
61
-
62
- def quantify(node)
63
- return node unless expression.quantified?
64
-
65
- Quantifier.to_ast(expression.quantifier).append(node)
66
- end
67
-
68
- def children
69
- expression.map(&Regexp.public_method(:to_ast))
70
- end
71
-
72
- def type
73
- :"#{PREFIX}_#{expression.token}_#{expression.type}"
74
- end
75
- end # ExpressionToAST
76
-
77
- # Abstract node transformer
78
- class ASTToExpression
79
- include Concord.new(:node), Procto, AbstractType, Adamantium
80
-
81
- # Call generic transform method and freeze result
82
- #
83
- # @return [Regexp::Expression]
84
- def call
85
- transform.freeze
86
- end
87
-
88
- private
89
-
90
- abstract_method :transform
91
-
92
- def subexpressions
93
- node.children.map(&Regexp.public_method(:to_expression))
94
- end
95
- end # ASTToExpression
96
-
97
- # Mixin for node transformers
98
- #
99
- # Helps construct a mapping from Parser::AST::Node domain to
100
- # Regexp::Expression domain
101
- module LookupTable
102
- Mapping = Class.new.include(Concord::Public.new(:token, :regexp_class))
103
-
104
- # Table mapping ast types to object information for regexp domain
105
- class Table
106
-
107
- # Coerce array of mapping information into structured table
108
- #
109
- # @param [Array(Symbol, Array, Class<Regexp::Expression>)]
110
- #
111
- # @return [Table]
112
- def self.create(*rows)
113
- table = rows.to_h do |ast_type, token, klass|
114
- [ast_type, Mapping.new(::Regexp::Token.new(*token), klass)]
115
- end
116
-
117
- new(table)
118
- end
119
-
120
- include Concord.new(:table), Adamantium
121
-
122
- # Types defined by the table
123
- #
124
- # @return [Array<Symbol>]
125
- def types
126
- table.keys
127
- end
128
-
129
- # Lookup mapping information given an ast node type
130
- #
131
- # @param type [Symbol]
132
- #
133
- # @return [Mapping]
134
- def lookup(type)
135
- table.fetch(type)
136
- end
137
- end # Table
138
-
139
- private
140
-
141
- def expression_token
142
- self.class::TABLE.lookup(node.type).token
143
- end
144
-
145
- def expression_class
146
- self.class::TABLE.lookup(node.type).regexp_class
147
- end
148
- end # LookupTable
149
- end # Transformer
150
- end # Regexp
151
- end # AST
152
- end # Mutant
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class AST
5
- # Regexp source mapper
6
- module Regexp
7
- # Parse regex string into expression
8
- #
9
- # @param regexp [String]
10
- #
11
- # @return [Regexp::Expression, nil]
12
- def self.parse(regexp)
13
- ::Regexp::Parser.parse(regexp)
14
- end
15
-
16
- # Convert expression into ast node
17
- #
18
- # @param expression [Regexp::Expression]
19
- #
20
- # @return [Parser::AST::Node]
21
- def self.to_ast(expression)
22
- ast_type = :"regexp_#{expression.token}_#{expression.type}"
23
-
24
- Transformer.lookup(ast_type).to_ast(expression)
25
- end
26
-
27
- # Convert node into expression
28
- #
29
- # @param node [Parser::AST::Node]
30
- #
31
- # @return [Regexp::Expression]
32
- def self.to_expression(node)
33
- Transformer.lookup(node.type).to_expression(node)
34
- end
35
-
36
- # Convert's a `parser` `regexp` node into more fine-grained AST nodes.
37
- #
38
- # @param node [Parser::AST::Node]
39
- #
40
- # @return [Parser::AST::Node]
41
- def self.expand_regexp_ast(node)
42
- *body, _opts = node.children
43
-
44
- # NOTE: We only mutate parts of regexp body if the body is composed of
45
- # only strings. Regular expressions with interpolation are skipped
46
- return unless body.all? { |child| child.type.equal?(:str) }
47
-
48
- body_expression = parse(body.map(&:children).join)
49
-
50
- to_ast(body_expression)
51
- end
52
- end # Regexp
53
- end # AST
54
- end # Mutant
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for pipe in `/foo|bar/` regexp
8
- class AlternationMeta < Node
9
- handle(:regexp_alternation_meta)
10
-
11
- private
12
-
13
- def dispatch
14
- children.each_index(&method(:delete_child))
15
- end
16
- end # AlternationMeta
17
- end # Regexp
18
- end # Node
19
- end # Mutator
20
- end # Mutant
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for beginning of line anchor `^`
8
- class BeginningOfLineAnchor < Node
9
- handle(:regexp_bol_anchor)
10
-
11
- private
12
-
13
- def dispatch
14
- emit(s(:regexp_bos_anchor))
15
- end
16
- end # BeginningOfLineAnchor
17
- end # Regexp
18
- end # Node
19
- end # Mutator
20
- end # Mutant
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for regexp capture groups, such as `/(foo)/`
8
- class CaptureGroup < Node
9
- handle(:regexp_capture_group)
10
-
11
- private
12
-
13
- def dispatch
14
- return if children.empty?
15
-
16
- emit(s(:regexp_passive_group, *children))
17
- children.each_index(&method(:mutate_child))
18
- end
19
- end # EndOfLineAnchor
20
- end # Regexp
21
- end # Node
22
- end # Mutator
23
- end # Mutant
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Character type mutator
8
- class CharacterType < Node
9
- map = {
10
- regexp_digit_type: :regexp_nondigit_type,
11
- regexp_hex_type: :regexp_nonhex_type,
12
- regexp_space_type: :regexp_nonspace_type,
13
- regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
14
- regexp_word_type: :regexp_nonword_type,
15
- regexp_xgrapheme_type: :regexp_linebreak_type
16
- }
17
-
18
- MAP = map.merge(map.invert)
19
-
20
- handle(*MAP.keys)
21
-
22
- private
23
-
24
- def dispatch
25
- emit(s(MAP.fetch(node.type)))
26
- end
27
- end # CharacterType
28
- end # Regexp
29
- end # Node
30
- end # Mutator
31
- end # Mutant
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for end of line anchor `$`
8
- class EndOfLineAnchor < Node
9
- handle(:regexp_eol_anchor)
10
-
11
- private
12
-
13
- def dispatch
14
- emit(s(:regexp_eos_anchor))
15
- end
16
- end # EndOfLineAnchor
17
- end # Regexp
18
- end # Node
19
- end # Mutator
20
- end # Mutant
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for end of line or before end of string anchor `\Z`
8
- class EndOfStringOrBeforeEndOfLineAnchor < Node
9
- handle(:regexp_eos_ob_eol_anchor)
10
-
11
- private
12
-
13
- def dispatch
14
- emit(s(:regexp_eos_anchor))
15
- end
16
- end # EndOfStringOrBeforeEndOfLineAnchor
17
- end # Regexp
18
- end # Node
19
- end # Mutator
20
- end # Mutant
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for regexp named capture groups, such as `/(?<foo>bar)/`
8
- class NamedGroup < Node
9
- handle(:regexp_named_group)
10
-
11
- children :name
12
-
13
- private
14
-
15
- def dispatch
16
- return if remaining_children.empty?
17
-
18
- remaining_children_indices.each(&method(:mutate_child))
19
-
20
- # Allows unused captures to be kept and named if they are explicitly prefixed with an
21
- # underscore, like we allow with unused local variables.
22
- return if name_underscored?
23
-
24
- emit(s(:regexp_passive_group, *remaining_children))
25
- emit_name_underscore_mutation
26
- end
27
-
28
- def emit_name_underscore_mutation
29
- emit_type("_#{name}", *remaining_children)
30
- end
31
-
32
- def name_underscored?
33
- name.start_with?('_')
34
- end
35
- end # EndOfLineAnchor
36
- end # Regexp
37
- end # Node
38
- end # Mutator
39
- end # Mutant
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for zero-or-more quantifier, `*`
8
- class ZeroOrMore < Node
9
- MAP = {
10
- regexp_greedy_zero_or_more: :regexp_greedy_one_or_more,
11
- regexp_reluctant_zero_or_more: :regexp_reluctant_one_or_more,
12
- regexp_possessive_zero_or_more: :regexp_possessive_one_or_more
13
- }.freeze
14
-
15
- handle(*MAP.keys)
16
-
17
- children :min, :max, :subject
18
-
19
- private
20
-
21
- # Replace:
22
- # * `/a*/` with `/a+/`
23
- # * `/a*?/` with `/a+?/`
24
- # * `/a*+/` with `/a++/`
25
- def dispatch
26
- emit(s(MAP.fetch(node.type), *children))
27
- emit_subject_mutations
28
- emit(subject)
29
- end
30
- end # ZeroOrMore
31
- end # Regexp
32
- end # Node
33
- end # Mutator
34
- end # Mutant
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mutant
4
- class Mutator
5
- class Node
6
- module Regexp
7
- # Mutator for root expression regexp wrapper
8
- class RootExpression < Node
9
- handle(:regexp_root_expression)
10
-
11
- private
12
-
13
- def dispatch
14
- children.each_index(&method(:mutate_child))
15
- end
16
- end # RootExpression
17
- end # Regexp
18
- end # Node
19
- end # Mutator
20
- end # Mutant