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.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -4
  3. data/Changelog.md +8 -0
  4. data/README.md +112 -43
  5. data/Rakefile +2 -16
  6. data/circle.yml +1 -1
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +3 -4
  10. data/config/rubocop.yml +53 -16
  11. data/lib/mutant.rb +27 -6
  12. data/lib/mutant/ast/meta/const.rb +2 -0
  13. data/lib/mutant/ast/meta/optarg.rb +2 -0
  14. data/lib/mutant/ast/meta/resbody.rb +2 -0
  15. data/lib/mutant/ast/meta/restarg.rb +2 -0
  16. data/lib/mutant/ast/meta/send.rb +4 -0
  17. data/lib/mutant/ast/meta/symbol.rb +2 -0
  18. data/lib/mutant/ast/named_children.rb +14 -4
  19. data/lib/mutant/ast/nodes.rb +3 -1
  20. data/lib/mutant/ast/regexp.rb +53 -0
  21. data/lib/mutant/ast/regexp/transformer.rb +185 -0
  22. data/lib/mutant/ast/regexp/transformer/alternative.rb +39 -0
  23. data/lib/mutant/ast/regexp/transformer/character_set.rb +46 -0
  24. data/lib/mutant/ast/regexp/transformer/direct.rb +99 -0
  25. data/lib/mutant/ast/regexp/transformer/options_group.rb +66 -0
  26. data/lib/mutant/ast/regexp/transformer/quantifier.rb +112 -0
  27. data/lib/mutant/ast/regexp/transformer/recursive.rb +50 -0
  28. data/lib/mutant/ast/regexp/transformer/root.rb +29 -0
  29. data/lib/mutant/ast/regexp/transformer/text.rb +55 -0
  30. data/lib/mutant/ast/types.rb +92 -5
  31. data/lib/mutant/cli.rb +2 -14
  32. data/lib/mutant/color.rb +1 -1
  33. data/lib/mutant/config.rb +1 -3
  34. data/lib/mutant/expression/methods.rb +1 -1
  35. data/lib/mutant/expression/namespace.rb +2 -2
  36. data/lib/mutant/expression/parser.rb +1 -1
  37. data/lib/mutant/integration.rb +10 -28
  38. data/lib/mutant/isolation.rb +9 -60
  39. data/lib/mutant/isolation/fork.rb +72 -0
  40. data/lib/mutant/isolation/none.rb +25 -0
  41. data/lib/mutant/matcher/config.rb +2 -0
  42. data/lib/mutant/matcher/method/singleton.rb +5 -4
  43. data/lib/mutant/meta.rb +11 -4
  44. data/lib/mutant/meta/example.rb +2 -116
  45. data/lib/mutant/meta/example/dsl.rb +22 -19
  46. data/lib/mutant/meta/example/verification.rb +86 -0
  47. data/lib/mutant/mutator.rb +22 -49
  48. data/lib/mutant/mutator/node.rb +15 -19
  49. data/lib/mutant/mutator/node/and_asgn.rb +1 -1
  50. data/lib/mutant/mutator/node/argument.rb +10 -5
  51. data/lib/mutant/mutator/node/arguments.rb +5 -9
  52. data/lib/mutant/mutator/node/begin.rb +4 -17
  53. data/lib/mutant/mutator/node/block.rb +1 -1
  54. data/lib/mutant/mutator/node/break.rb +1 -1
  55. data/lib/mutant/mutator/node/class.rb +21 -0
  56. data/lib/mutant/mutator/node/conditional_loop.rb +1 -1
  57. data/lib/mutant/mutator/node/define.rb +1 -1
  58. data/lib/mutant/mutator/node/defined.rb +1 -1
  59. data/lib/mutant/mutator/node/dstr.rb +1 -1
  60. data/lib/mutant/mutator/node/dsym.rb +1 -1
  61. data/lib/mutant/mutator/node/generic.rb +3 -3
  62. data/lib/mutant/mutator/node/kwbegin.rb +1 -1
  63. data/lib/mutant/mutator/node/literal.rb +9 -0
  64. data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
  65. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -2
  66. data/lib/mutant/mutator/node/literal/float.rb +4 -6
  67. data/lib/mutant/mutator/node/literal/hash.rb +1 -1
  68. data/lib/mutant/mutator/node/literal/nil.rb +1 -1
  69. data/lib/mutant/mutator/node/literal/range.rb +2 -19
  70. data/lib/mutant/mutator/node/literal/regex.rb +43 -3
  71. data/lib/mutant/mutator/node/literal/string.rb +1 -1
  72. data/lib/mutant/mutator/node/literal/symbol.rb +2 -4
  73. data/lib/mutant/mutator/node/masgn.rb +1 -1
  74. data/lib/mutant/mutator/node/match_current_line.rb +1 -1
  75. data/lib/mutant/mutator/node/mlhs.rb +2 -3
  76. data/lib/mutant/mutator/node/named_value/access.rb +2 -2
  77. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +4 -3
  78. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +4 -4
  79. data/lib/mutant/mutator/node/next.rb +1 -1
  80. data/lib/mutant/mutator/node/nthref.rb +1 -1
  81. data/lib/mutant/mutator/node/or_asgn.rb +1 -1
  82. data/lib/mutant/mutator/node/regexp.rb +44 -0
  83. data/lib/mutant/mutator/node/regopt.rb +31 -0
  84. data/lib/mutant/mutator/node/resbody.rb +1 -1
  85. data/lib/mutant/mutator/node/rescue.rb +1 -3
  86. data/lib/mutant/mutator/node/return.rb +1 -1
  87. data/lib/mutant/mutator/node/send.rb +43 -3
  88. data/lib/mutant/mutator/node/send/attribute_assignment.rb +4 -1
  89. data/lib/mutant/mutator/node/send/conditional.rb +23 -0
  90. data/lib/mutant/mutator/node/send/index.rb +1 -1
  91. data/lib/mutant/mutator/node/splat.rb +1 -1
  92. data/lib/mutant/mutator/node/when.rb +1 -1
  93. data/lib/mutant/mutator/node/yield.rb +1 -1
  94. data/lib/mutant/mutator/util.rb +0 -30
  95. data/lib/mutant/mutator/util/array.rb +4 -16
  96. data/lib/mutant/parallel.rb +1 -1
  97. data/lib/mutant/parallel/worker.rb +1 -1
  98. data/lib/mutant/registry.rb +44 -0
  99. data/lib/mutant/reporter/cli/format.rb +2 -0
  100. data/lib/mutant/reporter/cli/printer.rb +2 -2
  101. data/lib/mutant/reporter/cli/printer/config.rb +0 -1
  102. data/lib/mutant/reporter/cli/printer/env_progress.rb +1 -11
  103. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +1 -1
  104. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -0
  105. data/lib/mutant/reporter/cli/tput.rb +1 -1
  106. data/lib/mutant/reporter/sequence.rb +3 -0
  107. data/lib/mutant/require_highjack.rb +6 -2
  108. data/lib/mutant/result.rb +1 -1
  109. data/lib/mutant/subject.rb +5 -5
  110. data/lib/mutant/subject/method/instance.rb +1 -2
  111. data/lib/mutant/util.rb +18 -0
  112. data/lib/mutant/version.rb +1 -1
  113. data/lib/mutant/zombifier.rb +5 -3
  114. data/meta/and.rb +1 -1
  115. data/meta/and_asgn.rb +1 -1
  116. data/meta/array.rb +2 -2
  117. data/meta/begin.rb +2 -2
  118. data/meta/block.rb +7 -7
  119. data/meta/block_pass.rb +1 -1
  120. data/meta/blockarg.rb +1 -1
  121. data/meta/break.rb +1 -1
  122. data/meta/case.rb +2 -2
  123. data/meta/casgn.rb +11 -2
  124. data/meta/cbase.rb +1 -1
  125. data/meta/class.rb +10 -0
  126. data/meta/const.rb +9 -1
  127. data/meta/csend.rb +8 -0
  128. data/meta/cvar.rb +1 -1
  129. data/meta/cvasgn.rb +1 -1
  130. data/meta/date.rb +4 -4
  131. data/meta/def.rb +14 -14
  132. data/meta/defined.rb +1 -1
  133. data/meta/dstr.rb +1 -1
  134. data/meta/dsym.rb +1 -1
  135. data/meta/ensure.rb +1 -1
  136. data/meta/false.rb +1 -1
  137. data/meta/float.rb +3 -3
  138. data/meta/gvar.rb +1 -1
  139. data/meta/gvasgn.rb +1 -1
  140. data/meta/hash.rb +1 -1
  141. data/meta/if.rb +17 -3
  142. data/meta/int.rb +1 -1
  143. data/meta/ivar.rb +1 -1
  144. data/meta/ivasgn.rb +14 -1
  145. data/meta/kwarg.rb +8 -0
  146. data/meta/kwbegin.rb +1 -1
  147. data/meta/kwoptarg.rb +11 -0
  148. data/meta/lvar.rb +1 -1
  149. data/meta/lvasgn.rb +1 -1
  150. data/meta/masgn.rb +1 -1
  151. data/meta/match_current_line.rb +2 -2
  152. data/meta/next.rb +1 -1
  153. data/meta/nil.rb +1 -1
  154. data/meta/nthref.rb +5 -5
  155. data/meta/op_assgn.rb +1 -1
  156. data/meta/or.rb +1 -1
  157. data/meta/or_asgn.rb +5 -5
  158. data/meta/range.rb +2 -8
  159. data/meta/redo.rb +1 -1
  160. data/meta/regexp.rb +106 -0
  161. data/meta/regexp/regexp_bol_anchor.rb +13 -0
  162. data/meta/regexp/regexp_bos_anchor.rb +26 -0
  163. data/meta/regexp/regexp_root_expression.rb +13 -0
  164. data/meta/regopt.rb +8 -0
  165. data/meta/rescue.rb +49 -4
  166. data/meta/restarg.rb +6 -9
  167. data/meta/return.rb +2 -2
  168. data/meta/self.rb +1 -1
  169. data/meta/send.rb +228 -55
  170. data/meta/str.rb +1 -1
  171. data/meta/super.rb +3 -3
  172. data/meta/{symbol.rb → sym.rb} +1 -1
  173. data/meta/true.rb +1 -1
  174. data/meta/until.rb +1 -1
  175. data/meta/while.rb +2 -2
  176. data/meta/yield.rb +1 -1
  177. data/mutant-rspec.gemspec +2 -2
  178. data/mutant.gemspec +6 -5
  179. data/spec/integration/mutant/isolation/fork_spec.rb +8 -0
  180. data/spec/integration/mutant/rspec_spec.rb +1 -1
  181. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -2
  182. data/spec/integrations.yml +93 -24
  183. data/spec/spec_helper.rb +12 -7
  184. data/spec/support/compress_helper.rb +1 -1
  185. data/spec/support/corpus.rb +115 -50
  186. data/spec/support/fake_actor.rb +5 -5
  187. data/spec/support/file_system.rb +1 -1
  188. data/spec/support/ice_nine_config.rb +3 -3
  189. data/spec/support/ruby_vm.rb +11 -12
  190. data/spec/support/shared_context.rb +22 -13
  191. data/spec/support/test_app.rb +1 -1
  192. data/spec/support/warning.rb +64 -0
  193. data/spec/support/warnings.yml +4 -0
  194. data/spec/support/xspec.rb +177 -0
  195. data/spec/unit/mutant/actor/env_spec.rb +2 -2
  196. data/spec/unit/mutant/actor/sender_spec.rb +1 -1
  197. data/spec/unit/mutant/ast/meta/send_spec.rb +1 -1
  198. data/spec/unit/mutant/ast/named_children_spec.rb +26 -0
  199. data/spec/unit/mutant/ast/regexp/parse_spec.rb +7 -0
  200. data/spec/unit/mutant/ast/regexp/supported_predicate_spec.rb +14 -0
  201. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +19 -0
  202. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +33 -0
  203. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +19 -0
  204. data/spec/unit/mutant/ast/regexp_spec.rb +617 -0
  205. data/spec/unit/mutant/cli_spec.rb +7 -45
  206. data/spec/unit/mutant/context_spec.rb +4 -7
  207. data/spec/unit/mutant/env/{boostrap_spec.rb → bootstrap_spec.rb} +2 -2
  208. data/spec/unit/mutant/env_spec.rb +13 -16
  209. data/spec/unit/mutant/expression/namespace/{flat_spec.rb → exact_spec.rb} +0 -0
  210. data/spec/unit/mutant/integration/rspec_spec.rb +2 -2
  211. data/spec/unit/mutant/integration_spec.rb +14 -0
  212. data/spec/unit/mutant/isolation/fork_spec.rb +155 -0
  213. data/spec/unit/mutant/isolation/none_spec.rb +16 -0
  214. data/spec/unit/mutant/loader_spec.rb +1 -1
  215. data/spec/unit/mutant/matcher/methods/instance_spec.rb +2 -4
  216. data/spec/unit/mutant/meta/example/dsl_spec.rb +106 -0
  217. data/spec/unit/mutant/meta/example/verification_spec.rb +120 -0
  218. data/spec/unit/mutant/meta/example_spec.rb +32 -0
  219. data/spec/unit/mutant/mutator/node_spec.rb +37 -4
  220. data/spec/unit/mutant/mutator_spec.rb +21 -0
  221. data/spec/unit/mutant/{runner → parallel}/driver_spec.rb +0 -0
  222. data/spec/unit/mutant/parallel/master_spec.rb +13 -13
  223. data/spec/unit/mutant/registry_spec.rb +47 -0
  224. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -4
  225. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -8
  226. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -2
  227. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -8
  228. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -34
  229. data/spec/unit/mutant/reporter/cli_spec.rb +0 -22
  230. data/spec/unit/mutant/repository/diff_spec.rb +6 -6
  231. data/spec/unit/mutant/require_highjack_spec.rb +38 -14
  232. data/spec/unit/mutant/result/env_spec.rb +1 -4
  233. data/spec/unit/mutant/runner_spec.rb +1 -1
  234. data/spec/unit/mutant/subject/method/instance_spec.rb +1 -1
  235. data/spec/unit/mutant/subject_spec.rb +3 -3
  236. data/spec/unit/mutant/util/one_spec.rb +20 -0
  237. data/spec/unit/mutant/zombifier_spec.rb +18 -18
  238. data/test_app/{Gemfile.rspec3.3 → Gemfile.rspec3.5} +2 -2
  239. metadata +94 -24
  240. data/TODO +0 -21
  241. data/lib/mutant/mutator/node/blockarg.rb +0 -13
  242. data/lib/mutant/mutator/node/restarg.rb +0 -13
  243. data/lib/mutant/mutator/registry.rb +0 -49
  244. data/meta/boolean.rb +0 -13
  245. data/meta/regex.rb +0 -19
  246. data/spec/unit/mutant/isolation_spec.rb +0 -104
  247. data/spec/unit/mutant/mutator/registry_spec.rb +0 -57
@@ -125,13 +125,11 @@ Environment:
125
125
  -j, --jobs NUMBER Number of kill jobs. Defaults to number of processors.
126
126
 
127
127
  Options:
128
- --expected-coverage COVERAGE Fail unless COVERAGE is not reached exactly, parsed via Rational()
129
128
  --use INTEGRATION Use INTEGRATION to kill mutations
130
129
  --ignore-subject EXPRESSION Ignore subjects that match EXPRESSION as prefix
131
130
  --since REVISION Only select subjects touched since REVISION
132
131
  --fail-fast Fail fast
133
132
  --version Print mutants version
134
- -d, --debug Enable debugging output
135
133
  -h, --help Show this message
136
134
  MESSAGE
137
135
  end
@@ -151,6 +149,12 @@ Options:
151
149
  context 'when integration exists' do
152
150
  let(:flags) { %w[--use rspec] }
153
151
 
152
+ before do
153
+ expect(Kernel).to receive(:require)
154
+ .with('mutant/integration/rspec')
155
+ .and_call_original
156
+ end
157
+
154
158
  it_should_behave_like 'a cli parser'
155
159
 
156
160
  let(:expected_integration) { Mutant::Integration::Rspec }
@@ -189,38 +193,6 @@ Options:
189
193
  end
190
194
  end
191
195
 
192
- context 'with expected-coverage flag' do
193
- context 'given as decimal' do
194
- let(:flags) { %w[--expected-coverage 0.1] }
195
-
196
- it_should_behave_like 'a cli parser'
197
-
198
- it 'configures expected coverage' do
199
- expect(subject.config.expected_coverage).to eql(Rational(1, 10))
200
- end
201
- end
202
-
203
- context 'given as scientific' do
204
- let(:flags) { %w[--expected-coverage 1e-1] }
205
-
206
- it_should_behave_like 'a cli parser'
207
-
208
- it 'configures expected coverage' do
209
- expect(subject.config.expected_coverage).to eql(Rational(1, 10))
210
- end
211
- end
212
-
213
- context 'given as rational' do
214
- let(:flags) { %w[--expected-coverage 1/10] }
215
-
216
- it_should_behave_like 'a cli parser'
217
-
218
- it 'configures expected coverage' do
219
- expect(subject.config.expected_coverage).to eql(Rational(1, 10))
220
- end
221
- end
222
- end
223
-
224
196
  context 'with require flags' do
225
197
  let(:flags) { %w[--require foo --require bar] }
226
198
 
@@ -271,18 +243,8 @@ Options:
271
243
  end
272
244
  end
273
245
 
274
- context 'with debug flag' do
275
- let(:flags) { %w[--debug] }
276
-
277
- it_should_behave_like 'a cli parser'
278
-
279
- it 'sets the debug option' do
280
- expect(subject.config.debug).to be(true)
281
- end
282
- end
283
-
284
246
  context 'with zombie flag' do
285
- let(:flags) { %w[--zombie] }
247
+ let(:flags) { %w[--zombie] }
286
248
 
287
249
  it_should_behave_like 'a cli parser'
288
250
 
@@ -1,18 +1,16 @@
1
- # rubocop:disable ClosingParenthesisIndentation
2
1
  RSpec.describe Mutant::Context do
3
2
  describe '.wrap' do
4
3
  subject { described_class.wrap(scope, node) }
5
4
 
6
- let(:node) { s(:str, 'test') }
5
+ let(:node) { s(:str, 'test') }
7
6
 
8
7
  context 'with Module as scope' do
9
- let(:scope) { Mutant }
8
+ let(:scope) { Mutant }
10
9
 
11
10
  let(:expected) do
12
11
  s(:module,
13
12
  s(:const, nil, :Mutant),
14
- s(:str, 'test')
15
- )
13
+ s(:str, 'test'))
16
14
  end
17
15
 
18
16
  it { should eql(expected) }
@@ -25,8 +23,7 @@ RSpec.describe Mutant::Context do
25
23
  s(:class,
26
24
  s(:const, nil, :Context),
27
25
  nil,
28
- s(:str, 'test')
29
- )
26
+ s(:str, 'test'))
30
27
  end
31
28
 
32
29
  it { should eql(expected) }
@@ -177,8 +177,8 @@ RSpec.describe Mutant::Env::Bootstrap do
177
177
  Mutant::Scope.new(TestApp::Empty, match_expressions.last),
178
178
  Mutant::Scope.new(TestApp::Literal, match_expressions.first)
179
179
  ],
180
- mutations: subjects.flat_map(&:mutations),
181
- subjects: subjects
180
+ mutations: subjects.flat_map(&:mutations),
181
+ subjects: subjects
182
182
  )
183
183
  end
184
184
 
@@ -13,18 +13,15 @@ RSpec.describe Mutant::Env do
13
13
  )
14
14
  end
15
15
 
16
- let(:integration) { instance_double(Mutant::Integration) }
17
- let(:wrapped_node) { instance_double(Parser::AST::Node) }
18
- let(:context) { instance_double(Mutant::Context) }
19
- let(:test_a) { instance_double(Mutant::Test) }
20
- let(:test_b) { instance_double(Mutant::Test) }
21
- let(:tests) { [test_a, test_b] }
22
- let(:selector) { instance_double(Mutant::Selector) }
23
- let(:integration_class) { Mutant::Integration::Null }
24
-
25
- let(:isolation) do
26
- instance_double(Mutant::Isolation::Fork.singleton_class)
27
- end
16
+ let(:integration) { instance_double(Mutant::Integration) }
17
+ let(:wrapped_node) { instance_double(Parser::AST::Node) }
18
+ let(:context) { instance_double(Mutant::Context) }
19
+ let(:test_a) { instance_double(Mutant::Test) }
20
+ let(:test_b) { instance_double(Mutant::Test) }
21
+ let(:tests) { [test_a, test_b] }
22
+ let(:selector) { instance_double(Mutant::Selector) }
23
+ let(:integration_class) { Mutant::Integration::Null }
24
+ let(:isolation) { instance_double(Mutant::Isolation::Fork) }
28
25
 
29
26
  let(:mutation) do
30
27
  instance_double(
@@ -37,16 +34,16 @@ RSpec.describe Mutant::Env do
37
34
  Mutant::Config::DEFAULT.with(
38
35
  isolation: isolation,
39
36
  integration: integration_class,
40
- kernel: instance_double(Kernel.singleton_class)
37
+ kernel: class_double(Kernel)
41
38
  )
42
39
  end
43
40
 
44
41
  let(:mutation_subject) do
45
42
  instance_double(
46
43
  Mutant::Subject,
47
- context: context,
44
+ context: context,
48
45
  identification: 'subject',
49
- source: 'original'
46
+ source: 'original'
50
47
  )
51
48
  end
52
49
 
@@ -56,7 +53,7 @@ RSpec.describe Mutant::Env do
56
53
  specify do
57
54
  should eql(
58
55
  Mutant::Result::Mutation.new(
59
- mutation: mutation,
56
+ mutation: mutation,
60
57
  test_result: test_result
61
58
  )
62
59
  )
@@ -88,8 +88,8 @@ RSpec.describe Mutant::Integration::Rspec do
88
88
  let(:world) do
89
89
  double(
90
90
  'world',
91
- example_groups: example_groups,
92
- filtered_examples: filtered_examples
91
+ example_groups: example_groups,
92
+ filtered_examples: filtered_examples
93
93
  )
94
94
  end
95
95
 
@@ -10,6 +10,20 @@ RSpec.describe Mutant::Integration do
10
10
  subject { object.setup }
11
11
  it_should_behave_like 'a command method'
12
12
  end
13
+
14
+ describe '.setup' do
15
+ subject { described_class.setup(kernel, name) }
16
+
17
+ let(:name) { 'null' }
18
+ let(:kernel) { class_double(Kernel) }
19
+
20
+ before do
21
+ expect(kernel).to receive(:require)
22
+ .with('mutant/integration/null')
23
+ end
24
+
25
+ it { should be(Mutant::Integration::Null) }
26
+ end
13
27
  end
14
28
 
15
29
  RSpec.describe Mutant::Integration::Null do
@@ -0,0 +1,155 @@
1
+ # The fork isolation is all about managing a series of systemcalls with proper error handling
2
+ #
3
+ # So creating a unit spec for this is challenging. Especially under mutation testing.
4
+ # Hence we even have to implement our own message expectation mechanism, as rspec build in
5
+ # expectations are not able to correctly specify a sequence of expectations where a specific
6
+ # message is send twice.
7
+ #
8
+ # Also our replacement for rspec-expectations used here allows easier deduplication.
9
+ RSpec.describe Mutant::Isolation::Fork do
10
+ let(:block_return) { instance_double(Object, :block_return) }
11
+ let(:block_return_blob) { instance_double(String, :block_return_blob) }
12
+ let(:devnull) { instance_double(Proc, :devnull) }
13
+ let(:io) { class_double(IO) }
14
+ let(:isolated_block) { -> { block_return } }
15
+ let(:marshal) { class_double(Marshal) }
16
+ let(:process) { class_double(Process) }
17
+ let(:pid) { class_double(Fixnum) }
18
+ let(:reader) { instance_double(IO, :reader) }
19
+ let(:stderr) { instance_double(IO, :stderr) }
20
+ let(:stdout) { instance_double(IO, :stdout) }
21
+ let(:writer) { instance_double(IO, :writer) }
22
+ let(:nullio) { instance_double(IO, :nullio) }
23
+
24
+ describe '#call' do
25
+ let(:object) do
26
+ described_class.new(
27
+ devnull: devnull,
28
+ io: io,
29
+ marshal: marshal,
30
+ process: process,
31
+ stderr: stderr,
32
+ stdout: stdout
33
+ )
34
+ end
35
+
36
+ subject { object.call(&isolated_block) }
37
+
38
+ let(:prefork_expectations) do
39
+ [
40
+ {
41
+ receiver: io,
42
+ selector: :pipe,
43
+ arguments: [binmode: true],
44
+ reaction: {
45
+ yields: [[reader, writer]]
46
+ }
47
+ }
48
+ ]
49
+ end
50
+
51
+ context 'when no IO operation fails' do
52
+ let(:expectations) do
53
+ [
54
+ *prefork_expectations,
55
+ {
56
+ receiver: process,
57
+ selector: :fork,
58
+ reaction: {
59
+ yields: [],
60
+ return: pid
61
+ }
62
+ },
63
+ # Inside the killfork
64
+ {
65
+ receiver: reader,
66
+ selector: :close
67
+ },
68
+ {
69
+ receiver: writer,
70
+ selector: :binmode
71
+ },
72
+ {
73
+ receiver: devnull,
74
+ selector: :call,
75
+ reaction: {
76
+ yields: [nullio]
77
+ }
78
+ },
79
+ {
80
+ receiver: stderr,
81
+ selector: :reopen,
82
+ arguments: [nullio]
83
+ },
84
+ {
85
+ receiver: stdout,
86
+ selector: :reopen,
87
+ arguments: [nullio]
88
+ },
89
+ {
90
+ receiver: marshal,
91
+ selector: :dump,
92
+ arguments: [block_return],
93
+ reaction: {
94
+ return: block_return_blob
95
+ }
96
+ },
97
+ {
98
+ receiver: writer,
99
+ selector: :syswrite,
100
+ arguments: [block_return_blob]
101
+ },
102
+ {
103
+ receiver: writer,
104
+ selector: :close
105
+ },
106
+ # Outside the killfork
107
+ {
108
+ receiver: writer,
109
+ selector: :close
110
+ },
111
+ {
112
+ receiver: marshal,
113
+ selector: :load,
114
+ arguments: [reader],
115
+ reaction: {
116
+ return: block_return
117
+ }
118
+ },
119
+ {
120
+ receiver: process,
121
+ selector: :waitpid,
122
+ arguments: [pid]
123
+ }
124
+ ].map(&XSpec::MessageExpectation.method(:parse))
125
+ end
126
+
127
+ specify do
128
+ XSpec::ExpectationVerifier.verify(self, expectations) do
129
+ expect(subject).to be(block_return)
130
+ end
131
+ end
132
+ end
133
+
134
+ context 'when fork fails' do
135
+ let(:expectations) do
136
+ [
137
+ *prefork_expectations,
138
+ {
139
+ receiver: process,
140
+ selector: :fork,
141
+ reaction: {
142
+ exception: RuntimeError.new('fork(2)')
143
+ }
144
+ }
145
+ ].map(&XSpec::MessageExpectation.method(:parse))
146
+ end
147
+
148
+ specify do
149
+ XSpec::ExpectationVerifier.verify(self, expectations) do
150
+ expect { expect(subject) }.to raise_error(described_class::Error, 'fork(2)')
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,16 @@
1
+ RSpec.describe Mutant::Isolation::None do
2
+ describe '.call' do
3
+ let(:object) { described_class.new }
4
+
5
+ it 'return block value' do
6
+ expect(object.call { :foo }).to be(:foo)
7
+ end
8
+
9
+ it 'wraps *all* exceptions' do
10
+ expect { object.call { fail 'foo' } }.to raise_error(
11
+ Mutant::Isolation::Error,
12
+ 'foo'
13
+ )
14
+ end
15
+ end
16
+ end
@@ -11,7 +11,7 @@ RSpec.describe Mutant::Loader, '.call' do
11
11
  let(:path) { instance_double(Pathname, to_s: path_str) }
12
12
  let(:path_str) { instance_double(String) }
13
13
  let(:line) { instance_double(Fixnum) }
14
- let(:kernel) { instance_double(Kernel.singleton_class) }
14
+ let(:kernel) { class_double(Kernel) }
15
15
  let(:binding) { instance_double(Binding) }
16
16
  let(:source) { instance_double(String) }
17
17
  let(:node) { instance_double(Parser::AST::Node) }
@@ -16,17 +16,15 @@ RSpec.describe Mutant::Matcher::Methods::Instance, '#call' do
16
16
 
17
17
  private :method_d
18
18
 
19
- public
20
-
21
19
  def method_a
22
20
  end
23
21
 
24
- protected
22
+ protected
25
23
 
26
24
  def method_b
27
25
  end
28
26
 
29
- private
27
+ private
30
28
 
31
29
  def method_c
32
30
  end
@@ -0,0 +1,106 @@
1
+ RSpec.describe Mutant::Meta::Example::DSL do
2
+ describe '.call' do
3
+ subject { described_class.call(file, type, block) }
4
+
5
+ let(:file) { 'foo.rb' }
6
+ let(:node) { s(:false) }
7
+ let(:type) { node.type }
8
+ let(:expected) { [] }
9
+
10
+ let(:expected_example) do
11
+ Mutant::Meta::Example.new(
12
+ file: file,
13
+ node: node,
14
+ node_type: type,
15
+ expected: expected
16
+ )
17
+ end
18
+
19
+ def self.expect_example(&block)
20
+ let(:block) { block }
21
+
22
+ specify do
23
+ # Kill mutations to warnings
24
+ warnings = Mutant::WarningFilter.use do
25
+ should eql(expected_example)
26
+ end
27
+ expect(warnings).to eql([])
28
+ end
29
+ end
30
+
31
+ def self.expect_error(message, &block)
32
+ let(:block) { block }
33
+
34
+ specify do
35
+ expect { subject }.to raise_error(RuntimeError, message)
36
+ end
37
+ end
38
+
39
+ context 'source as node' do
40
+ expect_example do
41
+ source s(:false)
42
+ end
43
+ end
44
+
45
+ context 'source as string' do
46
+ expect_example do
47
+ source 'false'
48
+ end
49
+ end
50
+
51
+ context 'on node that needs unparser preprocessing to be normalized' do
52
+ let(:node) { s(:send, s(:float, -1.0), :/, s(:float, 0.0)) }
53
+
54
+ expect_example do
55
+ source '(-1.0) / 0.0'
56
+ end
57
+ end
58
+
59
+ context 'using #mutation' do
60
+ let(:expected) { [s(:nil)] }
61
+
62
+ expect_example do
63
+ source 'false'
64
+
65
+ mutation 'nil'
66
+ end
67
+ end
68
+
69
+ context 'using #singleton_mutations' do
70
+ let(:expected) { [s(:nil), s(:self)] }
71
+
72
+ expect_example do
73
+ source 'false'
74
+
75
+ singleton_mutations
76
+ end
77
+ end
78
+
79
+ context 'no definition of source' do
80
+ expect_error('source not defined') do
81
+ end
82
+ end
83
+
84
+ context 'duplicate definition of source' do
85
+ expect_error('source already defined') do
86
+ source 'true'
87
+ source 'false'
88
+ end
89
+ end
90
+
91
+ context 'uncoercable source' do
92
+ expect_error('Cannot coerce to node: nil') do
93
+ source nil
94
+ end
95
+ end
96
+
97
+ context 'duplicate mutation expectation' do
98
+ expect_error('Mutation for input: "true" is already expected') do
99
+ source 'false'
100
+
101
+ mutation 'true'
102
+ mutation 'true'
103
+ end
104
+ end
105
+ end
106
+ end