mutant 0.0.1 → 0.1.0

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 (59) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +1 -1
  3. data/.travis.yml +6 -0
  4. data/Readme.md +13 -0
  5. data/exe/mutate +6 -0
  6. data/lib/mutant.rb +21 -0
  7. data/lib/mutant/extensions.rb +8 -0
  8. data/lib/mutant/formatter.rb +19 -0
  9. data/lib/mutant/implementation.rb +70 -0
  10. data/lib/mutant/literal.rb +134 -0
  11. data/lib/mutant/method.rb +31 -0
  12. data/lib/mutant/mutatee.rb +61 -0
  13. data/lib/mutant/mutation.rb +24 -0
  14. data/lib/mutant/mutator.rb +49 -0
  15. data/lib/mutant/node.rb +26 -0
  16. data/lib/mutant/random.rb +37 -0
  17. data/lib/mutant/reporter.rb +38 -0
  18. data/lib/mutant/runners/rspec.rb +26 -4
  19. data/lib/mutant/version.rb +1 -1
  20. data/mutant.gemspec +5 -3
  21. data/spec/functional/class_spec.rb +46 -0
  22. data/spec/functional/instance_method/array_spec.rb +53 -0
  23. data/spec/functional/instance_method/boolean_spec.rb +101 -0
  24. data/spec/functional/instance_method/call_spec.rb +161 -0
  25. data/spec/functional/instance_method/fixnum_spec.rb +53 -0
  26. data/spec/functional/instance_method/float_spec.rb +53 -0
  27. data/spec/functional/instance_method/hash_spec.rb +53 -0
  28. data/spec/functional/instance_method/if_spec.rb +57 -0
  29. data/spec/functional/instance_method/range_spec.rb +53 -0
  30. data/spec/functional/instance_method/regex_spec.rb +55 -0
  31. data/spec/functional/instance_method/string_spec.rb +53 -0
  32. data/spec/functional/instance_method/symbol_spec.rb +53 -0
  33. data/spec/functional/reporter/method_loaded_spec.rb +62 -0
  34. data/spec/functional/reporter/running_mutations_spec.rb +60 -0
  35. data/spec/functional/runners/rspec_spec.rb +26 -0
  36. data/spec/functional/singleton_method/array_spec.rb +53 -0
  37. data/spec/functional/singleton_method/boolean_spec.rb +101 -0
  38. data/spec/functional/singleton_method/call_spec.rb +161 -0
  39. data/spec/functional/singleton_method/fixnum_spec.rb +53 -0
  40. data/spec/functional/singleton_method/float_spec.rb +53 -0
  41. data/spec/functional/singleton_method/hash_spec.rb +53 -0
  42. data/spec/functional/singleton_method/if_spec.rb +57 -0
  43. data/spec/functional/singleton_method/range_spec.rb +53 -0
  44. data/spec/functional/singleton_method/regex_spec.rb +55 -0
  45. data/spec/functional/singleton_method/string_spec.rb +53 -0
  46. data/spec/functional/singleton_method/symbol_spec.rb +53 -0
  47. data/spec/mutant/extensions_spec.rb +13 -0
  48. data/spec/mutant/implementation_spec.rb +223 -0
  49. data/spec/mutant/literal_spec.rb +129 -0
  50. data/spec/mutant/mutatee_spec.rb +28 -0
  51. data/spec/mutant/node_spec.rb +41 -0
  52. data/spec/mutant/random_spec.rb +33 -0
  53. data/spec/mutant/reporter_spec.rb +17 -0
  54. data/spec/mutant_spec.rb +28 -0
  55. data/spec/spec_helper.rb +11 -3
  56. data/spec/support/example_group_helpers.rb +11 -0
  57. data/spec/support/example_helpers.rb +5 -0
  58. metadata +149 -81
  59. data/spec/functional/boolean_spec.rb +0 -49
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating floats' do
4
+ context 'for a singleton method' do
5
+ context 'that contains 42.05' do
6
+ before do
7
+ write_file 'life.rb', """
8
+ class Life
9
+ def self.answer
10
+ 42.05
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context 'with an expectation that the return value is 42.05' do
17
+ before do
18
+ write_file 'spec/life_spec.rb', """
19
+ $: << '.'
20
+ require 'life'
21
+
22
+ describe 'Life.answer' do
23
+ specify { Life.answer.should eq(42.05) }
24
+ end
25
+ """
26
+ mutate 'Life.answer spec/life_spec.rb'
27
+ end
28
+
29
+ specify 'the mutation passes' do
30
+ all_output.should include('passed')
31
+ end
32
+ end
33
+
34
+ context 'with an expectation that the return value is a Float' do
35
+ before do
36
+ write_file 'spec/life_spec.rb', """
37
+ $: << '.'
38
+ require 'life'
39
+
40
+ describe 'Life.answer' do
41
+ specify { Life.answer.should be_a(Float) }
42
+ end
43
+ """
44
+ mutate 'Life.answer spec/life_spec.rb'
45
+ end
46
+
47
+ specify 'the mutation fails' do
48
+ all_output.should include('failed')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating hashes' do
4
+ context 'for a singleton method' do
5
+ context 'that contains {:foo => {:bar => 3}}' do
6
+ before do
7
+ write_file 'thing.rb', """
8
+ class Thing
9
+ def self.to_hash
10
+ {:foo => {:bar => 3}}
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context 'with an expectation that hash[:foo][:bar] is 3' do
17
+ before do
18
+ write_file 'spec/thing_spec.rb', """
19
+ $: << '.'
20
+ require 'thing'
21
+
22
+ describe 'Thing.to_hash' do
23
+ specify { Thing.to_hash[:foo][:bar].should eq(3) }
24
+ end
25
+ """
26
+ mutate 'Thing.to_hash spec/thing_spec.rb'
27
+ end
28
+
29
+ specify 'the mutation passes' do
30
+ all_output.should include('passed')
31
+ end
32
+ end
33
+
34
+ context 'with an expectation that hash[:foo][:bar] is a Fixnum' do
35
+ before do
36
+ write_file 'spec/thing_spec.rb', """
37
+ $: << '.'
38
+ require 'thing'
39
+
40
+ describe 'Thing.to_hash' do
41
+ specify { Thing.to_hash[:foo][:bar].should be_kind_of(Fixnum) }
42
+ end
43
+ """
44
+ mutate 'Thing.to_hash spec/thing_spec.rb'
45
+ end
46
+
47
+ specify 'the mutation fails' do
48
+ all_output.should include('failed')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating If clauses' do
4
+ context 'for an instance method' do
5
+ context 'that contains an if-else that returns 42' do
6
+ before do
7
+ write_file 'life.rb', """
8
+ class Life
9
+ def self.answer
10
+ if true
11
+ 42
12
+ else
13
+ 24
14
+ end
15
+ end
16
+ end
17
+ """
18
+ end
19
+
20
+ context 'with an expectation that the answer is 42' do
21
+ before do
22
+ write_file 'spec/life_spec.rb', """
23
+ $: << '.'
24
+ require 'life'
25
+
26
+ describe 'Life.answer' do
27
+ specify { Life.answer.should eq(42) }
28
+ end
29
+ """
30
+ run_simple '../../bin/mutate Life.answer spec/life_spec.rb'
31
+ end
32
+
33
+ specify 'the mutation passes' do
34
+ all_output.should include('passed')
35
+ end
36
+ end
37
+
38
+ context 'with an expectation that the answer is a Fixnum' do
39
+ before do
40
+ write_file 'spec/life_spec.rb', """
41
+ $: << '.'
42
+ require 'life'
43
+
44
+ describe 'Life.answer' do
45
+ specify { Life.answer.should be_kind_of(Fixnum) }
46
+ end
47
+ """
48
+ run_simple '../../bin/mutate Life.answer spec/life_spec.rb'
49
+ end
50
+
51
+ specify 'the mutation fails' do
52
+ all_output.should include('failed')
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating ranges' do
4
+ context 'for a singleton method' do
5
+ context 'that contains a..z' do
6
+ before do
7
+ write_file 'thing.rb', """
8
+ class Thing
9
+ def self.a_range
10
+ 'a'..'z'
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context "with an expectation that the return value is `'a'..'z'`" do
17
+ before do
18
+ write_file 'spec/thing_spec.rb', """
19
+ $: << '.'
20
+ require 'thing'
21
+
22
+ describe 'Thing#a_range' do
23
+ specify { Thing.a_range.should eq('a'..'z') }
24
+ end
25
+ """
26
+ mutate 'Thing.a_range spec/thing_spec.rb'
27
+ end
28
+
29
+ specify 'the mutation passes' do
30
+ all_output.should include('passed')
31
+ end
32
+ end
33
+
34
+ context "with an expectation that the return value is a range" do
35
+ before do
36
+ write_file 'spec/thing_spec.rb', """
37
+ $: << '.'
38
+ require 'thing'
39
+
40
+ describe 'Thing.a_string' do
41
+ specify { Thing.a_range.should be_a(Range) }
42
+ end
43
+ """
44
+ mutate 'Thing.a_range spec/thing_spec.rb'
45
+ end
46
+
47
+ specify 'the mutation fails' do
48
+ all_output.should include('failed')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating regexen' do
4
+ context 'for a singleton method' do
5
+ context 'that contains `.*`' do
6
+ before do
7
+ write_file 'thing.rb', """
8
+ class Thing
9
+ def self.regex
10
+ /.*/
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context 'with an expectation that a string matches the regex' do
17
+ before do
18
+ write_file 'spec/thing_spec.rb', """
19
+ $: << '.'
20
+ require 'thing'
21
+
22
+ describe 'Thing.regex' do
23
+ specify do
24
+ 'hello'.should match(Thing.regex)
25
+ end
26
+ end
27
+ """
28
+ mutate 'Thing.regex spec/thing_spec.rb'
29
+ end
30
+
31
+ specify 'the mutation passes' do
32
+ all_output.should include('passed')
33
+ end
34
+ end
35
+
36
+ context 'with an expectation that the regex is a Regexp' do
37
+ before do
38
+ write_file 'spec/thing_spec.rb', """
39
+ $: << '.'
40
+ require 'thing'
41
+
42
+ describe 'Thing.regex' do
43
+ specify { Thing.regex.should be_kind_of(Regexp) }
44
+ end
45
+ """
46
+ mutate 'Thing.regex spec/thing_spec.rb'
47
+ end
48
+
49
+ specify 'the mutation fails' do
50
+ all_output.should include('failed')
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating string' do
4
+ context 'for a singleton method' do
5
+ context 'that contains "foo"' do
6
+ before do
7
+ write_file 'thing.rb', """
8
+ class Thing
9
+ def self.a_string
10
+ 'foo'
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context 'with an expectation that the return value is "foo"' do
17
+ before do
18
+ write_file 'spec/thing_spec.rb', """
19
+ $: << '.'
20
+ require 'thing'
21
+
22
+ describe 'Thing.a_string' do
23
+ specify { Thing.a_string.should eq('foo') }
24
+ end
25
+ """
26
+ mutate 'Thing.a_string spec/thing_spec.rb'
27
+ end
28
+
29
+ specify 'the mutation passes' do
30
+ all_output.should include('passed')
31
+ end
32
+ end
33
+
34
+ context 'with an expectation that the return value is a string' do
35
+ before do
36
+ write_file 'spec/thing_spec.rb', """
37
+ $: << '.'
38
+ require 'thing'
39
+
40
+ describe 'Thing.a_string' do
41
+ specify { Thing.a_string.should be_a(String) }
42
+ end
43
+ """
44
+ mutate 'Thing.a_string spec/thing_spec.rb'
45
+ end
46
+
47
+ specify 'the mutation fails' do
48
+ all_output.should include('failed')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mutating symbols' do
4
+ context 'for a singleton method' do
5
+ context 'that contains :foo' do
6
+ before do
7
+ write_file 'thing.rb', """
8
+ class Thing
9
+ def self.a_symbol
10
+ :foo
11
+ end
12
+ end
13
+ """
14
+ end
15
+
16
+ context 'with an expectation that the return value is :foo' do
17
+ before do
18
+ write_file 'spec/thing_spec.rb', """
19
+ $: << '.'
20
+ require 'thing'
21
+
22
+ describe 'Thing.a_symbol' do
23
+ specify { Thing.a_symbol.should eq(:foo) }
24
+ end
25
+ """
26
+ mutate 'Thing.a_symbol spec/thing_spec.rb'
27
+ end
28
+
29
+ specify 'the mutation passes' do
30
+ all_output.should include('passed')
31
+ end
32
+ end
33
+
34
+ context 'with an expectation that the return value is a symbol' do
35
+ before do
36
+ write_file 'spec/thing_spec.rb', """
37
+ $: << '.'
38
+ require 'thing'
39
+
40
+ describe 'Thing.a_symbol' do
41
+ specify { Thing.a_symbol.should be_a(Symbol) }
42
+ end
43
+ """
44
+ mutate 'Thing.a_symbol spec/thing_spec.rb'
45
+ end
46
+
47
+ specify 'the mutation fails' do
48
+ all_output.should include('failed')
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Class do
4
+ describe '#basename' do
5
+ context 'when called on Thing::Spirit' do
6
+ setup_thing { class Spirit; end }
7
+
8
+ it 'returns "Spirit"' do
9
+ Thing::Spirit.basename.should eq('Spirit')
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,223 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mutant::Implementation do
4
+ describe '#scope_type' do
5
+ context 'given "Thing.alive?"' do
6
+ it 'returns :singleton' do
7
+ Mutant::Implementation.new('Thing.alive?').scope_type.should eq(:singleton)
8
+ end
9
+ end
10
+
11
+ context 'given "Thing#alive?"' do
12
+ it 'returns :instance' do
13
+ Mutant::Implementation.new('Thing#alive?').scope_type.should eq(:instance)
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '#class_name' do
19
+ context 'given "Thing"' do
20
+ it 'returns "Thing"' do
21
+ Mutant::Implementation.new('Thing').class_name.should eq('Thing')
22
+ end
23
+ end
24
+
25
+ context 'given "Thing.alive?"' do
26
+ it 'returns "Thing"' do
27
+ Mutant::Implementation.new('Thing.alive?').class_name.should eq('Thing')
28
+ end
29
+ end
30
+
31
+ context 'given "Thing::Spirit#alive?"' do
32
+ it 'returns "Thing::Spirit"' do
33
+ Mutant::Implementation.new('Thing::Spirit#alive?').
34
+ class_name.should eq('Thing::Spirit')
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#method_scope' do
40
+ context 'given "Thing"' do
41
+ it 'returns nil' do
42
+ Mutant::Implementation.new('Thing').method_scope.should be_nil
43
+ end
44
+ end
45
+
46
+ context 'given "Thing.alive?"' do
47
+ it 'returns "."' do
48
+ Mutant::Implementation.new('Thing.alive?').method_scope.should eq('.')
49
+ end
50
+ end
51
+
52
+ context 'given "Thing#alive?"' do
53
+ it 'returns "#"' do
54
+ Mutant::Implementation.new('Thing#alive?').method_scope.should eq('#')
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#method_name' do
60
+ context 'given "Thing"' do
61
+ it 'returns nil' do
62
+ Mutant::Implementation.new('Thing').method_name.should be_nil
63
+ end
64
+ end
65
+
66
+ context 'given "Thing.alive?"' do
67
+ it 'returns "alive?"' do
68
+ Mutant::Implementation.new('Thing.alive?').method_name.should eq('alive?')
69
+ end
70
+ end
71
+
72
+ context 'given "Thing#alive?"' do
73
+ it 'returns "alive?"' do
74
+ Mutant::Implementation.new('Thing#alive?').method_name.should eq('alive?')
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#constant' do
80
+ context 'given "Thing"' do
81
+ setup_thing
82
+
83
+ let(:implementation) { Mutant::Implementation.new('Thing') }
84
+
85
+ it 'returns Thing' do
86
+ implementation.constant.should eq(Thing)
87
+ end
88
+ end
89
+
90
+ context 'given "Thing::Spirit"' do
91
+ setup_thing { class Spirit; end }
92
+
93
+ let(:implementation) { Mutant::Implementation.new('Thing::Spirit') }
94
+
95
+ it 'returns Thing::Spirit' do
96
+ implementation.constant.should eq(Thing::Spirit)
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '#all_implementations' do
102
+ let(:implementation) { Mutant::Implementation.allocate }
103
+
104
+ before do
105
+ implementation.should_receive(:all_methods) { ['Thing.alive?'] }
106
+ end
107
+
108
+ let(:all_implementations) { implementation.all_implementations }
109
+
110
+ it 'returns an array of Implementation instances' do
111
+ all_implementations.should have(1).implementation
112
+ all_implementations.first.should be_a(Mutant::Implementation)
113
+ end
114
+ end
115
+
116
+ describe '#all_methods' do
117
+ let(:implementation) { Mutant::Implementation.allocate }
118
+
119
+ before do
120
+ implementation.stub(
121
+ :all_singleton_methods => [:a], :all_instance_methods => [:b]
122
+ )
123
+ end
124
+
125
+ it 'concatenates #all_singleton_methods and #all_instance_methods' do
126
+ implementation.all_methods.should eq([:a, :b])
127
+ end
128
+ end
129
+
130
+ describe '#all_singleton_methods' do
131
+ context 'given "Thing"' do
132
+ context 'and Thing has no singleton methods' do
133
+ setup_thing
134
+
135
+ it 'returns an empty array' do
136
+ Mutant::Implementation.new('Thing').all_singleton_methods.should be_empty
137
+ end
138
+ end
139
+
140
+ context 'and Thing has a singleton method' do
141
+ setup_thing do
142
+ def self.alive?() end
143
+ end
144
+
145
+ it 'returns the singleton method in an array' do
146
+ Mutant::Implementation.new('Thing').all_singleton_methods.should eq(
147
+ ['Thing.alive?']
148
+ )
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ describe '#all_instance_methods' do
155
+ context 'given "Thing"' do
156
+ context 'and Thing has no instance methods' do
157
+ setup_thing
158
+
159
+ it 'returns an empty array' do
160
+ Mutant::Implementation.new('Thing').all_instance_methods.should be_empty
161
+ end
162
+ end
163
+
164
+ context 'and Thing has an instance method named "alive?"' do
165
+ setup_thing do
166
+ def alive?() end
167
+ end
168
+
169
+ it 'returns "Thing#alive?" in an array' do
170
+ Mutant::Implementation.new('Thing').all_instance_methods.should eq(
171
+ ['Thing#alive?']
172
+ )
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ describe '#mutatees' do
179
+ context 'given "Thing.alive?"' do
180
+ let(:implementation) { Mutant::Implementation.new('Thing.alive?') }
181
+
182
+ it 'returns an array with one mutatee' do
183
+ implementation.mutatees.should have(1).mutatee
184
+ implementation.mutatees.first.should be_a(Mutant::Mutatee)
185
+ end
186
+ end
187
+
188
+ context 'given "Thing#alive?"' do
189
+ let(:implementation) { Mutant::Implementation.new('Thing#alive?') }
190
+
191
+ it 'returns an array with one mutatee' do
192
+ implementation.mutatees.should have(1).mutatee
193
+ implementation.mutatees.first.should be_a(Mutant::Mutatee)
194
+ end
195
+ end
196
+
197
+ context 'given "Thing"' do
198
+ context 'and Thing has no methods' do
199
+ setup_thing
200
+
201
+ it 'returns an empty array' do
202
+ Mutant::Implementation.new('Thing').mutatees.should be_empty
203
+ end
204
+ end
205
+
206
+ context 'and Thing has a singleton and instance method' do
207
+ setup_thing do
208
+ def self.alive?() end
209
+ def alive?() end
210
+ end
211
+
212
+ let(:implementation) { Mutant::Implementation.new('Thing') }
213
+
214
+ it 'returns an array with two mutatees' do
215
+ implementation.should have(2).mutatees
216
+ implementation.mutatees.each do |mutatee|
217
+ mutatee.should be_a(Mutant::Mutatee)
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end