mutant 0.11.16 → 0.11.18

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.
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