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
@@ -0,0 +1,55 @@
|
|
1
|
+
module Mutant
|
2
|
+
module AST
|
3
|
+
module Regexp
|
4
|
+
class Transformer
|
5
|
+
# Regexp AST transformer for nodes that encode a text value
|
6
|
+
class Text < self
|
7
|
+
# Mapper from `Regexp::Expression` to `Parser::AST::Node`
|
8
|
+
class ExpressionToAST < Transformer::ExpressionToAST
|
9
|
+
# Transform expression into node preserving text value
|
10
|
+
#
|
11
|
+
# @return [Parser::AST::Node]
|
12
|
+
def call
|
13
|
+
quantify(ast(expression.text))
|
14
|
+
end
|
15
|
+
end # ExpressionToAST
|
16
|
+
|
17
|
+
# Mapper from `Parser::AST::Node` to `Regexp::Expression`
|
18
|
+
class ASTToExpression < Transformer::ASTToExpression
|
19
|
+
include LookupTable
|
20
|
+
|
21
|
+
TABLE = Table.create(
|
22
|
+
[:regexp_literal_literal, %i[literal literal], ::Regexp::Expression::Literal],
|
23
|
+
[:regexp_comment_group, %i[group comment], ::Regexp::Expression::Group::Comment],
|
24
|
+
[:regexp_named_group, %i[group named], ::Regexp::Expression::Group::Named],
|
25
|
+
[:regexp_number_backref, %i[backref number], ::Regexp::Expression::Backreference::Number],
|
26
|
+
[:regexp_name_call_backref, %i[backref name_call], ::Regexp::Expression::Backreference::NameCall],
|
27
|
+
[:regexp_whitespace_free_space, %i[free_space whitespace], ::Regexp::Expression::WhiteSpace],
|
28
|
+
[:regexp_comment_free_space, %i[free_space comment], ::Regexp::Expression::WhiteSpace],
|
29
|
+
[:regexp_hex_escape, %i[escape hex], ::Regexp::Expression::EscapeSequence::Literal],
|
30
|
+
[:regexp_literal_escape, %i[escape literal], ::Regexp::Expression::EscapeSequence::Literal],
|
31
|
+
[:regexp_backslash_escape, %i[escape backslash], ::Regexp::Expression::EscapeSequence::Literal],
|
32
|
+
[:regexp_tab_escape, %i[escape tab], ::Regexp::Expression::EscapeSequence::Literal],
|
33
|
+
[:regexp_codepoint_list_escape, %i[escape codepoint_list], ::Regexp::Expression::EscapeSequence::Literal],
|
34
|
+
[:regexp_control_escape, %i[escape control], ::Regexp::Expression::EscapeSequence::Control],
|
35
|
+
[:regexp_meta_sequence_escape, %i[escape meta_sequence], ::Regexp::Expression::EscapeSequence::Control]
|
36
|
+
)
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Transform node to expression with text value
|
41
|
+
#
|
42
|
+
# @return [Regexp::Expression]
|
43
|
+
def transform
|
44
|
+
token = expression_token.dup
|
45
|
+
token.text = Util.one(node.children)
|
46
|
+
expression_class.new(token)
|
47
|
+
end
|
48
|
+
end # ASTToExpression
|
49
|
+
|
50
|
+
ASTToExpression::TABLE.types.each(&method(:register))
|
51
|
+
end # Text
|
52
|
+
end # Transformer
|
53
|
+
end # Regexp
|
54
|
+
end # AST
|
55
|
+
end # Mutant
|
data/lib/mutant/ast/types.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
module Mutant
|
2
2
|
module AST
|
3
3
|
# Groups of node types
|
4
|
+
#
|
5
|
+
# :reek:TooManyConstants
|
6
|
+
# rubocop:disable Metrics/ModuleLength
|
4
7
|
module Types
|
5
8
|
symbolset = ->(strings) { strings.map(&:to_sym).to_set.freeze }
|
6
9
|
|
@@ -38,15 +41,99 @@ module Mutant
|
|
38
41
|
#
|
39
42
|
BLACKLIST = symbolset.(%w[not])
|
40
43
|
|
44
|
+
# Nodes generated by regular expression body parsing
|
45
|
+
REGEXP = symbolset.(%w[
|
46
|
+
regexp_alpha_property
|
47
|
+
regexp_alternation_escape
|
48
|
+
regexp_alternation_meta
|
49
|
+
regexp_atomic_group
|
50
|
+
regexp_backslash_escape
|
51
|
+
regexp_bell_escape
|
52
|
+
regexp_bol_anchor
|
53
|
+
regexp_bos_anchor
|
54
|
+
regexp_capture_group
|
55
|
+
regexp_carriage_escape
|
56
|
+
regexp_character_set
|
57
|
+
regexp_character_set
|
58
|
+
regexp_codepoint_list_escape
|
59
|
+
regexp_comment_free_space
|
60
|
+
regexp_comment_group
|
61
|
+
regexp_control_escape
|
62
|
+
regexp_digit_type
|
63
|
+
regexp_dot_escape
|
64
|
+
regexp_dot_meta
|
65
|
+
regexp_eol_anchor
|
66
|
+
regexp_eol_escape
|
67
|
+
regexp_eos_anchor
|
68
|
+
regexp_eos_ob_eol_anchor
|
69
|
+
regexp_escape_escape
|
70
|
+
regexp_form_feed_escape
|
71
|
+
regexp_greedy_interval
|
72
|
+
regexp_greedy_one_or_more
|
73
|
+
regexp_greedy_zero_or_more
|
74
|
+
regexp_greedy_zero_or_one
|
75
|
+
regexp_group_close_escape
|
76
|
+
regexp_group_open_escape
|
77
|
+
regexp_hex_escape
|
78
|
+
regexp_hex_type
|
79
|
+
regexp_interval_close_escape
|
80
|
+
regexp_interval_open_escape
|
81
|
+
regexp_letter_any_property
|
82
|
+
regexp_literal_escape
|
83
|
+
regexp_literal_literal
|
84
|
+
regexp_lookahead_assertion
|
85
|
+
regexp_lookbehind_assertion
|
86
|
+
regexp_mark_keep
|
87
|
+
regexp_match_start_anchor
|
88
|
+
regexp_meta_sequence_escape
|
89
|
+
regexp_name_call_backref
|
90
|
+
regexp_named_group
|
91
|
+
regexp_newline_escape
|
92
|
+
regexp_nlookahead_assertion
|
93
|
+
regexp_nlookbehind_assertion
|
94
|
+
regexp_nondigit_type
|
95
|
+
regexp_nonspace_type
|
96
|
+
regexp_nonword_boundary_anchor
|
97
|
+
regexp_nonword_type
|
98
|
+
regexp_nonhex_type
|
99
|
+
regexp_number_backref
|
100
|
+
regexp_one_or_more_escape
|
101
|
+
regexp_open_conditional
|
102
|
+
regexp_options_group
|
103
|
+
regexp_passive_group
|
104
|
+
regexp_possessive_interval
|
105
|
+
regexp_possessive_one_or_more
|
106
|
+
regexp_possessive_zero_or_more
|
107
|
+
regexp_possessive_zero_or_one
|
108
|
+
regexp_reluctant_interval
|
109
|
+
regexp_reluctant_one_or_more
|
110
|
+
regexp_reluctant_zero_or_more
|
111
|
+
regexp_root_expression
|
112
|
+
regexp_script_arabic_property
|
113
|
+
regexp_script_han_property
|
114
|
+
regexp_script_hangul_property
|
115
|
+
regexp_script_hiragana_property
|
116
|
+
regexp_script_katakana_property
|
117
|
+
regexp_sequence_expression
|
118
|
+
regexp_set_close_escape
|
119
|
+
regexp_set_open_escape
|
120
|
+
regexp_space_type
|
121
|
+
regexp_tab_escape
|
122
|
+
regexp_vertical_tab_escape
|
123
|
+
regexp_whitespace_free_space
|
124
|
+
regexp_word_boundary_anchor
|
125
|
+
regexp_word_type
|
126
|
+
regexp_zero_or_more_escape
|
127
|
+
regexp_zero_or_one_escape
|
128
|
+
])
|
129
|
+
|
41
130
|
# Nodes that are NOT generated by parser but used by mutant / unparser.
|
42
|
-
|
131
|
+
GENERATED = symbolset.(%w[empty])
|
43
132
|
|
44
|
-
|
45
|
-
# * https://github.com/whitequark/parser/pull/251
|
46
|
-
MISSING = symbolset.(%w[csend])
|
133
|
+
EXTRA = symbolset.(GENERATED + REGEXP)
|
47
134
|
|
48
135
|
# All node types mutant handles
|
49
|
-
ALL = symbolset.((Parser::Meta::NODE_TYPES + EXTRA
|
136
|
+
ALL = symbolset.((Parser::Meta::NODE_TYPES + EXTRA) - BLACKLIST)
|
50
137
|
end # Types
|
51
138
|
end # AST
|
52
139
|
end # Mutant
|
data/lib/mutant/cli.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
module Mutant
|
2
|
-
|
3
|
-
# Commandline parser
|
4
|
-
#
|
5
|
-
# rubocop:disable ClassLength
|
2
|
+
# Commandline parser / runner
|
6
3
|
class CLI
|
7
4
|
include Adamantium::Flat, Equalizer.new(:config), Procto.call(:config)
|
8
5
|
|
@@ -103,7 +100,7 @@ module Mutant
|
|
103
100
|
#
|
104
101
|
# @return [undefined]
|
105
102
|
def setup_integration(name)
|
106
|
-
with(integration: Integration.setup(name))
|
103
|
+
with(integration: Integration.setup(config.kernel, name))
|
107
104
|
rescue LoadError
|
108
105
|
raise Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})"
|
109
106
|
end
|
@@ -117,12 +114,6 @@ module Mutant
|
|
117
114
|
opts.separator(nil)
|
118
115
|
opts.separator('Options:')
|
119
116
|
|
120
|
-
opts.on(
|
121
|
-
'--expected-coverage COVERAGE',
|
122
|
-
'Fail unless COVERAGE is not reached exactly, parsed via Rational()'
|
123
|
-
) do |coverage|
|
124
|
-
with(expected_coverage: Rational(coverage))
|
125
|
-
end
|
126
117
|
opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations', &method(:setup_integration))
|
127
118
|
end
|
128
119
|
|
@@ -162,9 +153,6 @@ module Mutant
|
|
162
153
|
puts("mutant-#{VERSION}")
|
163
154
|
config.kernel.exit
|
164
155
|
end
|
165
|
-
opts.on('-d', '--debug', 'Enable debugging output') do
|
166
|
-
with(debug: true)
|
167
|
-
end
|
168
156
|
opts.on_tail('-h', '--help', 'Show this message') do
|
169
157
|
puts(opts.to_s)
|
170
158
|
config.kernel.exit
|
data/lib/mutant/color.rb
CHANGED
data/lib/mutant/config.rb
CHANGED
@@ -5,8 +5,6 @@ module Mutant
|
|
5
5
|
# to current environment is being represented by the Mutant::Env object.
|
6
6
|
class Config
|
7
7
|
include Adamantium::Flat, Anima.new(
|
8
|
-
:debug,
|
9
|
-
:expected_coverage,
|
10
8
|
:expression_parser,
|
11
9
|
:fail_fast,
|
12
10
|
:integration,
|
@@ -23,7 +21,7 @@ module Mutant
|
|
23
21
|
:zombie
|
24
22
|
)
|
25
23
|
|
26
|
-
%i[fail_fast zombie
|
24
|
+
%i[fail_fast zombie].each do |name|
|
27
25
|
define_method(:"#{name}?") { public_send(name) }
|
28
26
|
end
|
29
27
|
|
@@ -57,7 +57,7 @@ module Mutant
|
|
57
57
|
MATCHER = Matcher::Scope
|
58
58
|
private_constant(*constants(false))
|
59
59
|
|
60
|
-
REGEXP
|
60
|
+
REGEXP = /\A#{SCOPE_NAME_PATTERN}\z/.freeze
|
61
61
|
|
62
62
|
# Matcher matcher on expression
|
63
63
|
#
|
@@ -74,5 +74,5 @@ module Mutant
|
|
74
74
|
|
75
75
|
end # Exact
|
76
76
|
end # Namespace
|
77
|
-
end #
|
77
|
+
end # Expression
|
78
78
|
end # Mutant
|
data/lib/mutant/integration.rb
CHANGED
@@ -4,38 +4,23 @@ module Mutant
|
|
4
4
|
class Integration
|
5
5
|
include AbstractType, Adamantium::Flat, Concord.new(:config)
|
6
6
|
|
7
|
-
REGISTRY = {}
|
8
|
-
|
9
7
|
# Setup integration
|
10
8
|
#
|
11
|
-
#
|
9
|
+
# Integrations are supposed to define a constant under
|
10
|
+
# Mutant::Integration named after the capitalized +name+
|
11
|
+
# parameter.
|
12
12
|
#
|
13
|
-
#
|
14
|
-
def self.setup(name)
|
15
|
-
require "mutant/integration/#{name}"
|
16
|
-
lookup(name)
|
17
|
-
end
|
18
|
-
|
19
|
-
# Lookup integration for name
|
13
|
+
# This avoids having to maintain a mutable registry.
|
20
14
|
#
|
21
|
-
# @param [
|
15
|
+
# @param kernel [Kernel]
|
16
|
+
# @param name [String]
|
22
17
|
#
|
23
|
-
# @return [Integration]
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
# @return [Class<Integration>]
|
19
|
+
def self.setup(kernel, name)
|
20
|
+
kernel.require("mutant/integration/#{name}")
|
21
|
+
const_get(name.capitalize)
|
27
22
|
end
|
28
23
|
|
29
|
-
# Register integration
|
30
|
-
#
|
31
|
-
# @param [String] name
|
32
|
-
#
|
33
|
-
# @return [undefined]
|
34
|
-
def self.register(name)
|
35
|
-
REGISTRY[name] = self
|
36
|
-
end
|
37
|
-
private_class_method :register
|
38
|
-
|
39
24
|
# Perform integration setup
|
40
25
|
#
|
41
26
|
# @return [self]
|
@@ -67,8 +52,6 @@ module Mutant
|
|
67
52
|
# Null integration that never kills a mutation
|
68
53
|
class Null < self
|
69
54
|
|
70
|
-
register('null')
|
71
|
-
|
72
55
|
# Available tests for integration
|
73
56
|
#
|
74
57
|
# @return [Enumerable<Test>]
|
@@ -91,6 +74,5 @@ module Mutant
|
|
91
74
|
end
|
92
75
|
|
93
76
|
end # Null
|
94
|
-
|
95
77
|
end # Integration
|
96
78
|
end # Mutant
|
data/lib/mutant/isolation.rb
CHANGED
@@ -1,62 +1,11 @@
|
|
1
1
|
module Mutant
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
# @raise [Error]
|
13
|
-
# if block terminates abnormal
|
14
|
-
def self.call(&block)
|
15
|
-
block.call
|
16
|
-
rescue => exception
|
17
|
-
raise Error, exception
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module Fork
|
22
|
-
|
23
|
-
# Call block in isolation
|
24
|
-
#
|
25
|
-
# This isolation implements the fork strategy.
|
26
|
-
# Future strategies will probably use a process pool that can
|
27
|
-
# handle multiple mutation kills, in-isolation at once.
|
28
|
-
#
|
29
|
-
# @return [Object]
|
30
|
-
# returns block execution result
|
31
|
-
#
|
32
|
-
# @raise [Error]
|
33
|
-
# if block terminates abnormal
|
34
|
-
#
|
35
|
-
# rubocop:disable MethodLength
|
36
|
-
def self.call(&block)
|
37
|
-
IO.pipe(binmode: true) do |reader, writer|
|
38
|
-
writer.binmode
|
39
|
-
begin
|
40
|
-
pid = Process.fork do
|
41
|
-
File.open(File::NULL, File::WRONLY) do |file|
|
42
|
-
$stderr.reopen(file)
|
43
|
-
reader.close
|
44
|
-
writer.write(Marshal.dump(block.call))
|
45
|
-
writer.close
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
writer.close
|
50
|
-
Marshal.load(reader.read)
|
51
|
-
ensure
|
52
|
-
Process.waitpid(pid) if pid
|
53
|
-
end
|
54
|
-
end
|
55
|
-
rescue => exception
|
56
|
-
raise Error, exception
|
57
|
-
end
|
58
|
-
|
59
|
-
end # Fork
|
60
|
-
|
61
|
-
end # Isolator
|
2
|
+
class Isolation
|
3
|
+
include AbstractType
|
4
|
+
|
5
|
+
# Call block in isolation
|
6
|
+
#
|
7
|
+
# @return [Object]
|
8
|
+
# the blocks result
|
9
|
+
abstract_method :call
|
10
|
+
end # Isolation
|
62
11
|
end # Mutant
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Isolation
|
3
|
+
# Isolation via the fork(2) systemcall.
|
4
|
+
#
|
5
|
+
# We do inject so many globals and common patterns to make this unit
|
6
|
+
# specifiable without mocking the globals and more important: Not having
|
7
|
+
# mutations that bypass mocks into a real world side effect.
|
8
|
+
class Fork < self
|
9
|
+
include Anima.new(:process, :stderr, :stdout, :io, :devnull, :marshal)
|
10
|
+
|
11
|
+
# Prevent mutation from `process.fork` to `fork` to call Kernel#fork
|
12
|
+
undef_method :fork
|
13
|
+
|
14
|
+
# Call block in isolation
|
15
|
+
#
|
16
|
+
# @return [Object]
|
17
|
+
# returns block execution result
|
18
|
+
#
|
19
|
+
# @raise [Error]
|
20
|
+
# if block terminates abnormal
|
21
|
+
def call(&block)
|
22
|
+
io.pipe(binmode: true) do |pipes|
|
23
|
+
parent(*pipes, &block)
|
24
|
+
end
|
25
|
+
rescue => exception
|
26
|
+
raise Error, exception
|
27
|
+
end
|
28
|
+
|
29
|
+
# Handle parent process
|
30
|
+
#
|
31
|
+
# @param [IO] reader
|
32
|
+
# @param [IO] writer
|
33
|
+
#
|
34
|
+
# @return [undefined]
|
35
|
+
def parent(reader, writer, &block)
|
36
|
+
pid = process.fork do
|
37
|
+
child(reader, writer, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
writer.close
|
41
|
+
marshal.load(reader)
|
42
|
+
ensure
|
43
|
+
process.waitpid(pid) if pid
|
44
|
+
end
|
45
|
+
|
46
|
+
# Handle child process
|
47
|
+
#
|
48
|
+
# @param [IO] reader
|
49
|
+
# @param [IO] writer
|
50
|
+
#
|
51
|
+
# @return [undefined]
|
52
|
+
def child(reader, writer, &block)
|
53
|
+
reader.close
|
54
|
+
writer.binmode
|
55
|
+
writer.syswrite(marshal.dump(result(&block)))
|
56
|
+
writer.close
|
57
|
+
end
|
58
|
+
|
59
|
+
# The block result computed under silencing
|
60
|
+
#
|
61
|
+
# @return [Object]
|
62
|
+
def result
|
63
|
+
devnull.call do |null|
|
64
|
+
stderr.reopen(null)
|
65
|
+
stdout.reopen(null)
|
66
|
+
yield
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end # Fork
|
71
|
+
end # Isolation
|
72
|
+
end # Mutant
|