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
@@ -2,20 +2,22 @@
2
2
 
3
3
  RSpec.describe Mutant::Runner do
4
4
  describe '.call' do
5
- let(:reporter) { instance_double(Mutant::Reporter, delay: delay) }
6
- let(:driver) { instance_double(Mutant::Parallel::Driver) }
7
- let(:delay) { instance_double(Float) }
8
- let(:env_result) { instance_double(Mutant::Result::Env) }
9
- let(:actor_env) { instance_double(Mutant::Actor::Env) }
10
- let(:kernel) { class_double(Kernel) }
11
- let(:sleep) { instance_double(Method) }
5
+ let(:condition_variable) { class_double(ConditionVariable) }
6
+ let(:delay) { instance_double(Float) }
7
+ let(:driver) { instance_double(Mutant::Parallel::Driver) }
8
+ let(:env_result) { instance_double(Mutant::Result::Env) }
9
+ let(:kernel) { class_double(Kernel) }
10
+ let(:mutex) { class_double(Mutex) }
11
+ let(:processor) { instance_double(Method) }
12
+ let(:reporter) { instance_double(Mutant::Reporter, delay: delay) }
13
+ let(:thread) { class_double(Thread) }
12
14
 
13
15
  let(:env) do
14
16
  instance_double(
15
17
  Mutant::Env,
16
- actor_env: actor_env,
17
18
  config: config,
18
- mutations: []
19
+ mutations: [],
20
+ world: world
19
21
  )
20
22
  end
21
23
 
@@ -23,52 +25,97 @@ RSpec.describe Mutant::Runner do
23
25
  instance_double(
24
26
  Mutant::Config,
25
27
  jobs: 1,
26
- kernel: kernel,
27
28
  reporter: reporter
28
29
  )
29
30
  end
30
31
 
31
- before do
32
- allow(env).to receive(:method).with(:kill).and_return(parallel_config.processor)
33
- allow(kernel).to receive(:method).with(:sleep).and_return(sleep)
32
+ let(:world) do
33
+ instance_double(
34
+ Mutant::World,
35
+ condition_variable: condition_variable,
36
+ kernel: kernel,
37
+ mutex: mutex,
38
+ thread: thread
39
+ )
34
40
  end
35
41
 
36
- let(:parallel_config) do
37
- Mutant::Parallel::Config.new(
38
- env: actor_env,
39
- jobs: 1,
40
- processor: ->(_object) { fail },
41
- sink: Mutant::Runner::Sink.new(env),
42
- source: Mutant::Parallel::Source::Array.new(env.mutations)
42
+ let(:status_a) do
43
+ instance_double(
44
+ Mutant::Parallel::Status,
45
+ done?: false
43
46
  )
44
47
  end
45
48
 
46
- before do
47
- expect(reporter).to receive(:start).with(env).ordered
48
- expect(Mutant::Parallel).to receive(:async).with(parallel_config).and_return(driver).ordered
49
+ let(:status_b) do
50
+ instance_double(
51
+ Mutant::Parallel::Status,
52
+ done?: true,
53
+ payload: env_result
54
+ )
49
55
  end
50
56
 
51
- subject { described_class.call(env) }
52
-
53
- context 'when report iterations are done' do
54
- let(:status_a) { instance_double(Mutant::Parallel::Status, done: false) }
55
- let(:status_b) { instance_double(Mutant::Parallel::Status, done: true, payload: env_result) }
56
-
57
- before do
58
- expect(driver).to receive(:status).and_return(status_a).ordered
59
- expect(reporter).to receive(:progress).with(status_a).ordered
60
- expect(sleep).to receive(:call).with(reporter.delay).ordered
57
+ let(:parallel_config) do
58
+ Mutant::Parallel::Config.new(
59
+ condition_variable: condition_variable,
60
+ jobs: 1,
61
+ mutex: mutex,
62
+ processor: processor,
63
+ sink: Mutant::Runner::Sink.new(env),
64
+ source: Mutant::Parallel::Source::Array.new(env.mutations),
65
+ thread: thread
66
+ )
67
+ end
61
68
 
62
- expect(driver).to receive(:status).and_return(status_b).ordered
63
- expect(reporter).to receive(:progress).with(status_b).ordered
64
- expect(driver).to receive(:stop).ordered
69
+ def apply
70
+ described_class.apply(env)
71
+ end
65
72
 
66
- expect(reporter).to receive(:report).with(env_result).ordered
67
- end
73
+ let(:raw_expectations) do
74
+ [
75
+ {
76
+ receiver: reporter,
77
+ selector: :start,
78
+ arguments: [env]
79
+ },
80
+ {
81
+ receiver: env,
82
+ selector: :method,
83
+ arguments: [:kill],
84
+ reaction: { return: processor }
85
+ },
86
+ {
87
+ receiver: Mutant::Parallel,
88
+ selector: :async,
89
+ arguments: [parallel_config],
90
+ reaction: { return: driver }
91
+ },
92
+ {
93
+ receiver: driver,
94
+ selector: :wait_timeout,
95
+ arguments: [delay],
96
+ reaction: { return: status_a }
97
+ },
98
+ {
99
+ receiver: reporter,
100
+ selector: :progress,
101
+ arguments: [status_a]
102
+ },
103
+ {
104
+ receiver: driver,
105
+ selector: :wait_timeout,
106
+ arguments: [delay],
107
+ reaction: { return: status_b }
108
+ },
109
+ {
110
+ receiver: reporter,
111
+ selector: :report,
112
+ arguments: [env_result]
113
+ }
114
+ ]
115
+ end
68
116
 
69
- it 'returns env result' do
70
- should be(env_result)
71
- end
117
+ it 'returns env result' do
118
+ verify_events { expect(apply).to eql(Mutant::Either::Right.new(env_result)) }
72
119
  end
73
120
  end
74
121
  end
@@ -4,28 +4,29 @@ RSpec.describe Mutant::Selector::Expression do
4
4
  describe '#call' do
5
5
  let(:object) { described_class.new(integration) }
6
6
 
7
+ let(:mutation_subject) { subject_class.new(context: context, node: node, warnings: warnings) }
8
+ let(:context) { instance_double(Mutant::Context) }
9
+ let(:node) { instance_double(Parser::AST::Node) }
10
+ let(:integration) { instance_double(Mutant::Integration, all_tests: all_tests) }
11
+ let(:test_a) { instance_double(Mutant::Test, expression: parse_expression('SubjectA')) }
12
+ let(:test_b) { instance_double(Mutant::Test, expression: parse_expression('SubjectB')) }
13
+ let(:test_c) { instance_double(Mutant::Test, expression: parse_expression('SubjectC')) }
14
+ let(:warnings) { instance_double(Mutant::Warnings) }
15
+
7
16
  let(:subject_class) do
8
17
  parse = method(:parse_expression)
9
18
 
10
19
  Class.new(Mutant::Subject) do
11
20
  define_method(:expression) do
12
- parse.('SubjectA')
21
+ parse.call('SubjectA')
13
22
  end
14
23
 
15
24
  define_method(:match_expressions) do
16
- [expression] << parse.('SubjectB')
25
+ [expression] << parse.call('SubjectB')
17
26
  end
18
27
  end
19
28
  end
20
29
 
21
- let(:mutation_subject) { subject_class.new(context, node) }
22
- let(:context) { instance_double(Mutant::Context) }
23
- let(:node) { instance_double(Parser::AST::Node) }
24
- let(:integration) { instance_double(Mutant::Integration, all_tests: all_tests) }
25
- let(:test_a) { instance_double(Mutant::Test, expression: parse_expression('SubjectA')) }
26
- let(:test_b) { instance_double(Mutant::Test, expression: parse_expression('SubjectB')) }
27
- let(:test_c) { instance_double(Mutant::Test, expression: parse_expression('SubjectC')) }
28
-
29
30
  subject { object.call(mutation_subject) }
30
31
 
31
32
  context 'without available tests' do
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Selector::Null do
4
+ describe '#call' do
5
+ subject { described_class.new }
6
+
7
+ let(:mutant_subject) { instance_double(Mutant::Subject) }
8
+
9
+ def apply
10
+ subject.call(mutant_subject)
11
+ end
12
+
13
+ it 'returns no tests' do
14
+ expect(apply).to eql([])
15
+ end
16
+ end
17
+ end
@@ -1,7 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Mutant::Subject::Method::Instance do
4
- let(:object) { described_class.new(context, node) }
4
+ let(:object) do
5
+ described_class.new(
6
+ context: context,
7
+ node: node,
8
+ warnings: warnings
9
+ )
10
+ end
11
+
12
+ let(:call_block?) { true }
13
+ let(:warnings) { instance_double(Mutant::Warnings) }
5
14
 
6
15
  let(:context) do
7
16
  Mutant::Context.new(
@@ -30,6 +39,12 @@ RSpec.describe Mutant::Subject::Method::Instance do
30
39
  end
31
40
  end
32
41
 
42
+ before do
43
+ allow(warnings).to receive(:call) do |&block|
44
+ block.call if call_block?
45
+ end
46
+ end
47
+
33
48
  describe '#expression' do
34
49
  subject { object.expression }
35
50
 
@@ -47,7 +62,6 @@ RSpec.describe Mutant::Subject::Method::Instance do
47
62
  end
48
63
 
49
64
  describe '#prepare' do
50
-
51
65
  let(:context) do
52
66
  Mutant::Context.new(scope, instance_double(Pathname))
53
67
  end
@@ -55,7 +69,20 @@ RSpec.describe Mutant::Subject::Method::Instance do
55
69
  subject { object.prepare }
56
70
 
57
71
  it 'undefines method on scope' do
58
- expect { subject }.to change { scope.instance_methods.include?(:foo) }.from(true).to(false)
72
+ expect { subject }
73
+ .to change { scope.instance_methods.include?(:foo) }
74
+ .from(true)
75
+ .to(false)
76
+ end
77
+
78
+ context 'within warning capture' do
79
+ let(:call_block?) { false }
80
+
81
+ it 'undefines method on scope' do
82
+ expect { subject }
83
+ .to_not change { scope.instance_methods.include?(:foo) }
84
+ .from(true)
85
+ end
59
86
  end
60
87
 
61
88
  it_should_behave_like 'a command method'
@@ -69,13 +96,25 @@ RSpec.describe Mutant::Subject::Method::Instance do
69
96
  end
70
97
 
71
98
  RSpec.describe Mutant::Subject::Method::Instance::Memoized do
72
- let(:object) { described_class.new(context, node) }
73
- let(:context) { double('Context') }
99
+ let(:object) do
100
+ described_class.new(
101
+ context: context,
102
+ node: node,
103
+ warnings: warnings
104
+ )
105
+ end
106
+
107
+ let(:context) { double('Context') }
108
+ let(:warnings) { instance_double(Mutant::Warnings) }
74
109
 
75
110
  let(:node) do
76
111
  s(:def, :foo, s(:args))
77
112
  end
78
113
 
114
+ before do
115
+ allow(warnings).to receive(:call).and_yield
116
+ end
117
+
79
118
  describe '#prepare' do
80
119
 
81
120
  let(:context) do
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Mutant::Subject::Method::Singleton do
4
+ let(:object) do
5
+ described_class.new(
6
+ context: context,
7
+ node: node,
8
+ warnings: warnings
9
+ )
10
+ end
4
11
 
5
- let(:object) { described_class.new(context, node) }
6
- let(:node) { s(:defs, s(:self), :foo, s(:args)) }
12
+ let(:node) { s(:defs, s(:self), :foo, s(:args)) }
13
+ let(:warnings) { instance_double(Mutant::Warnings) }
7
14
 
8
15
  let(:context) do
9
16
  Mutant::Context.new(scope, instance_double(Pathname))
@@ -16,7 +16,13 @@ RSpec.describe Mutant::Subject do
16
16
  end
17
17
  end
18
18
 
19
- let(:object) { class_under_test.new(context, node) }
19
+ let(:object) do
20
+ class_under_test.new(
21
+ context: context,
22
+ node: node,
23
+ warnings: warnings
24
+ )
25
+ end
20
26
 
21
27
  let(:node) do
22
28
  Unparser.parse(<<-RUBY)
@@ -32,6 +38,8 @@ RSpec.describe Mutant::Subject do
32
38
  )
33
39
  end
34
40
 
41
+ let(:warnings) { instance_double(Mutant::Warnings) }
42
+
35
43
  describe '#identification' do
36
44
  subject { object.identification }
37
45
 
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Transform::Array do
4
+ subject { described_class.new(transform) }
5
+
6
+ let(:transform) { Mutant::Transform::Boolean.new }
7
+
8
+ describe '#apply' do
9
+ def apply
10
+ subject.apply(input)
11
+ end
12
+
13
+ context 'on array input' do
14
+ context 'empty' do
15
+ let(:input) { [] }
16
+
17
+ it 'returns sucess' do
18
+ expect(apply).to eql(Mutant::Either::Right.new(input))
19
+ end
20
+ end
21
+
22
+ context 'valid elements' do
23
+ let(:input) { [true, true] }
24
+
25
+ it 'returns sucess' do
26
+ expect(apply).to eql(Mutant::Either::Right.new(input))
27
+ end
28
+ end
29
+
30
+ context 'invalid elements' do
31
+ let(:input) { [true, 1] }
32
+
33
+ let(:boolean_error) do
34
+ Mutant::Transform::Error.new(
35
+ cause: nil,
36
+ input: 1,
37
+ message: 'Expected: boolean but got: 1',
38
+ transform: transform
39
+ )
40
+ end
41
+
42
+ let(:index_error) do
43
+ Mutant::Transform::Error.new(
44
+ cause: boolean_error,
45
+ input: 1,
46
+ message: nil,
47
+ transform: Mutant::Transform::Index.new(index: 1, transform: transform)
48
+ )
49
+ end
50
+
51
+ let(:error) do
52
+ Mutant::Transform::Error.new(
53
+ cause: index_error,
54
+ input: input,
55
+ message: 'Failed to coerce array at index: 1',
56
+ transform: subject
57
+ )
58
+ end
59
+
60
+ it 'returns failure' do
61
+ expect(apply).to eql(Mutant::Either::Left.new(error))
62
+ end
63
+ end
64
+
65
+ context 'transformed elements' do
66
+ let(:input) { [{ 'foo' => 'bar' }] }
67
+ let(:transform) { Mutant::Transform::Hash::Symbolize.new }
68
+
69
+ it 'returns transformed elements' do
70
+ expect(apply).to eql(Mutant::Either::Right.new([foo: 'bar']))
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'on other input' do
76
+ let(:input) { false }
77
+
78
+ let(:error) do
79
+ Mutant::Transform::Error.new(
80
+ cause: nil,
81
+ input: input,
82
+ message: 'Expected: Array but got: FalseClass',
83
+ transform: subject
84
+ )
85
+ end
86
+
87
+ it 'returns failure' do
88
+ expect(apply).to eql(Mutant::Either::Left.new(error))
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Transform::Boolean do
4
+ subject { described_class.new }
5
+
6
+ let(:primitive) { String }
7
+
8
+ describe '#apply' do
9
+ def apply
10
+ subject.apply(input)
11
+ end
12
+
13
+ context 'on true' do
14
+ let(:input) { true }
15
+
16
+ it 'returns sucess' do
17
+ expect(apply).to eql(Mutant::Either::Right.new(input))
18
+ end
19
+ end
20
+
21
+ context 'on false' do
22
+ let(:input) { false }
23
+
24
+ it 'returns sucess' do
25
+ expect(apply).to eql(Mutant::Either::Right.new(input))
26
+ end
27
+ end
28
+
29
+ context 'on nil input' do
30
+ let(:input) { nil }
31
+
32
+ let(:error) do
33
+ Mutant::Transform::Error.new(
34
+ cause: nil,
35
+ input: input,
36
+ message: 'Expected: boolean but got: nil',
37
+ transform: subject
38
+ )
39
+ end
40
+
41
+ it 'returns failure' do
42
+ expect(apply).to eql(Mutant::Either::Left.new(error))
43
+ end
44
+ end
45
+
46
+ context 'on truthy input' do
47
+ let(:input) { '' }
48
+
49
+ let(:error) do
50
+ Mutant::Transform::Error.new(
51
+ cause: nil,
52
+ input: input,
53
+ message: 'Expected: boolean but got: ""',
54
+ transform: subject
55
+ )
56
+ end
57
+
58
+ it 'returns failure' do
59
+ expect(apply).to eql(Mutant::Either::Left.new(error))
60
+ end
61
+ end
62
+ end
63
+ end