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.
- checksums.yaml +4 -4
- data/bin/mutant +55 -46
- data/lib/mutant/bootstrap.rb +66 -35
- data/lib/mutant/cli/command/environment/run.rb +1 -1
- data/lib/mutant/cli/command/environment.rb +2 -2
- data/lib/mutant/cli/command.rb +24 -11
- data/lib/mutant/env.rb +9 -0
- data/lib/mutant/mutator/node/literal/regex.rb +8 -8
- data/lib/mutant/mutator/node/send.rb +27 -17
- data/lib/mutant/mutator/regexp.rb +211 -0
- data/lib/mutant/parallel/driver.rb +1 -0
- data/lib/mutant/parallel/worker.rb +5 -1
- data/lib/mutant/runner.rb +8 -6
- data/lib/mutant/segment/recorder.rb +124 -0
- data/lib/mutant/segment.rb +25 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/world.rb +5 -0
- data/lib/mutant.rb +288 -228
- metadata +12 -33
- data/lib/mutant/ast/regexp/transformer/direct.rb +0 -145
- data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -50
- data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -68
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -92
- data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -56
- data/lib/mutant/ast/regexp/transformer/root.rb +0 -28
- data/lib/mutant/ast/regexp/transformer/text.rb +0 -58
- data/lib/mutant/ast/regexp/transformer.rb +0 -152
- data/lib/mutant/ast/regexp.rb +0 -54
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -20
- data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -23
- data/lib/mutant/mutator/node/regexp/character_type.rb +0 -31
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -20
- data/lib/mutant/mutator/node/regexp/named_group.rb +0 -39
- data/lib/mutant/mutator/node/regexp/zero_or_more.rb +0 -34
- 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
|
data/lib/mutant/ast/regexp.rb
DELETED
@@ -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
|