mutant 0.5.10 → 0.5.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/Changelog.md +12 -1
- data/README.md +3 -0
- data/Rakefile +0 -9
- data/bin/mutant +1 -1
- data/config/flay.yml +1 -1
- data/config/mutant.yml +13 -0
- data/config/reek.yml +6 -2
- data/lib/mutant/constants.rb +0 -13
- data/lib/mutant/mutator/node/conditional_loop.rb +2 -1
- data/lib/mutant/mutator/node/generic.rb +1 -1
- data/lib/mutant/mutator/node/if.rb +1 -1
- data/lib/mutant/mutator/node/literal/regex.rb +2 -2
- data/lib/mutant/mutator/node/match_current_line.rb +27 -0
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +1 -1
- data/lib/mutant/mutator/node/nthref.rb +3 -1
- data/lib/mutant/mutator/node/rescue.rb +0 -12
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +51 -0
- data/lib/mutant/mutator/node/send/index.rb +43 -0
- data/lib/mutant/mutator/node/send.rb +7 -37
- data/lib/mutant/mutator/node.rb +4 -12
- data/lib/mutant/mutator.rb +2 -26
- data/lib/mutant/node_helpers.rb +3 -3
- data/lib/mutant/require_highjack.rb +64 -0
- data/lib/mutant/subject/method/instance.rb +9 -1
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warning_expectation.rb +40 -0
- data/lib/mutant/warning_filter.rb +74 -0
- data/lib/mutant/zombifier/file.rb +81 -0
- data/lib/mutant/zombifier.rb +61 -240
- data/lib/mutant.rb +57 -1
- data/lib/parser_extensions.rb +25 -0
- data/mutant.gemspec +4 -3
- data/spec/integration/mutant/corpus_spec.rb +121 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -1
- data/spec/integration/mutant/zombie_spec.rb +3 -3
- data/spec/integrations.yml +23 -0
- data/spec/shared/mutator_behavior.rb +22 -72
- data/spec/spec_helper.rb +4 -2
- data/spec/support/mutation_verifier.rb +95 -0
- data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +16 -0
- data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +4 -4
- data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +6 -3
- data/spec/unit/mutant/mutator/node/nthref_spec.rb +2 -2
- data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +3 -1
- data/spec/unit/mutant/mutator/node/send_spec.rb +0 -1
- data/spec/unit/mutant/require_highjack_spec.rb +54 -0
- data/spec/unit/mutant/subject/method/instance_spec.rb +34 -3
- data/spec/unit/mutant/warning_expectation.rb +71 -0
- data/spec/unit/mutant/warning_filter_spec.rb +94 -0
- metadata +40 -9
- data/lib/mutant/singleton_methods.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bff75074f1898f689c4215c2a19f14d02863ccc4
|
4
|
+
data.tar.gz: 576dbee5c9743707641a1f3fac543c0c76d85832
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47b0085d022c5e09f1013c824989f2449838bea7b9681b257e9e8ef7641a39fd522dacdf643e20e177422ff8c8a944b9d34a20c5c0f464f68f4458c02b2f1702
|
7
|
+
data.tar.gz: 47f0863f96176f3c90200a4a6ed46c86e31a39de77a8d35a66d7728446b38422288d162e5a0f1a4e54bc2a750ee34f869958e7019048652522d5e15c346e6cf7
|
data/.rubocop.yml
CHANGED
data/Changelog.md
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
+
# v0.5.11 2014-04-21
|
2
|
+
|
3
|
+
Changes:
|
4
|
+
|
5
|
+
* Fix crash on while and until without body
|
6
|
+
* Better require highjack based zombifier
|
7
|
+
* Do not mutate nthref $1 to gvar $0
|
8
|
+
* Use faster duplicate guarding hashing AST::Node intances
|
9
|
+
* Fix lots of shadowed invalid ASTs
|
10
|
+
* Fix undefine initialize warnings, Closes #175
|
11
|
+
|
1
12
|
# v0.5.10 2014-04-06
|
2
13
|
|
3
14
|
Changes:
|
4
15
|
|
5
|
-
* Fix crash without
|
16
|
+
* Fix crash on case without conditional
|
6
17
|
* Remove dependency to descendants tracker
|
7
18
|
* Add mutation #== => #eql?, #equal?
|
8
19
|
* Add mutation #eql? => #equal?
|
data/README.md
CHANGED
@@ -17,6 +17,9 @@ Mutant supports MRI and RBX 1.9 and 2.0, while support for jruby is planned.
|
|
17
17
|
It should also work under any ruby engine that supports POSIX-fork(2) semantics.
|
18
18
|
Support for MRI 2.1 is unstable, because this MRI release segfaults on basic metaprogramming mutants dependencies do.
|
19
19
|
|
20
|
+
Mutant uses a pure ruby [parser](https://github.com/whitequark/parser) and an [unparser](https://github.com/mbj/unparser)
|
21
|
+
to do its magic.
|
22
|
+
|
20
23
|
Integrations
|
21
24
|
------------
|
22
25
|
|
data/Rakefile
CHANGED
@@ -3,12 +3,3 @@
|
|
3
3
|
require 'devtools'
|
4
4
|
|
5
5
|
Devtools.init_rake_tasks
|
6
|
-
|
7
|
-
Rake.application.load_imports
|
8
|
-
task('metrics:mutant').clear
|
9
|
-
|
10
|
-
namespace :metrics do
|
11
|
-
task :mutant => :coverage do
|
12
|
-
$stderr.puts 'Mutant self mutation is disable till mutant is fast enough for travis'
|
13
|
-
end
|
14
|
-
end
|
data/bin/mutant
CHANGED
data/config/flay.yml
CHANGED
data/config/mutant.yml
CHANGED
@@ -1,2 +1,15 @@
|
|
1
1
|
name: mutant
|
2
2
|
namespace: Mutant
|
3
|
+
zombify: true
|
4
|
+
expect_coverage: 64.99
|
5
|
+
ignore_subjects:
|
6
|
+
# Mutation causes infinite runtime
|
7
|
+
- Mutant::Runner.lookup
|
8
|
+
# Suboptimal test selection stragegy (will be fixed soon) causes timeouts on CI
|
9
|
+
- Mutant::Zombifier*
|
10
|
+
- Mutant::Reporter*
|
11
|
+
- Mutant::CLI*
|
12
|
+
- Mutant.singleton_subclass_instance
|
13
|
+
- Mutant.symbolset
|
14
|
+
# Executing this has undefined behavior with the zombifier
|
15
|
+
- Mutant.zombify
|
data/config/reek.yml
CHANGED
@@ -52,6 +52,9 @@ NestedIterators:
|
|
52
52
|
- Mutant::CLI#parse
|
53
53
|
- Mutant::Mutator::Util::Array::Element#dispatch
|
54
54
|
- Mutant::Reporter::CLI::Printer::Config::Runner#generic_stats
|
55
|
+
- Mutant::RequireHighjack#infect
|
56
|
+
- Mutant::RequireHighjack#desinfect
|
57
|
+
- Parser::Lexer#self.new
|
55
58
|
max_allowed_nesting: 1
|
56
59
|
ignore_iterators: []
|
57
60
|
NilCheck:
|
@@ -85,7 +88,8 @@ TooManyStatements:
|
|
85
88
|
- Mutant::Reporter::CLI#colorized_diff
|
86
89
|
- Mutant::Reporter::CLI::Printer::Config::Runner#run
|
87
90
|
- Mutant::Runner#dispatch
|
88
|
-
- Mutant::Zombifier::File#self.
|
91
|
+
- Mutant::Zombifier::File#self.find
|
92
|
+
- Mutant::RequireHighjack#infect
|
89
93
|
# How mutant does CLI parsing is shit
|
90
94
|
- Mutant::CLI#parse
|
91
95
|
- Mutant::CLI#initialize
|
@@ -123,7 +127,7 @@ UncommunicativeVariableName:
|
|
123
127
|
- !ruby/regexp /^.$/
|
124
128
|
- !ruby/regexp /[0-9]$/
|
125
129
|
- !ruby/regexp /[A-Z]/
|
126
|
-
accept: []
|
130
|
+
accept: ['force_utf32']
|
127
131
|
UnusedParameters:
|
128
132
|
enabled: true
|
129
133
|
exclude: []
|
data/lib/mutant/constants.rb
CHANGED
@@ -2,19 +2,6 @@
|
|
2
2
|
|
3
3
|
module Mutant
|
4
4
|
|
5
|
-
# Return a frozen set of symbols from string enumerable
|
6
|
-
#
|
7
|
-
# @param [Enumerable<String>]
|
8
|
-
#
|
9
|
-
# @return [Set<Symbol>]
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
#
|
13
|
-
def self.symbolset(strings)
|
14
|
-
strings.map(&:to_sym).to_set.freeze
|
15
|
-
end
|
16
|
-
private_class_method :symbolset
|
17
|
-
|
18
5
|
# Set of nodes that cannot be on the LHS of an assignment
|
19
6
|
NOT_ASSIGNABLE = symbolset %w(
|
20
7
|
int float str dstr class module self
|
@@ -13,7 +13,7 @@ module Mutant
|
|
13
13
|
:ensure, :redo, :defined?, :regopt, :retry, :arg_expr,
|
14
14
|
:kwrestarg, :kwoptarg, :kwarg, :undef, :module, :empty,
|
15
15
|
:alias, :for, :xstr, :back_ref, :class,
|
16
|
-
:sclass, :match_with_lvasgn, :
|
16
|
+
:sclass, :match_with_lvasgn, :while_post,
|
17
17
|
:until_post, :preexe, :postexe, :iflipflop, :eflipflop, :kwsplat,
|
18
18
|
:shadowarg
|
19
19
|
)
|
@@ -33,7 +33,7 @@ module Mutant
|
|
33
33
|
#
|
34
34
|
def mutate_condition
|
35
35
|
emit_condition_mutations
|
36
|
-
emit_self(n_not(condition), if_branch, else_branch)
|
36
|
+
emit_self(n_not(condition), if_branch, else_branch) unless condition.type == :match_current_line
|
37
37
|
emit_self(N_TRUE, if_branch, else_branch)
|
38
38
|
emit_self(N_FALSE, if_branch, else_branch)
|
39
39
|
end
|
@@ -31,11 +31,11 @@ module Mutant
|
|
31
31
|
# @api private
|
32
32
|
#
|
33
33
|
def dispatch
|
34
|
-
emit_nil
|
34
|
+
emit_nil unless parent_type == :match_current_line
|
35
35
|
children.each_with_index do |child, index|
|
36
36
|
mutate_child(index) unless child.type == :str
|
37
37
|
end
|
38
|
-
emit_self(
|
38
|
+
emit_self(options)
|
39
39
|
emit_self(s(:str, NULL_REGEXP_SOURCE), options)
|
40
40
|
end
|
41
41
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
# Emitter for perl style match current line node
|
5
|
+
class MatchCurrentLine < self
|
6
|
+
|
7
|
+
handle :match_current_line
|
8
|
+
|
9
|
+
children :regexp
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Emit mutants
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def dispatch
|
20
|
+
emit_nil
|
21
|
+
emit_regexp_mutations
|
22
|
+
end
|
23
|
+
|
24
|
+
end # MatchCurrentLine
|
25
|
+
end # Node
|
26
|
+
end # Mutator
|
27
|
+
end # Mutant
|
@@ -8,18 +8,6 @@ module Mutant
|
|
8
8
|
|
9
9
|
handle :rescue
|
10
10
|
|
11
|
-
# Return identity
|
12
|
-
#
|
13
|
-
# @param [Parser::AST::Node] node
|
14
|
-
#
|
15
|
-
# @return [String]
|
16
|
-
#
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
def self.identity(node)
|
20
|
-
super(NodeHelpers.s(:kwbegin, node))
|
21
|
-
end
|
22
|
-
|
23
11
|
end # Rescue
|
24
12
|
end # Node
|
25
13
|
end # Mutator
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
class Send
|
7
|
+
|
8
|
+
# Mutator for sends that correspond to an attribute assignment
|
9
|
+
class AttributeAssignment < self
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# Emit mutations
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def dispatch
|
20
|
+
normal_dispatch
|
21
|
+
emit_attribute_read
|
22
|
+
end
|
23
|
+
|
24
|
+
# Mutate arguments
|
25
|
+
#
|
26
|
+
# @return [undefined]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def mutate_arguments
|
31
|
+
remaining_children_indices.each do |index|
|
32
|
+
mutate_child(index)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Emit attribute read
|
37
|
+
#
|
38
|
+
# @return [undefined]
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
def emit_attribute_read
|
43
|
+
emit_self(receiver, selector.to_s[0..-2].to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
end # AttributeAssignment
|
47
|
+
|
48
|
+
end # Send
|
49
|
+
end # Node
|
50
|
+
end # Mutator
|
51
|
+
end # Mutant
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
class Send
|
7
|
+
# Base mutator for index operations
|
8
|
+
class Index < self
|
9
|
+
|
10
|
+
# Mutator for index references
|
11
|
+
class Reference < self
|
12
|
+
|
13
|
+
# Perform dispatch
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def dispatch
|
20
|
+
emit(receiver)
|
21
|
+
end
|
22
|
+
|
23
|
+
end # Reference
|
24
|
+
|
25
|
+
# Mutator for index assignments
|
26
|
+
class Assign < self
|
27
|
+
|
28
|
+
# Perform dispatch
|
29
|
+
#
|
30
|
+
# @return [undefined]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
def dispatch
|
35
|
+
emit(receiver)
|
36
|
+
end
|
37
|
+
|
38
|
+
end # Assign
|
39
|
+
end # Index
|
40
|
+
end # Send
|
41
|
+
end # Node
|
42
|
+
end # Mutator
|
43
|
+
end # Mutant
|
@@ -22,40 +22,6 @@ module Mutant
|
|
22
22
|
INDEX_ASSIGN = :[]=
|
23
23
|
ASSIGN_SUFFIX = '='.freeze
|
24
24
|
|
25
|
-
# Base mutator for index operations
|
26
|
-
class Index < self
|
27
|
-
|
28
|
-
# Mutator for index references
|
29
|
-
class Reference < self
|
30
|
-
|
31
|
-
# Perform dispatch
|
32
|
-
#
|
33
|
-
# @return [undefined]
|
34
|
-
#
|
35
|
-
# @api private
|
36
|
-
#
|
37
|
-
def dispatch
|
38
|
-
emit(receiver)
|
39
|
-
end
|
40
|
-
|
41
|
-
end # Reference
|
42
|
-
|
43
|
-
# Mutator for index assignments
|
44
|
-
class Assign < self
|
45
|
-
|
46
|
-
# Perform dispatch
|
47
|
-
#
|
48
|
-
# @return [undefined]
|
49
|
-
#
|
50
|
-
# @api private
|
51
|
-
#
|
52
|
-
def dispatch
|
53
|
-
emit(receiver)
|
54
|
-
end
|
55
|
-
|
56
|
-
end # Assign
|
57
|
-
end # Index
|
58
|
-
|
59
25
|
private
|
60
26
|
|
61
27
|
# Perform dispatch
|
@@ -65,6 +31,7 @@ module Mutant
|
|
65
31
|
# @api private
|
66
32
|
#
|
67
33
|
def dispatch
|
34
|
+
emit_nil
|
68
35
|
case selector
|
69
36
|
when INDEX_REFERENCE
|
70
37
|
run(Index::Reference)
|
@@ -73,7 +40,6 @@ module Mutant
|
|
73
40
|
else
|
74
41
|
non_index_dispatch
|
75
42
|
end
|
76
|
-
emit_nil
|
77
43
|
end
|
78
44
|
|
79
45
|
# Perform non index dispatch
|
@@ -86,6 +52,8 @@ module Mutant
|
|
86
52
|
case
|
87
53
|
when binary_operator?
|
88
54
|
run(Binary)
|
55
|
+
when attribute_assignment?
|
56
|
+
run(AttributeAssignment)
|
89
57
|
else
|
90
58
|
normal_dispatch
|
91
59
|
end
|
@@ -173,7 +141,6 @@ module Mutant
|
|
173
141
|
# @api private
|
174
142
|
#
|
175
143
|
def mutate_arguments
|
176
|
-
return if arguments.empty?
|
177
144
|
emit_self(receiver, selector)
|
178
145
|
remaining_children_with_index.each do |node, index|
|
179
146
|
mutate_child(index)
|
@@ -213,7 +180,10 @@ module Mutant
|
|
213
180
|
# @api private
|
214
181
|
#
|
215
182
|
def emit_implicit_self
|
216
|
-
if receiver.type == :self &&
|
183
|
+
if receiver.type == :self &&
|
184
|
+
!KEYWORDS.include?(selector) &&
|
185
|
+
!attribute_assignment? &&
|
186
|
+
!OP_ASSIGN.include?(parent_type)
|
217
187
|
emit_receiver(nil)
|
218
188
|
end
|
219
189
|
end
|
data/lib/mutant/mutator/node.rb
CHANGED
@@ -9,18 +9,6 @@ module Mutant
|
|
9
9
|
class Node < self
|
10
10
|
include AbstractType, NodeHelpers, Unparser::Constants
|
11
11
|
|
12
|
-
# Return identity of node
|
13
|
-
#
|
14
|
-
# @param [Parser::AST::Node] node
|
15
|
-
#
|
16
|
-
# @return [String]
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
#
|
20
|
-
def self.identity(node)
|
21
|
-
Unparser.unparse(node)
|
22
|
-
end
|
23
|
-
|
24
12
|
# Define named child
|
25
13
|
#
|
26
14
|
# @param [Symbol] name
|
@@ -58,6 +46,10 @@ module Mutant
|
|
58
46
|
children.each_with_index.drop(names.length)
|
59
47
|
end
|
60
48
|
|
49
|
+
define_method(:remaining_children_indices) do
|
50
|
+
children.each_index.drop(names.length)
|
51
|
+
end
|
52
|
+
|
61
53
|
define_method(:remaining_children) do
|
62
54
|
children.drop(names.length)
|
63
55
|
end
|
data/lib/mutant/mutator.rb
CHANGED
@@ -33,18 +33,6 @@ module Mutant
|
|
33
33
|
end
|
34
34
|
private_class_method :handle
|
35
35
|
|
36
|
-
# Return identity of object (for deduplication)
|
37
|
-
#
|
38
|
-
# @param [Object] object
|
39
|
-
#
|
40
|
-
# @return [Object]
|
41
|
-
#
|
42
|
-
# @api private
|
43
|
-
#
|
44
|
-
def self.identity(object)
|
45
|
-
object
|
46
|
-
end
|
47
|
-
|
48
36
|
# Return input
|
49
37
|
#
|
50
38
|
# @return [Object]
|
@@ -92,7 +80,7 @@ module Mutant
|
|
92
80
|
# @api private
|
93
81
|
#
|
94
82
|
def new?(object)
|
95
|
-
!@seen.include?(
|
83
|
+
!@seen.include?(object)
|
96
84
|
end
|
97
85
|
|
98
86
|
# Add object to guarded values
|
@@ -104,19 +92,7 @@ module Mutant
|
|
104
92
|
# @api private
|
105
93
|
#
|
106
94
|
def guard(object)
|
107
|
-
@seen <<
|
108
|
-
end
|
109
|
-
|
110
|
-
# Return identity for input
|
111
|
-
#
|
112
|
-
# @param [Object] input
|
113
|
-
#
|
114
|
-
# @return [Object]
|
115
|
-
#
|
116
|
-
# @api private
|
117
|
-
#
|
118
|
-
def identity(input)
|
119
|
-
self.class.identity(input)
|
95
|
+
@seen << object
|
120
96
|
end
|
121
97
|
|
122
98
|
# Dispatch node generations
|
data/lib/mutant/node_helpers.rb
CHANGED
@@ -18,13 +18,13 @@ module Mutant
|
|
18
18
|
module_function :s
|
19
19
|
|
20
20
|
NAN =
|
21
|
-
s(:send, s(:float, 0.0), :/, s(:
|
21
|
+
s(:send, s(:float, 0.0), :/, s(:float, 0.0))
|
22
22
|
INFINITY =
|
23
|
-
s(:send, s(:float, 1.0), :/, s(:
|
23
|
+
s(:send, s(:float, 1.0), :/, s(:float, 0.0))
|
24
24
|
NEW_OBJECT =
|
25
25
|
s(:send, s(:const, s(:cbase), :Object), :new)
|
26
26
|
NEGATIVE_INFINITY =
|
27
|
-
s(:send, s(:float, -1.0), :/, s(:
|
27
|
+
s(:send, s(:float, -1.0), :/, s(:float, 0.0))
|
28
28
|
|
29
29
|
RAISE = s(:send, nil, :raise)
|
30
30
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Mutant
|
2
|
+
# Require highjack
|
3
|
+
class RequireHighjack
|
4
|
+
include Concord.new(:target, :callback)
|
5
|
+
|
6
|
+
# Return original method
|
7
|
+
#
|
8
|
+
# @return [#call]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
attr_reader :original
|
13
|
+
|
14
|
+
# Run block with highjacked require
|
15
|
+
#
|
16
|
+
# @return [self]
|
17
|
+
#
|
18
|
+
# @api pivate
|
19
|
+
#
|
20
|
+
def run
|
21
|
+
infect
|
22
|
+
yield
|
23
|
+
self
|
24
|
+
ensure
|
25
|
+
desinfect
|
26
|
+
end
|
27
|
+
|
28
|
+
# Infect kernel with highjack
|
29
|
+
#
|
30
|
+
# @return [self]
|
31
|
+
#
|
32
|
+
# @api pivate
|
33
|
+
#
|
34
|
+
def infect
|
35
|
+
callback = @callback
|
36
|
+
@original = target.method(:require)
|
37
|
+
target.module_eval do
|
38
|
+
undef :require
|
39
|
+
define_method(:require) do |logical_name|
|
40
|
+
callback.call(logical_name)
|
41
|
+
end
|
42
|
+
module_function :require
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Imperfectly desinfect kernel from highjack
|
47
|
+
#
|
48
|
+
# @return [self]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
#
|
52
|
+
def desinfect
|
53
|
+
original = @original
|
54
|
+
target.module_eval do
|
55
|
+
undef :require
|
56
|
+
define_method(:require) do |logical_name|
|
57
|
+
original.call(logical_name)
|
58
|
+
end
|
59
|
+
module_function :require
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end # RequireHighjack
|
64
|
+
end # Mutant
|
@@ -31,7 +31,15 @@ module Mutant
|
|
31
31
|
# @api private
|
32
32
|
#
|
33
33
|
def prepare
|
34
|
-
|
34
|
+
expected_warnings =
|
35
|
+
if name.equal?(:initialize)
|
36
|
+
["#{__FILE__}:#{__LINE__ + 5}: warning: undefining `initialize' may cause serious problems\n"]
|
37
|
+
else
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
WarningExpectation.new(expected_warnings).execute do
|
41
|
+
scope.send(:undef_method, name)
|
42
|
+
end
|
35
43
|
self
|
36
44
|
end
|
37
45
|
|
data/lib/mutant/version.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mutant
|
2
|
+
# A class to expect some warning message raising on absence of unexpected warnings
|
3
|
+
class WarningExpectation
|
4
|
+
include Adamantium::Flat, Concord.new(:expected)
|
5
|
+
|
6
|
+
# Error raised on expectation miss
|
7
|
+
class ExpectationError < RuntimeError
|
8
|
+
include Concord.new(:unexpected, :missing)
|
9
|
+
|
10
|
+
# Return exception message
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def message
|
17
|
+
"Unexpected warnings: #{unexpected.inspect} missing warnigns: #{missing.inspect}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Execute blocks with warning expectations
|
22
|
+
#
|
23
|
+
# @return [self]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def execute(&block)
|
28
|
+
warnings = WarningFilter.use do
|
29
|
+
block.call
|
30
|
+
end
|
31
|
+
missing = expected - warnings
|
32
|
+
unexpected = warnings - expected
|
33
|
+
if missing.any? or unexpected.any?
|
34
|
+
fail ExpectationError.new(unexpected, missing)
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
end # WarningExpectation
|
40
|
+
end # Mutant
|