mutant 0.5.10 → 0.5.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 -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
@@ -0,0 +1,121 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Mutant on ruby corpus' do
|
6
|
+
|
7
|
+
before do
|
8
|
+
pending 'Unparser is too slow on big files'
|
9
|
+
end
|
10
|
+
|
11
|
+
ROOT = Pathname.new(__FILE__).parent.parent.parent.parent
|
12
|
+
|
13
|
+
TMP = ROOT.join('tmp')
|
14
|
+
|
15
|
+
class Project
|
16
|
+
include Anima.new(:name, :repo_uri, :exclude)
|
17
|
+
|
18
|
+
# Perform verification via unparser cli
|
19
|
+
#
|
20
|
+
# @return [self]
|
21
|
+
# if successful
|
22
|
+
#
|
23
|
+
# @raise [Exception]
|
24
|
+
# otherwise
|
25
|
+
#
|
26
|
+
def verify
|
27
|
+
checkout
|
28
|
+
Pathname.glob(repo_path.join('**/*.rb')).sort.each do |path|
|
29
|
+
puts "Generating mutations for: #{path.to_s}"
|
30
|
+
node = Parser::CurrentRuby.parse(path.read)
|
31
|
+
count = 0
|
32
|
+
Mutant::Mutator::Node.each(node) do |mutant|
|
33
|
+
count += 1
|
34
|
+
if (count % 100).zero?
|
35
|
+
puts count
|
36
|
+
end
|
37
|
+
end
|
38
|
+
puts "Mutations: #{count}"
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Checkout repository
|
44
|
+
#
|
45
|
+
# @return [self]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def checkout
|
50
|
+
TMP.mkdir unless TMP.directory?
|
51
|
+
if repo_path.exist?
|
52
|
+
Dir.chdir(repo_path) do
|
53
|
+
system(%w(git pull origin master))
|
54
|
+
system(%w(git clean -f -d -x))
|
55
|
+
end
|
56
|
+
else
|
57
|
+
system(%W(git clone #{repo_uri} #{repo_path}))
|
58
|
+
end
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# Return repository path
|
65
|
+
#
|
66
|
+
# @return [Pathname]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
#
|
70
|
+
def repo_path
|
71
|
+
TMP.join(name)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Helper method to execute system commands
|
75
|
+
#
|
76
|
+
# @param [Array<String>] arguments
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
#
|
80
|
+
def system(arguments)
|
81
|
+
unless Kernel.system(*arguments)
|
82
|
+
if block_given?
|
83
|
+
yield
|
84
|
+
else
|
85
|
+
raise 'System command failed!'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
LOADER = Morpher.build do
|
91
|
+
s(:block,
|
92
|
+
s(:guard, s(:primitive, Array)),
|
93
|
+
s(:map,
|
94
|
+
s(:block,
|
95
|
+
s(:guard, s(:primitive, Hash)),
|
96
|
+
s(:hash_transform,
|
97
|
+
s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
|
98
|
+
s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
|
99
|
+
s(:key_symbolize, :exclude, s(:map, s(:guard, s(:primitive, String))))
|
100
|
+
),
|
101
|
+
s(:load_attribute_hash,
|
102
|
+
# NOTE: The domain param has no DSL currently!
|
103
|
+
Morpher::Evaluator::Transformer::Domain::Param.new(
|
104
|
+
Project,
|
105
|
+
[:repo_uri, :name, :exclude]
|
106
|
+
)
|
107
|
+
)
|
108
|
+
)
|
109
|
+
)
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))
|
114
|
+
end
|
115
|
+
|
116
|
+
Project::ALL.each do |project|
|
117
|
+
specify "unparsing #{project.name}" do
|
118
|
+
project.verify
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe
|
6
|
-
|
7
|
-
Mutant
|
5
|
+
describe 'as a zombie' do
|
6
|
+
specify 'it allows to create zombie from mutant' do
|
7
|
+
expect { Mutant.zombify }.to change { !!defined?(Zombie) }.from(false).to(true)
|
8
8
|
expect(Zombie.constants).to include(:Mutant)
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
- name: rubyspec
|
3
|
+
repo_uri: 'https://github.com/rubyspec/rubyspec.git'
|
4
|
+
exclude:
|
5
|
+
# Binary encoded source subjected to limitations see Readme
|
6
|
+
- core/array/pack/{b,h,u}_spec.rb
|
7
|
+
- language/versions/*1.8*
|
8
|
+
- core/array/pack/shared/float.rb
|
9
|
+
- core/array/pack/shared/integer.rb
|
10
|
+
- core/array/pack/{c,m,w}_spec.rb
|
11
|
+
- core/regexp/shared/new.rb
|
12
|
+
- core/regexp/shared/quote.rb
|
13
|
+
- core/encoding/compatible_spec.rb
|
14
|
+
- core/io/readpartial_spec.rb
|
15
|
+
- core/env/element_reference_spec.rb
|
16
|
+
- core/dir/pwd_spec.rb
|
17
|
+
- core/string/casecmp_spec.rb
|
18
|
+
- core/string/unpack/{b,c,h,m,u,w}_spec.rb
|
19
|
+
- core/string/unpack/b_spec.rb
|
20
|
+
- core/string/unpack/shared/float.rb
|
21
|
+
- core/string/unpack/shared/integer.rb
|
22
|
+
- core/symbol/casecmp_spec.rb
|
23
|
+
- optional/capi/integer_spec.rb
|
@@ -1,52 +1,12 @@
|
|
1
|
-
# encoding:
|
2
|
-
|
3
|
-
class Subject
|
4
|
-
|
5
|
-
include Equalizer.new(:source)
|
6
|
-
|
7
|
-
Undefined = Object.new.freeze
|
8
|
-
|
9
|
-
attr_reader :source
|
10
|
-
|
11
|
-
def self.coerce(input)
|
12
|
-
case input
|
13
|
-
when Parser::AST::Node
|
14
|
-
new(input)
|
15
|
-
when String
|
16
|
-
new(Parser::CurrentRuby.parse(input))
|
17
|
-
else
|
18
|
-
raise
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_s
|
23
|
-
"#{@node.inspect}\n#{@source}"
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize(node)
|
27
|
-
source = Unparser.unparse(node)
|
28
|
-
@node, @source = node, source
|
29
|
-
end
|
30
|
-
|
31
|
-
def assert_transitive!
|
32
|
-
generated = Unparser.generate(@node)
|
33
|
-
parsed = Parser::CurrentRuby.parse(generated)
|
34
|
-
again = Unparser.generate(parsed)
|
35
|
-
unless generated == again
|
36
|
-
# mostly an unparser bug!
|
37
|
-
fail sprintf("Untransitive:\n%s\n---\n%s", generated, again)
|
38
|
-
end
|
39
|
-
self
|
40
|
-
end
|
41
|
-
end
|
1
|
+
# encoding: UTF-8
|
42
2
|
|
43
3
|
shared_examples_for 'a mutator' do
|
44
|
-
subject { object.each(node
|
4
|
+
subject { object.each(node, &yields.method(:<<)) }
|
45
5
|
|
46
6
|
let(:yields) { [] }
|
47
7
|
let(:object) { described_class }
|
48
8
|
|
49
|
-
unless instance_methods.
|
9
|
+
unless instance_methods.include?(:node)
|
50
10
|
let(:node) { parse(source) }
|
51
11
|
end
|
52
12
|
|
@@ -57,42 +17,32 @@ shared_examples_for 'a mutator' do
|
|
57
17
|
|
58
18
|
it { should be_instance_of(to_enum.class) }
|
59
19
|
|
60
|
-
|
61
|
-
|
20
|
+
def coerce(input)
|
21
|
+
case input
|
22
|
+
when String
|
23
|
+
Parser::CurrentRuby.parse(input)
|
24
|
+
when Parser::AST::Node
|
25
|
+
input
|
26
|
+
else
|
27
|
+
raise
|
28
|
+
end
|
62
29
|
end
|
63
30
|
|
64
|
-
|
31
|
+
def normalize(node)
|
32
|
+
Unparser::Preprocessor.run(node)
|
65
33
|
end
|
66
34
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
missing = expected_mutations - generated
|
72
|
-
unexpected = generated - expected_mutations
|
73
|
-
|
74
|
-
message = []
|
75
|
-
|
76
|
-
if missing.any?
|
77
|
-
message << sprintf('Missing mutations (%i):', missing.length)
|
78
|
-
message.concat(missing)
|
79
|
-
end
|
80
|
-
|
81
|
-
if unexpected.any?
|
82
|
-
message << sprintf('Unexpected mutations (%i):', unexpected.length)
|
83
|
-
message.concat(unexpected)
|
84
|
-
end
|
35
|
+
let(:expected_mutations) do
|
36
|
+
mutations.map(&method(:coerce)).map(&method(:normalize))
|
37
|
+
end
|
85
38
|
|
86
|
-
|
39
|
+
it 'generates the expected mutations' do
|
40
|
+
generated_mutations = subject.map(&method(:normalize))
|
87
41
|
|
88
|
-
|
89
|
-
"Original:\n%s\n%s\n-----\n%s",
|
90
|
-
generate(node),
|
91
|
-
node.inspect,
|
92
|
-
message.join("\n-----\n")
|
93
|
-
)
|
42
|
+
verifier = MutationVerifier.new(node, expected_mutations, generated_mutations)
|
94
43
|
|
95
|
-
|
44
|
+
unless verifier.success?
|
45
|
+
fail verifier.error_report
|
96
46
|
end
|
97
47
|
end
|
98
48
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,8 +21,10 @@ if ENV['COVERAGE'] == 'true'
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
require '
|
24
|
+
require 'concord'
|
25
|
+
require 'adamantium'
|
25
26
|
require 'devtools/spec_helper'
|
27
|
+
require 'unparser/cli'
|
26
28
|
require 'mutant'
|
27
29
|
|
28
30
|
$LOAD_PATH << File.join(TestApp.root, 'lib')
|
@@ -39,7 +41,7 @@ module ParserHelper
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def parse(string)
|
42
|
-
Parser::CurrentRuby.parse(string)
|
44
|
+
Unparser::Preprocessor.run(Parser::CurrentRuby.parse(string))
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class MutationVerifier
|
4
|
+
include Adamantium::Flat, Concord.new(:original_node, :expected, :generated)
|
5
|
+
|
6
|
+
# Test if mutation was verified successfully
|
7
|
+
#
|
8
|
+
# @return [Boolean]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
def success?
|
13
|
+
unparser.success? && missing.empty? && unexpected.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return error report
|
17
|
+
#
|
18
|
+
# @return [String]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
def error_report
|
23
|
+
unless unparser.success?
|
24
|
+
return unparser.report
|
25
|
+
end
|
26
|
+
mutation_report
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Return unexpected mutationso
|
32
|
+
#
|
33
|
+
# @return [Array<Parser::AST::Node>]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
#
|
37
|
+
def unexpected
|
38
|
+
generated - expected
|
39
|
+
end
|
40
|
+
memoize :unexpected
|
41
|
+
|
42
|
+
# Return mutation report
|
43
|
+
#
|
44
|
+
# @return [String]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
#
|
48
|
+
def mutation_report
|
49
|
+
message = ['Original:', original_node.inspect]
|
50
|
+
if missing.any?
|
51
|
+
message << 'Missing mutations:'
|
52
|
+
message << missing.map(&method(:format_mutation)).join("\n-----\n")
|
53
|
+
end
|
54
|
+
if unexpected.any?
|
55
|
+
message << 'Unexpected mutations:'
|
56
|
+
message << unexpected.map(&method(:format_mutation)).join("\n-----\n")
|
57
|
+
end
|
58
|
+
message.join("\n======\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
# Format mutation
|
62
|
+
#
|
63
|
+
# @return [String]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
def format_mutation(node)
|
68
|
+
[
|
69
|
+
node.inspect,
|
70
|
+
Unparser.unparse(node)
|
71
|
+
].join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return missing mutationso
|
75
|
+
#
|
76
|
+
# @return [Array<Parser::AST::Node>]
|
77
|
+
#
|
78
|
+
# @api private
|
79
|
+
#
|
80
|
+
def missing
|
81
|
+
expected - generated
|
82
|
+
end
|
83
|
+
memoize :missing
|
84
|
+
|
85
|
+
# Return unparser verifier
|
86
|
+
#
|
87
|
+
# @return [Unparser::CLI::Source]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
def unparser
|
92
|
+
Unparser::CLI::Source::Node.new(Unparser::Preprocessor.run(original_node))
|
93
|
+
end
|
94
|
+
memoize :unparser
|
95
|
+
end # MutationVerifier
|
@@ -4,6 +4,20 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Mutant::Mutator::Node::ConditionalLoop do
|
6
6
|
|
7
|
+
context 'with empty body' do
|
8
|
+
let(:source) { 'while true; end' }
|
9
|
+
|
10
|
+
let(:mutations) do
|
11
|
+
mutations = []
|
12
|
+
mutations << 'while true; raise; end'
|
13
|
+
mutations << 'while false; end'
|
14
|
+
mutations << 'while nil; end'
|
15
|
+
mutations << 'nil'
|
16
|
+
end
|
17
|
+
|
18
|
+
it_should_behave_like 'a mutator'
|
19
|
+
end
|
20
|
+
|
7
21
|
context 'with while statement' do
|
8
22
|
let(:source) { 'while true; foo; bar; end' }
|
9
23
|
|
@@ -16,6 +30,7 @@ describe Mutant::Mutator::Node::ConditionalLoop do
|
|
16
30
|
mutations << 'while nil; foo; bar; end'
|
17
31
|
mutations << 'while true; foo; nil; end'
|
18
32
|
mutations << 'while true; nil; bar; end'
|
33
|
+
mutations << 'while true; raise; end'
|
19
34
|
mutations << 'nil'
|
20
35
|
end
|
21
36
|
|
@@ -34,6 +49,7 @@ describe Mutant::Mutator::Node::ConditionalLoop do
|
|
34
49
|
mutations << 'until nil; foo; bar; end'
|
35
50
|
mutations << 'until true; foo; nil; end'
|
36
51
|
mutations << 'until true; nil; bar; end'
|
52
|
+
mutations << 'until true; raise; end'
|
37
53
|
mutations << 'nil'
|
38
54
|
end
|
39
55
|
|
@@ -3,16 +3,16 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Mutant::Mutator::Node::Generic, 'match_current_line' do
|
6
|
-
let(:source) { 'true if
|
6
|
+
let(:source) { 'true if /foo/' }
|
7
7
|
|
8
8
|
let(:mutations) do
|
9
9
|
mutations = []
|
10
|
-
mutations << 'false if
|
11
|
-
mutations << '
|
10
|
+
mutations << 'false if /foo/'
|
11
|
+
mutations << 'true if //'
|
12
|
+
mutations << 'nil if /foo/'
|
12
13
|
mutations << 'true if true'
|
13
14
|
mutations << 'true if false'
|
14
15
|
mutations << 'true if nil'
|
15
|
-
mutations << s(:if, s(:send, s(:match_current_line, s(:regexp, s(:regopt))), :!), s(:true), nil)
|
16
16
|
mutations << 'true if /a\A/'
|
17
17
|
mutations << 'nil'
|
18
18
|
end
|
@@ -60,10 +60,13 @@ describe Mutant::Mutator::Node::NamedValue::Access, 'mutations' do
|
|
60
60
|
mutants = []
|
61
61
|
mutants << 'a = nil; nil'
|
62
62
|
mutants << 'a = nil'
|
63
|
-
mutants << 'a'
|
64
63
|
mutants << 'a = ::Object.new; a'
|
65
|
-
|
66
|
-
|
64
|
+
# TODO: fix invalid AST
|
65
|
+
# These ASTs are not valid and should NOT be emitted
|
66
|
+
# Mutations of lvarasgn need to be special cased to avoid this.
|
67
|
+
mutants << s(:begin, s(:lvasgn, :srandom, s(:nil)), s(:lvar, :a))
|
68
|
+
mutants << s(:begin, s(:nil), s(:lvar, :a))
|
69
|
+
mutants << s(:lvar, :a)
|
67
70
|
end
|
68
71
|
|
69
72
|
it_should_behave_like 'a mutator'
|
@@ -13,10 +13,12 @@ describe Mutant::Mutator::Node::Generic, 'op_asgn' do
|
|
13
13
|
mutations << '@a.b += 2'
|
14
14
|
mutations << '@a.b += 0'
|
15
15
|
mutations << '@a.b += nil'
|
16
|
-
mutations << '@a += 1'
|
17
16
|
mutations << '@a.b += 5'
|
18
17
|
mutations << 'nil.b += 1'
|
19
18
|
mutations << 'nil'
|
19
|
+
# TODO: fix invalid AST
|
20
|
+
# This should not get emitted as invalid AST with valid unparsed source
|
21
|
+
mutations << s(:op_asgn, s(:ivar, :@a), :+, s(:int, 1))
|
20
22
|
end
|
21
23
|
|
22
24
|
before do
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mutant::RequireHighjack do
|
4
|
+
let(:object) { described_class.new(target, highjacked_calls.method(:push)) }
|
5
|
+
|
6
|
+
let(:highjacked_calls) { [] }
|
7
|
+
let(:require_calls) { [] }
|
8
|
+
|
9
|
+
let(:target) do
|
10
|
+
require_calls = self.require_calls
|
11
|
+
Module.new do
|
12
|
+
define_method(:require) do |logical_name|
|
13
|
+
require_calls << logical_name
|
14
|
+
end
|
15
|
+
module_function :require
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#run' do
|
20
|
+
let(:block) { -> {} }
|
21
|
+
let(:logical_name) { double('Logical Name') }
|
22
|
+
|
23
|
+
subject do
|
24
|
+
object.run(&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'require calls before run' do
|
28
|
+
it 'does not highjack anything' do
|
29
|
+
target.require(logical_name)
|
30
|
+
expect(require_calls).to eql([logical_name])
|
31
|
+
expect(highjacked_calls).to eql([])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'require calls during run' do
|
36
|
+
let(:block) { -> { target.require(logical_name) } }
|
37
|
+
|
38
|
+
it 'does highjack the calls' do
|
39
|
+
expect { subject }.to change { highjacked_calls }.from([]).to([logical_name])
|
40
|
+
expect(require_calls).to eql([])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'require calls after run' do
|
45
|
+
|
46
|
+
it 'does not the calls anything' do
|
47
|
+
subject
|
48
|
+
target.require(logical_name)
|
49
|
+
expect(require_calls).to eql([logical_name])
|
50
|
+
expect(highjacked_calls).to eql([])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -20,6 +20,12 @@ describe Mutant::Subject::Method::Instance do
|
|
20
20
|
|
21
21
|
let(:scope) do
|
22
22
|
Class.new do
|
23
|
+
attr_reader :bar
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@bar = :boo
|
27
|
+
end
|
28
|
+
|
23
29
|
def foo
|
24
30
|
end
|
25
31
|
end
|
@@ -27,11 +33,36 @@ describe Mutant::Subject::Method::Instance do
|
|
27
33
|
|
28
34
|
subject { object.prepare }
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
context 'on non initialize methods' do
|
37
|
+
|
38
|
+
it 'undefines method on scope' do
|
39
|
+
expect { subject }.to change { scope.instance_methods.include?(:foo) }.from(true).to(false)
|
40
|
+
end
|
41
|
+
|
42
|
+
it_should_behave_like 'a command method'
|
43
|
+
|
32
44
|
end
|
33
45
|
|
34
|
-
|
46
|
+
context 'on initialize method' do
|
47
|
+
|
48
|
+
let(:node) do
|
49
|
+
s(:def, :initialize, s(:args))
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'does not write warnings' do
|
53
|
+
warnings = Mutant::WarningFilter.use do
|
54
|
+
subject
|
55
|
+
end
|
56
|
+
expect(warnings).to eql([])
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'undefines method on scope' do
|
60
|
+
subject
|
61
|
+
expect { scope.new }.to raise_error(NoMethodError)
|
62
|
+
end
|
63
|
+
|
64
|
+
it_should_behave_like 'a command method'
|
65
|
+
end
|
35
66
|
end
|
36
67
|
|
37
68
|
describe '#source' do
|