mutant 0.8.24 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/Changelog.md +14 -654
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +59 -64
  6. data/LICENSE +271 -20
  7. data/README.md +73 -140
  8. data/Rakefile +0 -21
  9. data/bin/mutant +7 -2
  10. data/config/reek.yml +2 -1
  11. data/config/rubocop.yml +5 -9
  12. data/docs/incremental.md +76 -0
  13. data/docs/known-problems.md +0 -14
  14. data/docs/mutant-minitest.md +1 -1
  15. data/docs/mutant-rspec.md +2 -24
  16. data/lib/mutant.rb +45 -53
  17. data/lib/mutant/ast/nodes.rb +0 -2
  18. data/lib/mutant/ast/types.rb +1 -117
  19. data/lib/mutant/base.rb +192 -0
  20. data/lib/mutant/bootstrap.rb +145 -0
  21. data/lib/mutant/cli.rb +68 -54
  22. data/lib/mutant/config.rb +119 -6
  23. data/lib/mutant/env.rb +94 -8
  24. data/lib/mutant/expression.rb +6 -1
  25. data/lib/mutant/expression/parser.rb +9 -31
  26. data/lib/mutant/integration.rb +64 -36
  27. data/lib/mutant/isolation.rb +16 -1
  28. data/lib/mutant/isolation/fork.rb +105 -40
  29. data/lib/mutant/license.rb +34 -0
  30. data/lib/mutant/license/subscription.rb +47 -0
  31. data/lib/mutant/license/subscription/commercial.rb +57 -0
  32. data/lib/mutant/license/subscription/opensource.rb +77 -0
  33. data/lib/mutant/loader.rb +27 -4
  34. data/lib/mutant/matcher.rb +48 -1
  35. data/lib/mutant/matcher/chain.rb +1 -1
  36. data/lib/mutant/matcher/config.rb +0 -2
  37. data/lib/mutant/matcher/filter.rb +1 -1
  38. data/lib/mutant/matcher/method.rb +11 -7
  39. data/lib/mutant/matcher/methods.rb +1 -1
  40. data/lib/mutant/matcher/namespace.rb +1 -1
  41. data/lib/mutant/matcher/null.rb +1 -1
  42. data/lib/mutant/matcher/scope.rb +1 -1
  43. data/lib/mutant/meta/example/dsl.rb +0 -8
  44. data/lib/mutant/mutation.rb +1 -2
  45. data/lib/mutant/mutator/node.rb +2 -9
  46. data/lib/mutant/mutator/node/arguments.rb +1 -1
  47. data/lib/mutant/mutator/node/class.rb +0 -8
  48. data/lib/mutant/mutator/node/define.rb +0 -12
  49. data/lib/mutant/mutator/node/generic.rb +30 -44
  50. data/lib/mutant/mutator/node/index.rb +4 -4
  51. data/lib/mutant/mutator/node/literal/regex.rb +0 -39
  52. data/lib/mutant/mutator/node/send.rb +13 -12
  53. data/lib/mutant/parallel.rb +61 -40
  54. data/lib/mutant/parallel/driver.rb +59 -0
  55. data/lib/mutant/parallel/source.rb +6 -2
  56. data/lib/mutant/parallel/worker.rb +63 -45
  57. data/lib/mutant/range.rb +15 -0
  58. data/lib/mutant/reporter/cli.rb +5 -11
  59. data/lib/mutant/reporter/cli/format.rb +3 -46
  60. data/lib/mutant/reporter/cli/printer/config.rb +5 -6
  61. data/lib/mutant/reporter/cli/printer/env.rb +40 -0
  62. data/lib/mutant/reporter/cli/printer/env_progress.rb +13 -17
  63. data/lib/mutant/reporter/cli/printer/isolation_result.rb +17 -3
  64. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -3
  65. data/lib/mutant/reporter/cli/printer/status_progressive.rb +19 -10
  66. data/lib/mutant/repository.rb +0 -65
  67. data/lib/mutant/repository/diff.rb +104 -0
  68. data/lib/mutant/repository/diff/ranges.rb +52 -0
  69. data/lib/mutant/result.rb +16 -7
  70. data/lib/mutant/runner.rb +38 -47
  71. data/lib/mutant/runner/sink.rb +1 -1
  72. data/lib/mutant/selector/null.rb +19 -0
  73. data/lib/mutant/subject.rb +3 -1
  74. data/lib/mutant/subject/method/instance.rb +3 -1
  75. data/lib/mutant/transform.rb +511 -0
  76. data/lib/mutant/variable.rb +282 -0
  77. data/lib/mutant/version.rb +1 -1
  78. data/lib/mutant/warnings.rb +113 -0
  79. data/meta/case.rb +1 -0
  80. data/meta/class.rb +0 -9
  81. data/meta/def.rb +1 -26
  82. data/meta/regexp.rb +10 -20
  83. data/meta/send.rb +14 -46
  84. data/mutant-minitest.gemspec +1 -1
  85. data/mutant-rspec.gemspec +2 -2
  86. data/mutant.gemspec +15 -16
  87. data/mutant.yml +6 -0
  88. data/spec/integration/mutant/isolation/fork_spec.rb +22 -5
  89. data/spec/integration/mutant/minitest_spec.rb +3 -2
  90. data/spec/integration/mutant/rspec_spec.rb +4 -3
  91. data/spec/integrations.yml +16 -13
  92. data/spec/shared/base_behavior.rb +45 -0
  93. data/spec/shared/framework_integration_behavior.rb +43 -14
  94. data/spec/spec_helper.rb +21 -17
  95. data/spec/support/corpus.rb +56 -95
  96. data/spec/support/shared_context.rb +37 -14
  97. data/spec/support/xspec.rb +7 -3
  98. data/spec/unit/mutant/bootstrap_spec.rb +216 -0
  99. data/spec/unit/mutant/cli_spec.rb +173 -117
  100. data/spec/unit/mutant/config_spec.rb +126 -0
  101. data/spec/unit/mutant/either_spec.rb +247 -0
  102. data/spec/unit/mutant/env_spec.rb +162 -40
  103. data/spec/unit/mutant/expression/method_spec.rb +16 -0
  104. data/spec/unit/mutant/expression/parser_spec.rb +29 -33
  105. data/spec/unit/mutant/expression_spec.rb +5 -7
  106. data/spec/unit/mutant/integration_spec.rb +100 -9
  107. data/spec/unit/mutant/isolation/fork_spec.rb +125 -67
  108. data/spec/unit/mutant/isolation/result_spec.rb +33 -1
  109. data/spec/unit/mutant/license_spec.rb +257 -0
  110. data/spec/unit/mutant/loader_spec.rb +50 -11
  111. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -78
  112. data/spec/unit/mutant/matcher/method/instance_spec.rb +55 -11
  113. data/spec/unit/mutant/matcher/method/singleton_spec.rb +12 -2
  114. data/spec/unit/mutant/matcher_spec.rb +102 -0
  115. data/spec/unit/mutant/maybe_spec.rb +60 -0
  116. data/spec/unit/mutant/meta/example/dsl_spec.rb +1 -17
  117. data/spec/unit/mutant/mutation_spec.rb +13 -6
  118. data/spec/unit/mutant/parallel/driver_spec.rb +112 -14
  119. data/spec/unit/mutant/parallel/source/array_spec.rb +25 -17
  120. data/spec/unit/mutant/parallel/worker_spec.rb +182 -44
  121. data/spec/unit/mutant/parallel_spec.rb +105 -8
  122. data/spec/unit/mutant/range_spec.rb +141 -0
  123. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +7 -21
  124. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +15 -6
  125. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +10 -2
  126. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +12 -4
  127. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +31 -2
  128. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +4 -4
  129. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +5 -0
  130. data/spec/unit/mutant/reporter/cli_spec.rb +46 -123
  131. data/spec/unit/mutant/repository/diff/ranges_spec.rb +180 -0
  132. data/spec/unit/mutant/repository/diff_spec.rb +84 -71
  133. data/spec/unit/mutant/require_highjack_spec.rb +1 -1
  134. data/spec/unit/mutant/result/env_spec.rb +39 -9
  135. data/spec/unit/mutant/result/test_spec.rb +14 -0
  136. data/spec/unit/mutant/runner_spec.rb +88 -41
  137. data/spec/unit/mutant/selector/expression_spec.rb +11 -10
  138. data/spec/unit/mutant/selector/null_spec.rb +17 -0
  139. data/spec/unit/mutant/subject/method/instance_spec.rb +44 -5
  140. data/spec/unit/mutant/subject/method/singleton_spec.rb +9 -2
  141. data/spec/unit/mutant/subject_spec.rb +9 -1
  142. data/spec/unit/mutant/transform/array_spec.rb +92 -0
  143. data/spec/unit/mutant/transform/bool_spec.rb +63 -0
  144. data/spec/unit/mutant/transform/error_spec.rb +132 -0
  145. data/spec/unit/mutant/transform/exception_spec.rb +44 -0
  146. data/spec/unit/mutant/transform/hash_spec.rb +236 -0
  147. data/spec/unit/mutant/transform/index_spec.rb +92 -0
  148. data/spec/unit/mutant/transform/named_spec.rb +49 -0
  149. data/spec/unit/mutant/transform/primitive_spec.rb +56 -0
  150. data/spec/unit/mutant/transform/sequence_spec.rb +98 -0
  151. data/spec/unit/mutant/variable_spec.rb +618 -0
  152. data/spec/unit/mutant/warnings_spec.rb +89 -0
  153. data/spec/unit/mutant/world_spec.rb +63 -0
  154. data/test_app/Gemfile.minitest +0 -2
  155. metadata +79 -113
  156. data/.gitattributes +0 -1
  157. data/.ruby-gemset +0 -1
  158. data/config/triage.yml +0 -2
  159. data/lib/mutant/actor.rb +0 -57
  160. data/lib/mutant/actor/env.rb +0 -31
  161. data/lib/mutant/actor/mailbox.rb +0 -34
  162. data/lib/mutant/actor/receiver.rb +0 -42
  163. data/lib/mutant/actor/sender.rb +0 -26
  164. data/lib/mutant/ast/meta/restarg.rb +0 -19
  165. data/lib/mutant/ast/regexp.rb +0 -42
  166. data/lib/mutant/ast/regexp/transformer.rb +0 -187
  167. data/lib/mutant/ast/regexp/transformer/direct.rb +0 -123
  168. data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -59
  169. data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -83
  170. data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -114
  171. data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -58
  172. data/lib/mutant/ast/regexp/transformer/root.rb +0 -31
  173. data/lib/mutant/ast/regexp/transformer/text.rb +0 -60
  174. data/lib/mutant/env/bootstrap.rb +0 -160
  175. data/lib/mutant/matcher/compiler.rb +0 -60
  176. data/lib/mutant/mutator/node/regexp.rb +0 -35
  177. data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -23
  178. data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -28
  179. data/lib/mutant/mutator/node/regexp/character_type.rb +0 -32
  180. data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -23
  181. data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -23
  182. data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +0 -27
  183. data/lib/mutant/parallel/master.rb +0 -181
  184. data/lib/mutant/reporter/cli/printer/status.rb +0 -53
  185. data/lib/mutant/reporter/cli/tput.rb +0 -46
  186. data/lib/mutant/warning_filter.rb +0 -61
  187. data/meta/regexp/character_types.rb +0 -23
  188. data/meta/regexp/regexp_alternation_meta.rb +0 -13
  189. data/meta/regexp/regexp_bol_anchor.rb +0 -10
  190. data/meta/regexp/regexp_bos_anchor.rb +0 -18
  191. data/meta/regexp/regexp_capture_group.rb +0 -19
  192. data/meta/regexp/regexp_eol_anchor.rb +0 -10
  193. data/meta/regexp/regexp_eos_anchor.rb +0 -8
  194. data/meta/regexp/regexp_eos_ob_eol_anchor.rb +0 -10
  195. data/meta/regexp/regexp_greedy_zero_or_more.rb +0 -12
  196. data/meta/regexp/regexp_root_expression.rb +0 -10
  197. data/meta/restarg.rb +0 -10
  198. data/spec/support/fake_actor.rb +0 -111
  199. data/spec/support/warning.rb +0 -66
  200. data/spec/unit/mutant/actor/binding_spec.rb +0 -34
  201. data/spec/unit/mutant/actor/env_spec.rb +0 -31
  202. data/spec/unit/mutant/actor/mailbox_spec.rb +0 -28
  203. data/spec/unit/mutant/actor/message_spec.rb +0 -25
  204. data/spec/unit/mutant/actor/receiver_spec.rb +0 -58
  205. data/spec/unit/mutant/actor/sender_spec.rb +0 -24
  206. data/spec/unit/mutant/ast/regexp/parse_spec.rb +0 -19
  207. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +0 -21
  208. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +0 -35
  209. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +0 -21
  210. data/spec/unit/mutant/ast/regexp_spec.rb +0 -704
  211. data/spec/unit/mutant/env/bootstrap_spec.rb +0 -188
  212. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +0 -26
  213. data/spec/unit/mutant/parallel/master_spec.rb +0 -338
  214. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -121
  215. data/spec/unit/mutant/reporter/cli/tput_spec.rb +0 -50
  216. data/spec/unit/mutant/warning_filter_spec.rb +0 -106
  217. data/spec/unit/mutant_spec.rb +0 -17
  218. data/test_app/Gemfile.rspec3.7 +0 -7
@@ -3,19 +3,29 @@
3
3
  RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
4
4
  subject { object.call(env) }
5
5
 
6
- let(:object) { described_class.new(scope, method) }
7
- let(:method_name) { :foo }
8
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
9
- let(:method) { scope.instance_method(method_name) }
10
- let(:type) { :def }
11
- let(:method_arity) { 0 }
12
- let(:base) { TestApp::InstanceMethodTests }
6
+ let(:base) { TestApp::InstanceMethodTests }
7
+ let(:method) { scope.instance_method(method_name) }
8
+ let(:method_arity) { 0 }
9
+ let(:method_name) { :foo }
10
+ let(:object) { described_class.new(scope, method) }
11
+ let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
12
+ let(:type) { :def }
13
+ let(:warnings) { instance_double(Mutant::Warnings) }
14
+
15
+ let(:world) do
16
+ instance_double(
17
+ Mutant::World,
18
+ pathname: Pathname,
19
+ warnings: warnings
20
+ )
21
+ end
13
22
 
14
23
  let(:env) do
15
24
  instance_double(
16
- Mutant::Env::Bootstrap,
25
+ Mutant::Env,
17
26
  config: Mutant::Config::DEFAULT,
18
- parser: Fixtures::TEST_ENV.parser
27
+ parser: Fixtures::TEST_ENV.parser,
28
+ world: world
19
29
  )
20
30
  end
21
31
 
@@ -28,8 +38,9 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
28
38
  end
29
39
 
30
40
  context 'when method is defined inside eval' do
31
- let(:scope) { base::WithMemoizer }
32
- let(:method) { scope.instance_method(:boz) }
41
+ let(:subject_class) { Mutant::Subject::Method::Instance::Memoized }
42
+ let(:scope) { base::WithMemoizer }
43
+ let(:method) { scope.instance_method(:boz) }
33
44
 
34
45
  let(:expected_warnings) do
35
46
  [
@@ -38,6 +49,10 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
38
49
  end
39
50
 
40
51
  include_examples 'skipped candidate'
52
+
53
+ it 'returns expected subjects' do
54
+ expect(subject).to eql([])
55
+ end
41
56
  end
42
57
 
43
58
  context 'when method is defined without source location' do
@@ -51,6 +66,10 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
51
66
  end
52
67
 
53
68
  include_examples 'skipped candidate'
69
+
70
+ it 'returns expected subjects' do
71
+ expect(subject).to eql([])
72
+ end
54
73
  end
55
74
 
56
75
  context 'in module eval' do
@@ -63,6 +82,10 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
63
82
  end
64
83
 
65
84
  include_examples 'skipped candidate'
85
+
86
+ it 'returns expected subjects' do
87
+ expect(subject).to eql([])
88
+ end
66
89
  end
67
90
 
68
91
  context 'in class eval' do
@@ -75,6 +98,10 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
75
98
  end
76
99
 
77
100
  include_examples 'skipped candidate'
101
+
102
+ it 'returns expected subjects' do
103
+ expect(subject).to eql([])
104
+ end
78
105
  end
79
106
 
80
107
  context 'when method is defined once' do
@@ -83,6 +110,23 @@ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
83
110
  let(:method_line) { 13 }
84
111
 
85
112
  it_should_behave_like 'a method matcher'
113
+
114
+ it 'returns expected subjects' do
115
+ context = Mutant::Context.new(
116
+ TestApp::InstanceMethodTests::WithMemoizer,
117
+ MutantSpec::ROOT.join('test_app', 'lib', 'test_app.rb')
118
+ )
119
+
120
+ expect(subject).to eql(
121
+ [
122
+ Mutant::Subject::Method::Instance.new(
123
+ context: context,
124
+ node: s(:def, :bar, s(:args), nil),
125
+ warnings: warnings
126
+ )
127
+ ]
128
+ )
129
+ end
86
130
  end
87
131
 
88
132
  context 'when method is defined once with a memoizer' do
@@ -10,12 +10,22 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#call' do
10
10
  let(:method_arity) { 0 }
11
11
  let(:base) { TestApp::SingletonMethodTests }
12
12
  let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
13
+ let(:warnings) { instance_double(Mutant::Warnings) }
14
+
15
+ let(:world) do
16
+ instance_double(
17
+ Mutant::World,
18
+ pathname: Pathname,
19
+ warnings: warnings
20
+ )
21
+ end
13
22
 
14
23
  let(:env) do
15
24
  instance_double(
16
- Mutant::Env::Bootstrap,
25
+ Mutant::Env,
17
26
  config: Mutant::Config::DEFAULT,
18
- parser: Fixtures::TEST_ENV.parser
27
+ parser: Fixtures::TEST_ENV.parser,
28
+ world: world
19
29
  )
20
30
  end
21
31
 
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Matcher do
4
+ describe '.from_config' do
5
+ def apply
6
+ described_class.from_config(config)
7
+ end
8
+
9
+ let(:anon_matcher) { instance_double(Mutant::Matcher) }
10
+ let(:env) { instance_double(Mutant::Env) }
11
+ let(:ignore_expressions) { [] }
12
+ let(:match_expression_a) { expression('Foo::Bar#a', matcher_a) }
13
+ let(:match_expression_b) { expression('Foo::Bar#b', matcher_b) }
14
+ let(:subject_filters) { [] }
15
+
16
+ let(:matcher_a) do
17
+ instance_double(Mutant::Matcher, call: [subject_a])
18
+ end
19
+
20
+ let(:matcher_b) do
21
+ instance_double(Mutant::Matcher, call: [subject_b])
22
+ end
23
+
24
+ let(:expression_class) do
25
+ Class.new(Mutant::Expression) do
26
+ include Concord.new(:child, :matcher)
27
+
28
+ %w[syntax prefix?].each do |name|
29
+ define_method(name) do |*arguments, &block|
30
+ child.public_send(name, *arguments, &block)
31
+ end
32
+ end
33
+
34
+ public :matcher
35
+ end
36
+ end
37
+
38
+ let(:config) do
39
+ Mutant::Matcher::Config.new(
40
+ ignore_expressions: ignore_expressions,
41
+ match_expressions: [match_expression_a, match_expression_b],
42
+ subject_filters: subject_filters
43
+ )
44
+ end
45
+
46
+ let(:subject_a) do
47
+ instance_double(Mutant::Subject, 'subject a', expression: expression('Foo::Bar#a'))
48
+ end
49
+
50
+ let(:subject_b) do
51
+ instance_double(Mutant::Subject, 'subject b', expression: expression('Foo::Bar#b'))
52
+ end
53
+
54
+ def expression(input, matcher = anon_matcher)
55
+ expression_class.new(parse_expression(input), matcher)
56
+ end
57
+
58
+ context 'empty ignores and empty filter' do
59
+ it 'returns expected subjects' do
60
+ expect(apply.call(env)).to eql([subject_a, subject_b])
61
+ end
62
+ end
63
+
64
+ context 'with ignore matching a subject' do
65
+ let(:ignore_expressions) { [subject_b.expression] }
66
+
67
+ it 'returns expected subjects' do
68
+ expect(apply.call(env)).to eql([subject_a])
69
+ end
70
+ end
71
+
72
+ context 'with ignore matching many subjects' do
73
+ let(:ignore_expressions) { [expression('Foo*')] }
74
+
75
+ it 'returns expected subjects' do
76
+ expect(apply.call(env)).to eql([])
77
+ end
78
+ end
79
+
80
+ context 'with subject filter' do
81
+ let(:subject_filters) do
82
+ [subject_a.method(:eql?)]
83
+ end
84
+
85
+ it 'returns expected subjects' do
86
+ expect(apply.call(env)).to eql([subject_a])
87
+ end
88
+ end
89
+
90
+ context 'with subject ignore and filter' do
91
+ let(:ignore_expressions) { [subject_b.expression] }
92
+
93
+ let(:subject_filters) do
94
+ [subject_b.method(:eql?)]
95
+ end
96
+
97
+ it 'returns expected subjects' do
98
+ expect(apply.call(env)).to eql([])
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Maybe::Nothing do
4
+ subject { described_class.new }
5
+
6
+ let(:block) { -> {} }
7
+
8
+ describe '#fmap' do
9
+ def apply
10
+ subject.fmap(&block)
11
+ end
12
+
13
+ include_examples 'no block evaluation'
14
+ include_examples 'requires block'
15
+ include_examples 'returns self'
16
+ end
17
+
18
+ describe '#apply' do
19
+ def apply
20
+ subject.apply(&block)
21
+ end
22
+
23
+ include_examples 'no block evaluation'
24
+ include_examples 'requires block'
25
+ include_examples 'returns self'
26
+ end
27
+ end
28
+
29
+ RSpec.describe Mutant::Maybe::Just do
30
+ subject { described_class.new(value) }
31
+
32
+ let(:block_result) { instance_double(Object, 'block result') }
33
+ let(:value) { instance_double(Object, 'value') }
34
+ let(:yields) { [] }
35
+
36
+ let(:block) do
37
+ lambda do |value|
38
+ yields << value
39
+ block_result
40
+ end
41
+ end
42
+
43
+ describe '#fmap' do
44
+ def apply
45
+ subject.fmap(&block)
46
+ end
47
+
48
+ include_examples 'requires block'
49
+ include_examples 'Functor#fmap block evaluation'
50
+ end
51
+
52
+ describe '#apply' do
53
+ def apply
54
+ subject.apply(&block)
55
+ end
56
+
57
+ include_examples 'requires block'
58
+ include_examples '#apply block evaluation'
59
+ end
60
+ end
@@ -23,7 +23,7 @@ RSpec.describe Mutant::Meta::Example::DSL do
23
23
 
24
24
  specify do
25
25
  # Kill mutations to warnings
26
- warnings = Mutant::WarningFilter.use do
26
+ warnings = Mutant::WORLD.warnings.call do
27
27
  should eql(expected_example)
28
28
  end
29
29
  expect(warnings).to eql([])
@@ -78,22 +78,6 @@ RSpec.describe Mutant::Meta::Example::DSL do
78
78
  end
79
79
  end
80
80
 
81
- context 'using #regexp_mutations' do
82
- let(:expected) do
83
- [s(:regexp, s(:regopt)), s(:regexp, s(:str, 'nomatch\\A'), s(:regopt))]
84
- end
85
-
86
- let(:node) do
87
- s(:regexp, s(:str, 'foo'), s(:regopt))
88
- end
89
-
90
- expect_example do
91
- source '/foo/'
92
-
93
- regexp_mutations
94
- end
95
- end
96
-
97
81
  context 'no definition of source' do
98
82
  expect_error('source not defined') do
99
83
  end
@@ -24,11 +24,16 @@ RSpec.describe Mutant::Mutation do
24
24
  end
25
25
 
26
26
  describe '#insert' do
27
- subject { object.insert(kernel) }
27
+ subject { object }
28
28
 
29
- let(:expected_source) { '1' }
30
- let(:kernel) { instance_double(Kernel) }
31
- let(:root_node) { s(:int, 1) }
29
+ def apply
30
+ subject.insert(kernel)
31
+ end
32
+
33
+ let(:expected_source) { '1' }
34
+ let(:kernel) { instance_double(Kernel) }
35
+ let(:loader_result) { instance_double(Mutant::Loader::Result) }
36
+ let(:root_node) { s(:int, 1) }
32
37
 
33
38
  before do
34
39
  expect(context).to receive(:root)
@@ -47,10 +52,12 @@ RSpec.describe Mutant::Mutation do
47
52
  source: expected_source,
48
53
  subject: mutation_subject
49
54
  )
50
- .and_return(Mutant::Loader)
55
+ .and_return(loader_result)
51
56
  end
52
57
 
53
- it_should_behave_like 'a command method'
58
+ it 'returns loader result' do
59
+ expect(apply).to be(loader_result)
60
+ end
54
61
  end
55
62
 
56
63
  describe '#code' do
@@ -1,28 +1,126 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Mutant::Parallel::Driver do
4
- let(:object) { described_class.new(binding) }
4
+ let(:active_jobs) { [] }
5
+ let(:thread_a) { instance_double(Thread, alive?: true) }
6
+ let(:thread_b) { instance_double(Thread, alive?: true) }
7
+ let(:threads) { [thread_a, thread_b] }
8
+ let(:timeout) { instance_double(Float) }
9
+ let(:sink_status) { instance_double(Object) }
5
10
 
6
- let(:binding) { instance_double(Mutant::Actor::Binding) }
7
- let(:value) { instance_double(Object, 'value') }
11
+ let(:sink) do
12
+ instance_double(
13
+ Mutant::Parallel::Sink,
14
+ status: sink_status
15
+ )
16
+ end
8
17
 
9
- describe '#stop' do
10
- subject { object.stop }
18
+ let(:var_active_jobs) do
19
+ instance_double(Mutant::Variable::IVar, 'active jobs')
20
+ end
11
21
 
12
- before do
13
- expect(binding).to receive(:call).with(:stop)
14
- end
22
+ let(:var_final) do
23
+ instance_double(Mutant::Variable::IVar, 'final')
24
+ end
25
+
26
+ let(:var_sink) do
27
+ instance_double(Mutant::Variable::IVar, 'sink')
28
+ end
15
29
 
16
- it_should_behave_like 'a command method'
30
+ subject do
31
+ described_class.new(
32
+ threads: threads,
33
+ var_active_jobs: var_active_jobs,
34
+ var_final: var_final,
35
+ var_sink: var_sink
36
+ )
17
37
  end
18
38
 
19
- describe '#status' do
20
- subject { object.status }
39
+ describe '#wait_timeout' do
40
+ def apply
41
+ subject.wait_timeout(timeout)
42
+ end
43
+
44
+ shared_examples 'returns expected status' do
45
+ it 'returns expected status' do
46
+ verify_events do
47
+ expect(apply).to eql(expected_status)
48
+ end
49
+ end
21
50
 
22
- before do
23
- expect(binding).to receive(:call).with(:status).and_return(value)
51
+ it 'returns frozen copy of active jobs' do
52
+ verify_events do
53
+ returned_active_jobs = apply.active_jobs
54
+
55
+ expect(returned_active_jobs).to_not be(active_jobs)
56
+ expect(returned_active_jobs.frozen?).to be(true)
57
+ end
58
+ end
24
59
  end
25
60
 
26
- it { should be(value) }
61
+ let(:raw_expectations) do
62
+ [
63
+ {
64
+ receiver: var_final,
65
+ selector: :take_timeout,
66
+ arguments: [timeout],
67
+ reaction: { return: Mutant::Variable.const_get(:Result)::Timeout.new }
68
+ },
69
+ {
70
+ receiver: var_active_jobs,
71
+ selector: :with,
72
+ reaction: { yields: [active_jobs] }
73
+ },
74
+ {
75
+ receiver: var_sink,
76
+ selector: :with,
77
+ reaction: { yields: [sink] }
78
+ }
79
+ ]
80
+ end
81
+
82
+ context 'when not done' do
83
+ let(:expected_status) do
84
+ Mutant::Parallel::Status.new(
85
+ active_jobs: active_jobs,
86
+ done: false,
87
+ payload: sink_status
88
+ )
89
+ end
90
+
91
+ include_examples 'returns expected status'
92
+ end
93
+
94
+ context 'when done' do
95
+ before do
96
+ allow(thread_a).to receive_messages(alive?: false)
97
+ allow(thread_b).to receive_messages(alive?: false)
98
+ end
99
+
100
+ let(:raw_expectations) do
101
+ [
102
+ *super(),
103
+ {
104
+ receiver: thread_a,
105
+ selector: :join
106
+ },
107
+ {
108
+ receiver: thread_b,
109
+ selector: :join
110
+ }
111
+ ]
112
+
113
+ end
114
+
115
+ let(:expected_status) do
116
+ Mutant::Parallel::Status.new(
117
+ active_jobs: active_jobs,
118
+ done: true,
119
+ payload: sink_status
120
+ )
121
+ end
122
+
123
+ include_examples 'returns expected status'
124
+ end
27
125
  end
28
126
  end